:root {
  --ink: #1f1f1f;
  --ink-2: #4a4a4a;
  --dim: #8a8a8a;
  --line: #e2e2e2;
  --bg: #ffffff;
  --bg-2: #f7f7f7;
  --hl: #e8ecff;
  --danger: #c2453a;
  --ws-w: 300px;   /* 工作区宽度，拖右侧把手可调（app.js 写入） */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font: 14px/1.6 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* 页面 = 纵向 flex：顶栏自然高（窄屏可换行增高）+ 主体占满剩余。
   过去主体写死 calc(100% − 52px)，顶栏一换行就和主体错位/重叠。 */
body {
  display: flex;
  flex-direction: column;
}

/* -------------------------------------------------------------- 顶栏 */

.topbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;              /* 窄屏第二行，而不是把按钮裁掉 */
  gap: 8px 12px;
  min-height: 52px;
  flex: none;                   /* 自然高度（换行时撑高，主体自动让位） */
  padding: 6px 16px;
  border-bottom: 1px solid var(--line);
}

.brand {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
  flex: none;
}

.brand span {
  color: var(--dim);
  font-weight: 400;
  font-size: 12px;
  margin-left: 4px;
}

/* 顶栏里的任何链接都继承正文色、不带下划线（品牌名不做跳转，也不漏出默认蓝） */
.topbar a {
  color: inherit;
  text-decoration: none;
}

/* 当前文档名 + 未保存标记 */
.doc-info {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 13px;
  color: var(--ink-2);
}

#doc-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
}

.doc-state { font-size: 12px; color: var(--dim); white-space: nowrap; }
.doc-state.dirty { color: #7a5c00; }
.doc-state.readonly { color: #1a56a8; }   /* 库谱只读：区别于「未保存」的琥珀色 */

.actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-left: auto; }
.group-label { font-size: 12px; color: var(--dim); }

.btn {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink);
  height: 30px;
  padding: 0 12px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}

.btn:hover { border-color: #c8c8c8; background: var(--bg-2); }
.btn.primary { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn.primary:hover { background: #000; }
.btn.ghost { border-color: transparent; color: var(--dim); }
.btn.ghost:hover { color: var(--ink); background: var(--bg-2); }
.btn:disabled { opacity: 0.35; cursor: default; }
.btn:disabled:hover { border-color: var(--line); background: var(--bg); }
/* 小号按钮：谱面板头的「宽 / 窄」切换（仅预览模式显示） */
.btn.mini { height: 24px; padding: 0 10px; font-size: 12px; border-radius: 5px; color: var(--dim); }
.btn.mini:hover { color: var(--ink); }
.btn.mini.active { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn.mini.active:hover { background: #000; color: #fff; }

/* 库谱 banner：从谱库载入一首时显示（只读提示 + 「存一份」转化 CTA + 复制链接）。
   平时 hidden；app.js 按 libraryScore 状态显隐。 */
.library-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  font-size: 12.5px;
  color: var(--ink-2);
  background: var(--hl);
  border-bottom: 1px solid var(--line);
  flex: none;
}
.library-banner .lb-note { flex: 1; min-width: 0; }
.library-banner .lb-actions { display: flex; gap: 8px; flex: none; }
.library-banner .btn { height: 28px; font-size: 12.5px; padding: 0 11px; }

/* -------------------------------------------------------------- 主体 */

.layout {
  display: grid;
  grid-template-columns: var(--ws-w) 1fr;
  flex: 1;
  min-height: 0;        /* flex 列里占满剩余、内部可滚动（顶栏换行增高时自动让位） */
  position: relative;   /* 宽度把手绝对定位，锚在工作区右缘（见 .ws-resizer） */
}

.panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; }

/* 左侧工作区：谱头速览 + 声部管理（替代原常驻文本面板） */
.workspace {
  border-right: 0;
  overflow-y: auto;
  background: var(--bg-2);
  min-width: 0;
}
/* 宽度可调的把手：夹在 aside 与谱面之间（命中区 5px，视觉 1px 线，hover 加深提示可拖）。
   绝对定位**浮在**两列交界上、不占 grid 轨道——.layout 只有两列（工作区 + 谱面），
   把手若进流会被当成第 3 个 grid 项把谱面挤到第二行（曾致「全挤左边、右边空白」）。 */
.ws-resizer {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--ws-w) - 2px);   /* 5px 命中区跨住交界：2px 压工作区、3px 压谱面 */
  width: 5px;
  cursor: col-resize;
  background: var(--line);
  transition: background 0.12s;
  z-index: 2;
}
.ws-resizer:hover { background: #b8b8b8; }
.ws-section { padding: 10px 14px; border-bottom: 1px solid var(--line); }
.ws-head {
  font-size: 12px;
  color: var(--dim);
  margin-bottom: 8px;
  letter-spacing: 0.04em;
}
/* 可折叠的区块头：点它收起 / 展开本块内容 */
button.ws-head {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
button.ws-head:hover { color: var(--ink-2); }
.ws-caret {
  display: inline-block;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  transform: rotate(90deg);
  transition: transform 0.12s;
  flex: none;
}
.ws-section.collapsed .ws-caret { transform: rotate(0deg); }
/* 折叠时只留头行：内容整体隐藏（列表 DOM 保留不重渲，输入状态不丢） */
.ws-section.collapsed > :not(.ws-head) { display: none; }
.ws-meta { font-size: 13px; line-height: 1.8; color: var(--ink-2); }
.ws-meta .dim { color: var(--dim); }
.ws-side-btn { margin-top: 8px; }
.ws-add { width: 100%; margin-top: 6px; }
/* 每行 = 名字 | M | S | ▲ | ▼ | ✕ | 音量滑杆（7 列；音量是第 7 列，加在最后不挤动前 6 列的下标） */
.voice-row { display: grid; grid-template-columns: 1fr auto auto auto auto auto auto; gap: 4px; align-items: center; }
/* 各声部独立音量：窄滑杆，只影响本声部播放 / 试听（会话状态） */
.voice-vol { width: 48px; height: 24px; accent-color: var(--ink); cursor: pointer; margin: 0; }
/* M / S 是会话状态（不进文档）：点亮 = 生效中 */
.ws-ms {
  width: 26px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg);
  color: var(--dim);
  font-size: 11px;
  cursor: pointer;
}
.ws-ms:hover { border-color: #c8c8c8; }
.ws-ms.active { background: var(--ink); border-color: var(--ink); color: #fff; }
/* 删除键：✕ + 危险色。过去是灰字「−」，和 ▲▼ 一个视觉权重，误点率高 */
.ws-del {
  width: 28px;
  height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 5px;
  background: none;
  color: var(--dim);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}
.ws-del:hover { background: #fbeeeb; border-color: #ecc8c3; color: var(--danger); }

.panel-head {
  display: flex;
  align-items: center;
  height: 34px;
  padding: 0 14px;
  font-size: 12px;
  color: var(--dim);
  border-bottom: 1px solid var(--line);
  flex: none;
}

/* 标题占满剩余宽度，把 #score-info 与右侧控件（宽/窄）都顶到行尾 */
.panel-head > span:first-child { flex: 1; }

.panel-head-right { display: flex; align-items: center; gap: 8px; margin-left: 8px; }

/* 工作区收起后谱面占满整行（收起 / 展开状态由 body 上的 class 承载） */
body.workspace-hidden .workspace { display: none; }
body.workspace-hidden .layout { grid-template-columns: 1fr; }
body.workspace-hidden .ws-resizer { display: none; }   /* 工作区没了，拖宽把手也没意义 */

/* 预览模式：只留查看与播放。状态由 body class 承载（同 workspace-hidden 的手法）——
   顶栏带 data-editable 的按钮（新建/打开/导入/撤销/重做/工作区）与工具栏、
   状态条、工作区、拖宽把手全隐藏；谱面与播放条保留。 */
body.preview-mode .topbar [data-editable] { display: none; }
body.preview-mode .toolbar,
body.preview-mode .status-strip,
body.preview-mode .workspace,
body.preview-mode .ws-resizer { display: none; }
body.preview-mode .layout { grid-template-columns: 1fr; }

/* 库谱只读（body.lib-readonly，由 libraryScore 决定，与预览开关无关）：
   编辑入口一律 disable（app.js 的 applyEditLocks），这里只给「不能点」的视觉，
   并让谱面光标保持默认（只读 ≠ 不能看、不能复制）。 */
body.lib-readonly .toolbar :disabled,
body.lib-readonly .note-keyboard button:disabled { opacity: .38; cursor: not-allowed; }
body.lib-readonly .score svg { cursor: default; }

/* 保存菜单里的分组说明（「分享」一节：链接 / SVG / 视频给运营发作品用） */
.menu-block-note { display: block; padding: 0 10px 4px; font-size: 11.5px; line-height: 1.5; color: var(--dim); }

/* 预览宽度：谱面约束到「视口宽 × --preview-pct%」（app.js 写入），居中、两侧留白；
   系统换行按这个宽度算（paint 读 .score 实际 clientWidth）。--preview-pct 缺省 100（占满）。
   body.preview-width 只在 <100% 时挂（100% 时不约束、不留白）。 */
:root { --preview-pct: 100; }
body.preview-width .score { max-width: calc(var(--preview-pct) * 1vw); margin: 0 auto; }

/* 预览宽度滑杆（谱面板头右侧，仅预览下显示）：宽度标签 + 滑杆 + 百分比读数 */
.pv-label { font-size: 12px; color: var(--dim); }
#preview-width-slider { width: 120px; accent-color: var(--ink); cursor: pointer; margin: 0; }
.pv-val { width: 40px; text-align: right; font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; }

.dim { color: var(--dim); }

/* 状态条：错误 / 告警常驻可见（原文本面板底部的 #status 挪到这里），临时提示靠右 */
.status-strip {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-height: 0;
  max-height: 96px;
  overflow: auto;
  padding: 0 14px;
  font-size: 12px;
  line-height: 1.7;
  color: var(--dim);
  border-top: 1px solid var(--line);
}
.status-strip:empty { display: none; }
.status-list .err { display: block; color: #b3261e; }
.status-list .warn { display: block; color: #7a5c00; }
.status-strip:has(.status-list:empty) { min-height: 0; border-top-color: transparent; }

/* ------------------------------------------------------------ 手机端小键盘（M1.1 就地输入） */
/* 桌面（>820px）恒隐藏：基线 display:none，≤820px 断点里 :not([hidden]) 才放开。
   与 [hidden] 兜底规则同思路——hidden 属性决定「该不该出」，display 决定「窄屏才出」。 */
.note-keyboard { display: none; }

/* ------------------------------------------------------------ 谱面 */

/* 编辑工具栏：时值 / 小节操作 */

.toolbar {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  min-height: 40px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--line);
}

.tb-group { display: flex; align-items: center; gap: 4px; flex: none; }

/* display:flex/grid 会盖掉 [hidden] 的 UA 默认值，这里统一补回来（记号/力度组隐藏用） */
[hidden] { display: none !important; }

.tb {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink-2);
  height: 26px;
  padding: 0 9px;
  border-radius: 5px;
  font-size: 12px;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
}

.tb:hover { border-color: #c8c8c8; background: var(--bg-2); }
.tb.active { background: var(--ink); border-color: var(--ink); color: #fff; }
.tb.active:hover { background: #000; }

/* 演奏记号：单字符方钮（颤 / 波 / 滑 …），紧凑一排 */
.tb.mark { width: 26px; padding: 0; text-align: center; font-weight: 600; }
.tb.mark.active { background: var(--ink); color: #fff; }

.tb-sep { flex: none; width: 1px; height: 18px; background: var(--line); }

.tb-select {
  appearance: none;
  height: 26px;
  padding: 0 6px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg);
  color: var(--ink-2);
  font-size: 12px;
  cursor: pointer;
}

.tb-select:hover { border-color: #c8c8c8; }

/* 「更多」溢出菜单：低频工具（八度 / 双音 / 紧凑）收进下拉，窄屏不再挤成一排。
   菜单内按钮**不自动收起**（八度是状态切换，点完看一眼谁亮着再关）。 */
.tb-more { position: relative; flex: none; }
.tb-more .tb { display: flex; align-items: center; gap: 4px; }
/* 顶栏 ⋯ 溢出菜单：桌面 display:none（顶栏平铺放得下），窄屏由 ≤820px 块激活。
   定位同 .tb-more（position:relative + .menu absolute）。 */
.topbar-more { position: relative; flex: none; display: none; }
.topbar-more .btn { display: flex; align-items: center; gap: 4px; }
.topbar-more.open .btn { background: var(--bg-2); border-color: #c8c8c8; }
.topbar-more-menu { right: 0; min-width: 188px; }
.topbar-more-menu .menu-item { justify-content: flex-start; }
.tb-more.open .tb { background: var(--bg-2); border-color: #c8c8c8; }
.tb-more-menu { right: 0; min-width: 236px; }
.menu-block { padding: 2px 4px; }
.menu-block-label {
  font-size: 11px;
  color: var(--dim);
  padding: 4px 6px 3px;
  letter-spacing: 0.02em;
}
.menu-btns { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 4px 4px; }

.edit-hint {
  flex: none;
  margin-left: auto;
  font-size: 12px;
  color: #7a5c00;
  white-space: nowrap;
}
.edit-hint:empty { display: none; }

/* 粘贴导入弹窗 */
dialog#import-dialog {
  width: min(640px, calc(100vw - 32px));
  max-height: 82vh;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--ink);
}
dialog#import-dialog::backdrop { background: rgba(0, 0, 0, 0.28); }
.import-text {
  width: 100%;
  height: 280px;
  margin-top: 4px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  outline: none;
  resize: vertical;
  font: 13px/1.8 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--ink);
  background: var(--bg);
}

/* 歌词输入：真实的可聚焦输入框（输入法与 composition 事件需要），但贴到当前音符旁边，不可见 */
.lyric-input {
  position: fixed;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  outline: none;
  opacity: 0;
  pointer-events: none;
}

.score {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 4px 0 12px;
}

.score svg { display: block; }
.score .range { fill: #ededed; }
.score .hl { fill: var(--hl); }
.score .sel { fill: none; stroke: var(--ink); stroke-width: 1.6; }
.score .caret { stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; }

.sel-info {
  font-size: 12px;
  color: var(--dim);
  margin-left: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* 播放条 = Spotify 式「运输区」：一行装下，靠**强视觉层级**区分主次。
   [●▶] [■] [N/总] [──── 可拖进度条 ────] [1x] [🔊 80]
   唯一的实心深色播放/暂停键是全条的视觉锚点（白底主题里唯一深色块）；
   停止 / 倍速 / 音量全部降权成浅色图标键（灰 → 悬停转深）；进度条最宽、
   双色轨道 + 圆头，flex:1 拿走全部余量。位置信息（#sel-info）在「谱面」头，不占这一行。 */
.player-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px 12px;
  min-height: 52px;
  padding: 8px 16px;
  border-top: 1px solid var(--line);
  background: var(--bg);
}

/* 播放 / 暂停 = 唯一锚点：48px 实心深色圆 + 白色 glyph，悬停微放大、变纯黑。
   全条唯一深色块，其余控件都是它的陪衬 —— 这就是「成熟播放器」的焦点语言。 */
.player-bar #btn-play {
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: grid;
  place-items: center;
  transition: transform 0.1s ease, background 0.12s ease;
}
.player-bar #btn-play:hover { background: #000; transform: scale(1.05); }
.player-bar #btn-play:active { transform: scale(0.97); }
.player-bar #btn-play svg { width: 22px; height: 22px; }
/* 位置（当前小节/总小节）：等宽数字、固定宽不抖动。恒显示「下次从哪播」，无待命 — 态 */
.play-pos {
  flex: none;
  min-width: 44px;
  text-align: center;
  font-size: 12px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 进度条：4px 轨道 + 已播放段（--pp 由 JS 写 0..1）+ 圆头，去掉浏览器默认外观。
   命中区靠 28px 高的 input 本体，手指拖得准；悬停/拖动时圆头微放大给反馈。 */
#play-progress {
  flex: 1 1 0;
  min-width: 60px;
  width: auto;
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
  height: 28px;
  background: transparent;
  cursor: pointer;
}
#play-progress::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(to right, var(--ink) calc(var(--pp, 0) * 100%), var(--line) 0);
}
#play-progress::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -4px;   /* (12 - 4) / 2，居中在 4px 轨道上 */
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  transition: transform 0.1s ease;
}
#play-progress:hover::-webkit-slider-thumb,
#play-progress:active::-webkit-slider-thumb { transform: scale(1.25); }
#play-progress::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: var(--line);
}
#play-progress::-moz-range-progress {
  height: 4px;
  border-radius: 2px;
  background: var(--ink);
}
#play-progress::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
}
/* 倍速 / 音量 = 降权的浅色 chip（无边框无底，灰 → 悬停转深 + 浅底）；音量 = 喇叭 SVG + 数字 */
.player-bar #btn-speed,
.player-bar #btn-volume {
  flex: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  padding: 0 8px;
  border: 0;
  background: transparent;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  transition: color 0.12s ease, background 0.12s ease;
}
.player-bar #btn-speed:hover,
.player-bar #btn-volume:hover { color: var(--ink); background: var(--bg-2); }
.player-bar #btn-volume .vol-icon { display: inline-flex; }
.player-bar #btn-volume .vol-icon svg { width: 15px; height: 15px; }
#vol-num { font-variant-numeric: tabular-nums; min-width: 18px; text-align: right; }

/* ------------------------------------------------------------ 帮助 */

dialog#help {
  width: min(680px, calc(100vw - 32px));
  max-height: 82vh;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--ink);
}

dialog#help::backdrop { background: rgba(0, 0, 0, 0.28); }

.help-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}

.help-head h2 { margin: 0; font-size: 15px; font-weight: 600; }

.help-body { padding: 14px 16px 20px; overflow: auto; max-height: calc(82vh - 56px); }
.help-body h3 { font-size: 13px; margin: 20px 0 8px; }
.help-body h2.help-appendix { font-size: 14px; margin: 28px 0 8px; padding-top: 14px; border-top: 2px solid var(--line); }
.help-body p { margin: 6px 0; color: var(--ink-2); }

.help-quick { margin: 6px 0; padding-left: 20px; }
.help-quick li { margin: 4px 0; color: var(--ink-2); line-height: 1.7; }
.help-quick kbd, .help-body kbd {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 0 4px;
}

.help-body table { width: 100%; border-collapse: collapse; font-size: 13px; }
.help-body th, .help-body td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.help-body th { color: var(--dim); font-weight: 500; }
.help-body td:first-child { white-space: nowrap; font-family: ui-monospace, Menlo, Consolas, monospace; }

.help-body pre {
  margin: 6px 0;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  font: 12px/1.7 ui-monospace, Menlo, Consolas, monospace;
  overflow: auto;
}

.help-body code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  background: var(--bg-2);
  padding: 1px 4px;
  border-radius: 3px;
}

/* ------------------------------------------------------- 谱头设置 / 新建 */

/* 谱头弹窗收窄：只留核心字段，高级项折叠在底部 */
dialog#meta-dialog {
  width: min(420px, calc(100vw - 32px));
}
.meta-actions { display: flex; gap: 8px; }
.meta-advanced { margin-top: 14px; }
.meta-advanced summary { font-size: 12px; color: var(--dim); cursor: pointer; user-select: none; }
.meta-advanced[open] summary { margin-bottom: 4px; }
.meta-advanced .meta-grid-sub { margin-top: 8px; }

/* 两列：标签 + 控件 */
.meta-grid {
  display: grid;
  grid-template-columns: 6.5em 1fr;
  gap: 10px 12px;
  align-items: center;
  font-size: 13px;
}

.meta-grid label { color: var(--dim); }

.meta-grid input,
.meta-grid select {
  height: 30px;
  min-width: 0;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  font-size: 13px;
}

.meta-grid input:focus,
.meta-grid select:focus { outline: none; border-color: #b0b0b0; }

.meta-note {
  margin: 16px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  line-height: 1.7;
  color: var(--dim);
}

.tpl-list { display: grid; gap: 8px; }

/* 「创建空谱」：表单的主动作，给足点击面积 */
.new-actions { margin-top: 14px; }
.new-actions .btn { width: 100%; height: 34px; }

/* 导出视频弹窗：比谱头弹窗稍宽（要放 2×2 比例格 + 说明） */
dialog#export-dialog { width: min(400px, calc(100vw - 32px)); }

/* 比例选择：2×2 卡片，点整张卡选（label 包住 radio），缩略图形示意比例 */
.export-field { display: block; font-size: 12px; color: var(--dim); margin-bottom: 8px; }
/* 水印输入：与比例格同宽，和其它表单字段同高度 */
.export-input {
  display: block; width: 100%; box-sizing: border-box; height: 32px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--bg);
  font: inherit; font-size: 13px; color: var(--ink);
}
.export-input:focus { outline: none; border-color: #5b6bfe; }
.ratio-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.ratio-opt {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 8px 9px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); cursor: pointer; transition: border-color .12s, background .12s;
}
.ratio-opt:hover { border-color: #c8c8c8; background: var(--bg-2); }
.ratio-opt input { position: absolute; opacity: 0; pointer-events: none; }
.ratio-opt:has(input:checked) { border-color: #5b6bfe; background: var(--hl); }
.ratio-name { font-size: 12px; color: var(--ink-2); }
.ratio-opt:has(input:checked) .ratio-name { color: var(--ink); font-weight: 600; }
/* 缩略图形：外框固定 34×34，内色块按真实比例居中 —— 一眼看出横 / 竖 / 方 */
.ratio-glyph { position: relative; width: 34px; height: 34px; }
.ratio-glyph::before {
  content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  background: #c3c9f5; border: 1px solid #8b96e6; border-radius: 2px;
}
.ratio-opt:has(input:checked) .ratio-glyph::before { background: #5b6bfe; border-color: #3f4ed8; }
.rg-169::before { width: 34px; height: 19px; }
.rg-916::before { width: 19px; height: 34px; }
.rg-11::before  { width: 28px; height: 28px; }
.rg-43::before  { width: 34px; height: 26px; }

/* 导出中：进度条 + 百分比 */
.export-actions { display: flex; gap: 8px; }
.export-actions .btn { width: auto; }
.export-progress { display: flex; align-items: center; gap: 10px; }
.export-bar { flex: 1; height: 8px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 5px; overflow: hidden; }
.export-bar-fill { height: 100%; width: 0; background: #5b6bfe; border-radius: 4px 0 0 4px; transition: width .1s linear; }
.export-pct { flex: none; width: 40px; text-align: right; font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.tpl {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  text-align: left;
  cursor: pointer;
}

.tpl:hover { border-color: #c8c8c8; background: var(--bg-2); }
.tpl-name { font-size: 13px; font-weight: 600; color: var(--ink); }
.tpl-hint { font-size: 12px; color: var(--dim); }

/* 顶栏「工作区」按钮：工作区当前可见时点亮 */
.btn.ghost.active { color: var(--ink); background: var(--bg-2); border-color: var(--line); }

/* 保存 / 导出：一个下拉（菜单面板）。主按钮直接保存，右侧小三角展开菜单 */
.save-menu { position: relative; flex: none; }
.save-menu .btn { display: flex; align-items: center; gap: 5px; }
.save-caret {
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--dim);
}
.save-menu.open .save-caret { transform: rotate(180deg); }
/* 命中区撑满按钮高度：三角本体只有 5px，可点区做小了几乎点不中，
   用户会一直点到按钮主体（=直接保存），感觉「导出菜单没有了」 */
.save-caret-wrap {
  display: grid;
  place-items: center;
  padding: 0 4px;
  align-self: stretch;
  cursor: pointer;
}
.save-caret-wrap:hover .save-caret { border-top-color: var(--ink); }
.menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 196px;
  padding: 4px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  z-index: 50;
}
.menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 6px 10px;
  border: 0;
  border-radius: 5px;
  background: none;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
/* display 会盖过 hidden 属性的默认 display:none（UA 规则优先级低于类）：
   「复制链接」这类按状态显隐的菜单项靠 JS 设 hidden，这里必须显式压住。 */
.menu-item[hidden] { display: none; }
.menu-item:hover { background: var(--bg-2); }
.menu-item kbd { font-family: inherit; font-size: 11px; color: var(--dim); }
.menu-sep { height: 1px; margin: 4px 6px; background: var(--line); border: 0; }

/* 工作区里的声部列表：每行 = 名字输入框 + M / S / 上移 / 下移 / 删除 + 音量滑杆
（列布局见上方 .voice-row 的 7 列定义） */
.voice-list { display: grid; gap: 6px; }
/* 只套名字输入框（type=text）；音量滑杆是 input[type=range]，样式见 .voice-vol */
.voice-row input[type="text"] {
  height: 28px;
  min-width: 0;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg);
  color: var(--ink);
  font-size: 13px;
}
.voice-row input[type="text"]:focus { outline: none; border-color: #b0b0b0; }

/* 段落列表：每段一张**单行**小卡片
   [字母徽章] [第 N 小节起] [调性] [拍号] [速度] [✕ 删除（开头段没有）]。
   徽章就是段落名（自动命名 A段 / B段 …，本轮只读，不另设名称框）。
   继承上一段的字段灰显（.sec-inherit），改它才变成显式。
   开头段（A 段）起始小节固定第 1 小节、只读、不可移、不可删。 */
.section-list { display: grid; gap: 6px; }
.section-card {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 5px 8px;
  background: var(--bg);
}
/* 字母徽章：A / B / C / D …，自动按段落顺序排（用户不改名时的默认标识） */
.sec-badge {
  flex: none;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg-2);
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
}
.sec-line { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; row-gap: 5px; }
.sec-at { font-size: 12px; color: var(--dim); flex: none; }
.sec-line select {
  height: 24px; padding: 0 3px; max-width: 70px;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg); color: var(--ink); font-size: 12px;
}
.sec-line select:focus { outline: none; border-color: #b0b0b0; }
.sec-line input[type="number"] {
  width: 44px; height: 24px; padding: 0 4px;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg); color: var(--ink); font-size: 12px;
  -moz-appearance: textfield;
}
.sec-line input[type="number"]:focus { outline: none; border-color: #b0b0b0; }
.sec-del { flex: none; margin-left: auto; }   /* ✕ 靠行尾，字段多的窄卡也顶得开 */
/* 继承来的值：灰显提示「这是上一段的，改它才会单独变」 */
.sec-inherit { opacity: 0.55; }
.sec-empty { font-size: 12px; color: var(--dim); line-height: 1.7; }

/* ------------------------------------------------------------ 窄屏 */

/* 中屏：标题收窄，给文件按钮让位（顶栏自身可换行，min-height 兜底） */
@media (max-width: 1100px) {
  #doc-title { max-width: 12ch; }
}

/* ============ 手机视口（≤600px，与 app.js paint 的 <600px fit-to-width 同断点）============
   设计原则：谱面是手机上的绝对主角，非谱面 chrome 压到 ~20%。顶栏 / 工具栏各收成**单行**，
   低频功能收纳（顶栏进 ⋯ 菜单、工具栏整条横滑），不折成多行。桌面 / 平板（>600px）不动。 */
@media (max-width: 600px) {
  /* ---- 顶栏单行化：谱名(状态) …… 存一份(仅库谱) 保存▾ ⋯ ---- */
  .topbar { flex-wrap: nowrap; padding: 4px 10px; gap: 4px 8px; }
  .brand { display: none; }                /* 手机上谱名即标识，去掉「哈哈有谱」占位 */
  .doc-info { flex: 1; min-width: 0; }     /* 谱名吃掉剩余宽度、省略号 */
  .actions { flex-wrap: nowrap; margin-left: 0; }
  /* 低频按钮收进 ⋯ 菜单（JS 里菜单项调同一函数），顶栏只留 存一份/保存/⋯ */
  #btn-new, #btn-open, #btn-import-paste,
  #btn-undo, #btn-redo,
  #btn-library, #btn-preview, #btn-help, #btn-workspace,
  .actions > .tb-sep { display: none; }
  .topbar-more { display: block; }         /* 激活 ⋯ 溢出按钮 */

  /* ---- 工具栏单行横滑：18 钮不折行，整条左右滑动（编辑随手可达）---- */
  .toolbar {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 5px 10px;
  }
  .toolbar::-webkit-scrollbar { display: none; }   /* 吃掉滚动条、保留滚动 */
  .toolbar .tb-group { flex: none; }               /* 组不拆、整组随横滑走 */
}

/* 手机视口：谱面按 640 参考宽排版后等比缩放进容器（与 app.js paint 的 <600px
   fit-to-width 同断点）。viewBox 保住比例，命中换算走 toSvgPoint 的「布局宽/渲染宽」，
   缩放不影响点选。 */
@media (max-width: 600px) {
  .score svg { width: 100%; height: auto; }
}

@media (max-width: 820px) {
  .layout { grid-template-columns: 1fr; grid-template-rows: 40% 1fr; }
  .workspace { border-right: 0; border-bottom: 1px solid var(--line); }
  body.workspace-hidden .layout { grid-template-rows: 1fr; }
  /* 预览模式工作区被 display:none，只剩谱面一个 grid 项 → 会落进 40% 上行、1fr 下行
     空着（灰），播放条卡在页面中间。塌成单行让谱面占满、播放条落到底。 */
  body.preview-mode .layout { grid-template-rows: 1fr; }
  body.workspace-hidden .ws-resizer { display: none; }
  .ws-resizer { display: none; }   /* 窄屏上下堆叠，没有「宽」可调 */
  .brand span { display: none; }
  /* 「工作区」按钮窄屏保留可用：≤820px 工作区默认收起（app.js），按钮是展开
     谱头速览 / 声部管理的唯一入口（预览模式下由 .topbar [data-editable] 隐藏，不受影响）。 */

  /* 触摸目标：**下拉菜单行 / banner 按钮** ≥44px（行高即热区，不牺牲视觉）。
     顶栏 / 播放条按钮**保持自然 30px**——M0.4 曾把它们也拉到 44px，视觉太大把
     顶栏撑成 3 行（用户反馈「要素都比较大、挤到下面的行」）。小按钮 + 足间距
     在手机上可点，纵向空间还给谱面才是收益。 */
  .library-banner .btn,
  .menu-item,
  .menu-btns .tb { min-height: 44px; }
  /* 库谱只读通知横幅在手机上不再独占一行：CTA（存一份 / 复制链接）已移进顶栏 / 保存菜单，
     横幅只剩说明文字、且与状态条「已打开谱库…只读」重复。只选 #library-banner，
     不碰同样用 .library-banner 类的首次引导横幅（#onboarding-banner，编辑态才出现）。 */
  #library-banner { display: none; }
  /* 顶栏 / 播放条压紧：更小的行内间距 + 更窄的 padding，能少一行就少一行。
     真正的「顶栏单行化」（低频按钮收进 ⋯ 菜单）在 ≤600px 断点 —— 手机视口；
     768 平板仍按平铺 + 换行处理，不提前收窄。 */
  .topbar { min-height: 44px; padding: 4px 10px; gap: 4px 8px; }
  .player-bar { padding: 4px 10px; gap: 6px 8px; }
  .doc-info { font-size: 12px; }
  #doc-title { max-width: 8ch; }

  /* 预览宽度滑杆在窄屏无意义（谱面本就按视口重排，宽度恒占满），隐藏；
     「满屏 / A4 竖版」两档留待 M0.3 需要时再补，不预先做。 */
  #preview-width-ctrl { display: none; }

  /* 状态条：多条错误时换行而不是被 max-height 裁掉（overflow:auto 已有，这里保可读间距） */
  .status-strip { padding: 4px 12px; }

  /* 手机端小键盘：窄屏才放开（基线 display:none，这里 :not([hidden]) 才 flex）。
     流内停靠在状态条下 / 播放器上（.panel flex-column 里），打开时播放器自然下移，
     不占 position:fixed、不跟滚动 / 焦点打架。44px 触摸键（沿用菜单行 / banner 键的 44px 先例）。 */
  .note-keyboard:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 10px;
    border-top: 1px solid var(--line);
    background: var(--bg);
  }
  .note-keyboard .kb-row { display: flex; gap: 6px; }
  .note-keyboard .kb-key {
    flex: 1 1 0;
    min-height: 44px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg-2);
    color: var(--ink);
    font-size: 15px;
    line-height: 1;
  }
  .note-keyboard .kb-key:active { background: #e6e6e6; }
  .note-keyboard .kb-key.active { background: var(--ink); border-color: var(--ink); color: #fff; }
  .note-keyboard .kb-key.kb-rest { color: var(--ink-2); }
  .note-keyboard .kb-key.kb-close { flex: 0 0 auto; width: 44px; color: var(--dim); }
  /* 时值键：显示的是简谱记号（`1 - - -` / `1_` 这类），字号收紧、等宽数字、不换行 */
  .note-keyboard .kb-durkey { font-size: 12px; white-space: nowrap; font-variant-numeric: tabular-nums; }
  /* 宽键（延音线 / 圆滑线 / ＋小节 这类两字以上的中文键）：占两个普通键宽 */
  .note-keyboard .kb-wide { flex: 2 1 0; }
  /* 导航键：箭头符号大一号、居中 */
  .note-keyboard .kb-nav { font-size: 18px; }
  /* tab 栏：常驻在面板顶部，✕ 永远可达；当前页 tab 用下划线式点亮（克制，不填色） */
  .note-keyboard .kb-tabs { display: flex; align-items: stretch; gap: 2px; }
  .note-keyboard .kb-tabs .kb-close { margin-left: auto; align-self: center; min-height: 40px; }
  .note-keyboard .kb-tab {
    flex: 1 1 0;
    min-height: 44px;
    border: 0;
    background: transparent;
    color: var(--dim);
    font-size: 14px;
    border-bottom: 2px solid transparent;
  }
  .note-keyboard .kb-tab.active { color: var(--ink); border-bottom-color: var(--ink); font-weight: 600; }
}
