/* ============================================================================
   渐变流动 Gradient Flow · 设计系统
   与 ring-strands / particle-pointcloud 同一套视觉语言：
     单色阶（黑/白/灰），层级只靠明度（--ink → --ink-4）与 1px 细线建立，不靠颜色。
     唯一的彩色只出现在「图像内容本身」——色带、取色点、取样线预览。
   理由：这是个调色工具，UI 带颜色会干扰用户对画布颜色的判断。
   ============================================================================ */
:root {
  color-scheme: dark;
  --ink:    #f5f5f5;                    /* 主文字 */
  --hi:     #bcbcbc;                    /* 滑块已填充段 / 手柄 */
  --glass-1: rgba(255,255,255,.28);
  --glass-2: rgba(255,255,255,.16);
  --glass-3: rgba(255,255,255,.085);
  --ink-2:  #9c9c9c;                    /* 标签、次级文字 */
  --ink-3:  #626262;                    /* 说明文字、非激活图标 */
  --ink-4:  #2e2e2e;                    /* 滑轨未填充部分 */
  --line:   rgba(255,255,255,.10);
  --line-2: rgba(255,255,255,.20);
  /* ---- 面板玻璃（2026-10-03 第 2 轮，按用户给的 reference/玻璃UI材质参考.jpg 改）----
     基线是 rgba(10,10,10,.90) 的"黑底板"。现在拆成两块：
       · --panel-rgb / --panel-a  = 玻璃的本体色与**浓度**
       · --glass-edge / --glass-top = 参考图里那两件玻璃特征物：1px 亮边 + 内上沿高光
     ⚠️ --panel-a 不是固定值：面板一透明，文字对比度就取决于**面板底下那片画布多亮**，
     所以它由 app.js 的 glassTick()/panelAForBg() 按实测底亮度实时给（暗背景更透、亮背景更实）。
     boot() 里会立刻调 applyPanelA() 把保守值（.88，最实）写上去，所以下面这个 .62
     只是"JS 没跑起来"时的兜底值，正常看不到。 */
  --panel-rgb: 10,10,12;
  --panel-a: .62;
  --panel:  rgba(var(--panel-rgb), var(--panel-a));
  --glass-edge: rgba(255,255,255,.16);
  --glass-top:  rgba(255,255,255,.13);
  /* 玻璃上的输入底/分段底：原来是实色 #191919，那会在玻璃上贴出一块"黑补丁" */
  --field:  rgba(255,255,255,.055);
  --ease:   cubic-bezier(.32,.72,0,1);  /* 面板进出场：先快后缓，有"重量感" */
  --r-panel: 12px;                      /* 度量表：面板圆角 */
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
  width: 100%; height: 100%; overflow: hidden; background: #000; color: var(--ink);
  font: 12px/1.5 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
button:focus-visible, summary:focus-visible, input:focus-visible, select:focus-visible {
  outline: 1px solid var(--ink); outline-offset: 2px;
}
input[type=range]:focus-visible { outline: none; }
input[type=range]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px rgba(255,255,255,.28); }
summary::-webkit-details-marker { display: none; }
summary { cursor: pointer; list-style: none; }
summary::-webkit-details-marker { display: none; }

/* ---------------------------------------------------------------- 画布 */
#stage { position: fixed; inset: 0; background: #000; }
#gl { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
#stage.grabbing { cursor: grabbing; }

/* 画面右下角的极简状态：分辨率 / 帧率。透明度极低，不抢画面 */
#hud {
  position: absolute; right: 14px; bottom: 12px; z-index: 3;
  font: 10px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: rgba(255,255,255,.30); letter-spacing: .04em; text-align: right;
  pointer-events: none; text-shadow: 0 1px 3px rgba(0,0,0,.5);
  opacity: 0; transition: opacity .3s var(--ease);
}
#hud.on { opacity: 1; }

/* ---------------------------------------------------------------- 面板 */
.panel {
  position: fixed; top: 14px; bottom: 14px; width: 286px; z-index: 10;
  max-height: calc(100vh - 28px);
  display: flex; flex-direction: column;
  /* 玻璃 = 半透明本体 + 一层左上向右下的白色斜光（模拟玻璃受光面）
     + 强背景模糊与提饱和（参考图里卡片背后的东西完全不可辨，却仍能看出是它） */
  background-color: var(--panel);
  background-image: linear-gradient(158deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,.022) 38%, rgba(255,255,255,0) 64%);
  border: 1px solid var(--glass-edge);
  border-radius: var(--r-panel);
  backdrop-filter: blur(30px) saturate(170%);
  -webkit-backdrop-filter: blur(30px) saturate(170%);
  box-shadow: 0 26px 64px rgba(0,0,0,.42),
              inset 0 1px 0 var(--glass-top),
              inset 0 -1px 0 rgba(0,0,0,.18);
  transition: transform .42s var(--ease), opacity .3s var(--ease);
}
#panelL { left: 14px; }
#panelR { right: 14px; }
.panel.collapsed { transform: translateX(calc(-100% - 20px)); opacity: 0; pointer-events: none;
  visibility: hidden; }  /* visibility 必加：只改 opacity 的话元素还留在无障碍树里 */
#panelR.collapsed { transform: translateX(calc(100% + 20px)); }

.panel-head {
  display: flex; align-items: center; gap: 7px;
  position: sticky; top: 0; z-index: 2;
  padding: 13px 14px 11px; border-bottom: 1px solid var(--line); flex: none;
  /* sticky 标题栏必须有底，否则滚动内容会从字底下穿过去。但它也得是**玻璃**：
     一层极淡的白 + 自己的背景模糊（backdrop-filter 会连带糊掉滚到它下面的内容）。 */
  background: linear-gradient(to bottom, rgba(255,255,255,.055), rgba(255,255,255,.015));
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  /* 必须跟随父级圆角：sticky 标题栏自带背景，方角会盖住面板的圆角，
     在顶端露出两个"尖角"（用户实测反馈）。 */
  border-radius: var(--r-panel) var(--r-panel) 0 0;
}
/* 项目名改为 8 字（色彩渐变流动背景）后，286px 面板的一行放不下：
   收紧字距并禁止 h1 / 按钮换行（否则标题断成两行、按钮被挤成"收/起"上下两字）。2026-09-23 */
.panel-head h1 { font-size: 12px; font-weight: 600; letter-spacing: .02em; white-space: nowrap; flex: none; }
.panel-head .btn { white-space: nowrap; flex: none; }

/* 面板顶部的快捷条：常用动作放最上面，不用展开折叠分组去找 */
.toolbar { padding: 10px 14px 11px; border-bottom: 1px solid var(--line); flex: none; }
.toolbar .row { margin-top: 0; }
.toolbar .row + .seg { margin-top: 6px; }
.toolbar .btn { width: 100%; margin-top: 8px; }
/* 语言段控（中 / EN）。度量与 particle-pointcloud 的 .lang-seg 一致：
   只在面板标题栏里出现，固定宽、不许被压缩，字号比普通段控小一档。
   （原 .panel-head .tag 的"英文角标"规则随 2026-09 夜间任务"去掉标题上的英文"一并删除。） */
.lang-seg { flex: none; width: 56px; }
.lang-seg > button { padding: 3px 0; font-size: 10px; letter-spacing: .02em; }
.panel-head .sp { flex: 1; }

.body { overflow-y: auto; overflow-x: hidden; padding: 4px 0 14px; flex: 1; }
.body::-webkit-scrollbar { width: 9px; }
.body::-webkit-scrollbar-thumb { background: rgba(255,255,255,.16); border-radius: 4px; }
.body::-webkit-scrollbar-track { background: transparent; }

section { border-bottom: 1px solid var(--line); }
section:last-child { border-bottom: 0; }
.sec-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 14px; text-align: left;
}
.sec-head .no {
  font: 9px/1 ui-monospace, Menlo, monospace; color: var(--ink-3);
  letter-spacing: .06em; width: 14px; flex: none;
}
.sec-head .t { font-size: 11.5px; letter-spacing: .08em; color: var(--ink); flex: 1; }
.sec-head .caret {
  width: 8px; height: 8px; border-right: 1px solid var(--ink-3); border-bottom: 1px solid var(--ink-3);
  transform: rotate(-135deg); transition: transform .28s var(--ease); margin-right: 2px;
}
section.open .sec-head .caret { transform: rotate(45deg); }
.sec-body { display: none; padding: 1px 14px 13px; }
section.open .sec-body { display: block; }

/* ---------------------------------------------------------------- 控件 */
.row { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.row:first-child { margin-top: 2px; }
/* 参数名不再 flex:1 撑满整行 —— 那是 ↺ 被顶到最右边的根因：
   名字吃掉所有剩余空间后，插在它后面的 ↺ 实际落点紧贴右对齐的读数，
   离参数名隔了半个面板（"位置太远，有点尴尬"）。改成读数自己
   margin-left:auto 靠右，名字保持内容宽度，↺ 才会紧贴名字。
   这也是 particle-pointcloud / baseline.css 的写法（.ctl-head .v）。 */
.lab { font-size: 11px; color: var(--ink-2); letter-spacing: .02em; }
.val {
  font: 10px/1 ui-monospace, Menlo, monospace; color: var(--ink-2);
  min-width: 42px; text-align: right; letter-spacing: .02em; margin-left: auto;
}

input[type=range] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; background: none; cursor: pointer; display: block;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 2px; border-radius: 1px;
  background: linear-gradient(to right, var(--hi) var(--p, 0%), var(--ink-4) var(--p, 0%));
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 10px; height: 10px; border-radius: 50%;
  background: #fff; border: 0; margin-top: -4px;
  box-shadow: 0 1px 4px rgba(0,0,0,.6); transition: transform .16s var(--ease);
}
input[type=range]:hover::-webkit-slider-thumb { transform: scale(1.2); }
input[type=range]:active::-webkit-slider-thumb { transform: scale(1.35); }
input[type=range]::-moz-range-track { height: 2px; border-radius: 1px; background: var(--ink-4); }
input[type=range]::-moz-range-progress { height: 2px; border-radius: 1px; background: var(--hi); }
input[type=range]::-moz-range-thumb { width: 10px; height: 10px; border: 0; border-radius: 50%; background: #fff; }

/* 分段控件：玻璃选中药（半透明白纵向渐变 + 上沿高光） */
.seg {
  display: flex; gap: 2px; padding: 2px; border-radius: 7px;
  background: var(--field); border: 1px solid var(--line);
}
.seg button {
  flex: 1; padding: 4px 2px; border-radius: 5px; font-size: 11px; letter-spacing: .02em;
  color: var(--ink-3); transition: color .18s var(--ease), background .18s var(--ease);
  white-space: nowrap;
}
.seg button:hover { color: var(--ink-2); }
.seg button.on {
  color: #fff;
  background: linear-gradient(to bottom, var(--glass-1), var(--glass-2) 55%, var(--glass-3));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.16), 0 1px 3px rgba(0,0,0,.4);
}

/* 开关（switch）。⚠️ 这是本项目对「工具类UI风格」的**一次有意偏离**：
   技能规范第 6 条明确写"不用开关（switch）、不用单选按钮"——理由是会引入第三种控件语言。
   2026-09 用户明确要求"设一个开关切换玻璃的有无"，故按基线令牌实现一个最小开关：
   关闭 = 只有 1px 描边 + 灰点；打开 = 与分段控件选中态同一套"单色玻璃"填充 + 白点，
   不引入任何新的颜色或形状语言（圆角/描边宽度/过渡曲线都取自基线令牌）。
   如果哪天要回到严格基线：把这里删掉，让玻璃类型多一个「关」选项即可。 */
.tgl {
  flex: none; margin-left: auto; width: 28px; height: 15px; padding: 0;
  border: 1px solid var(--line-2); border-radius: 8px; background: none; cursor: pointer;
  position: relative; transition: background .18s var(--ease), border-color .18s var(--ease);
}
.tgl i {
  position: absolute; top: 2px; left: 2px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--ink-3); transition: transform .18s var(--ease), background .18s var(--ease);
}
.tgl:hover { border-color: var(--ink-3); }
.tgl.on { background: linear-gradient(to bottom, var(--glass-1), var(--glass-3)); border-color: var(--ink-3); }
.tgl.on i { transform: translateX(13px); background: var(--ink); }
.tgl:focus-visible { outline: 1px solid var(--line-2); outline-offset: 2px; }

/* 实心按钮 = 唯一的"主操作"外观 */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 10px; border-radius: 7px; font-size: 11.5px; letter-spacing: .04em;
  border: 1px solid var(--line-2); color: var(--ink-2);
  background: linear-gradient(to bottom, var(--glass-3), rgba(255,255,255,.03));
  transition: color .18s var(--ease), border-color .18s var(--ease), background .18s var(--ease);
}
.btn:hover { color: var(--ink); border-color: rgba(255,255,255,.34); background: rgba(255,255,255,.08); }
.btn:active { background: rgba(255,255,255,.14); filter: brightness(.94); }
.btn.primary {
  color: #fff; background: linear-gradient(to bottom, var(--glass-1), var(--glass-2) 55%, var(--glass-3));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.16);
}
.btn.wide { width: 100%; }
.btn[disabled] { opacity: .34; pointer-events: none; }
.btn.sm { padding: 5px 8px; font-size: 10px; }
.btn-row { display: flex; gap: 6px; margin-top: 10px; }
.btn-row .btn { flex: 1; }

.hint { font-size: 10.5px; line-height: 1.55; color: var(--ink-3); letter-spacing: .02em; margin-top: 9px; }
.hint b { color: var(--ink-2); font-weight: 500; }
.mono { font-family: ui-monospace, Menlo, monospace; }
.val, .sheet textarea, #pickHex { font-variant-numeric: tabular-nums; }

/* ↺ 重置：紧贴参数名，平时 .4、悬停才到 1；已在默认值上时更淡且不可点。
   工具类UI风格的核心——试错成本为零，所以每个数值参数都得有。
   ⚠️ 2026-09 用户发现"默认时显着、调完反而消失"，是本项目偏离基线的结果：
   这里原本基础不透明度写成 0（只有 .row:hover 才 .55），而 .at-default 是
   .12 —— 于是静止时"默认的看得见、改过的不悬停就看不见"，逻辑正好反了。
   现按 particle-pointcloud / baseline.css 逐行对齐：基础 .4，悬停 1，
   .at-default .12 且 pointer-events:none（规则必须排最后：与 :hover 同特异性，
   靠顺序取胜，这也是基线里不写 !important 的原因）。 */
.rv {
  align-self: center; flex: none; margin-left: -5px;
  width: 15px; height: 15px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 50%; background: none;
  color: var(--ink-3); font-size: 10px; line-height: 1; cursor: pointer;
  opacity: .4; transition: opacity .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.rv:hover, .rv:focus-visible { opacity: 1; color: var(--ink); border-color: var(--line-2); }
.rv.at-default { opacity: .12; pointer-events: none; }

/* ---------------------------------------------------------------- 取样 */
#drop {
  margin: 2px 0 10px; padding: 16px 12px; border-radius: 10px; text-align: center;
  border: 1px dashed var(--line-2); background: rgba(255,255,255,.015); cursor: pointer;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
#drop:hover, #drop.drag { border-color: var(--hi); background: rgba(255,255,255,.045); }
#drop .t { font-size: 11.5px; }
#drop .s { font-size: 10px; color: var(--ink-3); margin-top: 4px; letter-spacing: .02em; }

#imgBox {
  position: relative; margin-top: 10px; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--line); background: #0d0d0d; display: none;
}
#imgBox.on { display: block; }
#imgBox canvas { display: block; width: 100%; height: auto; cursor: crosshair; }
#lineSvg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
#lineSvg .ln { stroke: #fff; stroke-width: 1.25; vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 3px rgba(0,0,0,.9)); }
#lineSvg .h { fill: rgba(0,0,0,.45); stroke: #fff; stroke-width: 1.25; vector-effect: non-scaling-stroke; }
#lineSvg .tick { stroke: rgba(255,255,255,.55); stroke-width: 1; vector-effect: non-scaling-stroke; }

/* 色带：一段连续渐变 + 骑在上面的 12 个取色点 */
#bandWrap { position: relative; margin-top: 12px; }
#band {
  height: 26px; border-radius: 6px; border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07);
}
#swatches { position: absolute; left: 0; right: 0; top: 0; height: 26px; }
.sw {
  position: absolute; top: 0; height: 26px; padding: 0; border-radius: 5px;
  transform: translateX(-50%); transition: box-shadow .16s var(--ease);
}
.sw i { display: block; width: 100%; height: 100%; border-radius: 5px; }
.sw b {
  position: absolute; left: 50%; top: 50%; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  border-radius: 50%; background: #fff; box-shadow: 0 0 0 1.5px rgba(0,0,0,.55);
  transition: transform .16s var(--ease);
}
.sw:hover b, .sw.open b { transform: scale(1.5); }
.sw.edited i::after {
  content: ''; position: absolute; inset: 0; border-radius: 5px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.85);
}
.sw .x {
  position: absolute; left: 50%; top: -15px; transform: translateX(-50%);
  width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 50%;
  font-size: 10px; color: var(--ink); background: rgba(20,20,20,.92);
  border: 1px solid var(--line-2); display: none;
}
.sw.edited .x { display: block; }
.sw .x:hover { color: #fff; background: #333; }

/* 内联 HSV 取色器（自己画，不依赖原生 <input type=color>：
   原生面板无法在自动化环境里驱动，也无法在 Safari 上稳定 showPicker()） */
#picker {
  position: fixed; z-index: 40; width: 190px; padding: 10px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--line-2);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 16px 40px rgba(0,0,0,.6); display: none;
}
#picker.on { display: block; }
#sv { position: relative; height: 110px; border-radius: 6px; cursor: crosshair; overflow: hidden; }
#svC { display: block; width: 100%; height: 100%; }
#svDot {
  position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  box-shadow: 0 0 0 1.5px #fff, 0 0 0 3px rgba(0,0,0,.45); pointer-events: none;
}
#hue { -webkit-appearance: none; appearance: none; width: 100%; height: 14px; margin-top: 9px;
  border-radius: 4px; cursor: pointer; background: linear-gradient(to right,
    #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); }
#hue::-webkit-slider-thumb { -webkit-appearance: none; width: 8px; height: 18px; border-radius: 3px;
  background: #fff; border: 0; box-shadow: 0 1px 4px rgba(0,0,0,.7); }
#hue::-moz-range-thumb { width: 8px; height: 18px; border: 0; border-radius: 3px; background: #fff; }
#pickHead { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; }
#pickChip { width: 22px; height: 22px; border-radius: 5px; border: 1px solid var(--line-2); flex: none; }
#pickHex { flex: 1; background: var(--field); border: 1px solid var(--line);
  border-radius: 5px; color: var(--ink); font: 10.5px/1 ui-monospace, Menlo, monospace;
  padding: 6px 7px; letter-spacing: .04em; }
#pickHex:focus { outline: 1px solid var(--hi); outline-offset: 0; }

/* ---------------------------------------------------------------- 预设 */
#presets { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 4px; }
.preset {
  position: relative; border-radius: 8px; overflow: hidden; height: 46px;
  border: 1px solid var(--line); transition: border-color .18s var(--ease), transform .18s var(--ease);
}
.preset:hover { border-color: var(--line-2); transform: translateY(-1px); }
.preset.on { border-color: var(--hi); box-shadow: 0 0 0 1px var(--hi); }
.preset i { position: absolute; inset: 0; }
.preset span {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 3px 6px; font-size: 9.5px;
  letter-spacing: .03em; text-align: left; color: #fff;
  background: linear-gradient(to top, rgba(0,0,0,.62), rgba(0,0,0,0));
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
}

/* ---------------------------------------------------------------- 弹层 */
#modal {
  position: fixed; inset: 0; z-index: 60; display: none;
  align-items: center; justify-content: center; padding: 24px;
  background: rgba(0,0,0,.66); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
#modal.on { display: flex; }
.sheet {
  width: min(720px, 100%); max-height: 82vh; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line-2); border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,.7); overflow: hidden;
}
.sheet header {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.sheet header h2 { font-size: 12.5px; font-weight: 600; letter-spacing: .04em; flex: 1; }
.sheet .content { padding: 16px; overflow: auto; }
.sheet textarea {
  width: 100%; height: 300px; resize: vertical; background: rgba(0,0,0,.38); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 12px;
  font: 10.5px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
}
.sheet .btn-row { margin-top: 12px; }

/* 进度条（录制时） */
#recBar {
  position: fixed; left: 50%; top: 16px; transform: translate(-50%, -30px); z-index: 30;
  display: flex; align-items: center; gap: 10px; padding: 8px 14px; border-radius: 999px;
  background: rgba(var(--panel-rgb), min(.86, calc(var(--panel-a) + .18)));
  border: 1px solid var(--glass-edge);
  backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: 0 12px 34px rgba(0,0,0,.6); opacity: 0; pointer-events: none;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
#recBar.on { opacity: 1; transform: translate(-50%, 0); }
#recBar .dot { width: 7px; height: 7px; border-radius: 50%; background: #e05252; animation: blip 1.1s infinite; }
@keyframes blip { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
#recBar .txt { font: 10.5px/1 ui-monospace, Menlo, monospace; letter-spacing: .05em; color: var(--ink-2); }

#toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 12px); z-index: 50;
  padding: 9px 15px; border-radius: 999px; font-size: 11px; letter-spacing: .02em;
  background: rgba(var(--panel-rgb), min(.88, calc(var(--panel-a) + .20)));
  border: 1px solid var(--glass-edge); color: var(--ink);
  backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: 0 12px 34px rgba(0,0,0,.5); opacity: 0; pointer-events: none;
  transition: opacity .28s var(--ease), transform .28s var(--ease);
}
#toast.on { opacity: 1; transform: translate(-50%, 0); }

/* 底部中央的极简播放条：只在大面板都收起时出现 */

/* ---------------------------------------------------------------- 收起后的唤出按钮 */
/* 一个按钮控两侧面板；收起后它出现在右上角。（这段样式曾经在某轮重构里被误删，
   结果按钮变成普通文档流里的裸 div —— 用户反馈"收起后找不到唤回按钮"，就是这个原因。） */
#toggleBtn {
  position: fixed; top: 14px; right: 14px; z-index: 21; padding: 7px 12px;
  border: 1px solid var(--line-2); border-radius: 8px; background: var(--panel);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  color: var(--ink-2); font-size: 11px; letter-spacing: .08em; cursor: pointer;
  opacity: 0; pointer-events: none;
  transform: translateY(-6px);
  transition: opacity .25s var(--ease), transform .25s var(--ease), color .15s var(--ease);
}
#toggleBtn.show { opacity: 1; pointer-events: auto; transform: none; }
#toggleBtn:hover { color: var(--ink); border-color: var(--ink); }

/* HUD：只在收起面板时出现，极低存在感 */
#hud.on { opacity: 1; }

/* ---------------------------------------------------------------- 窄屏 */
/* 手机宽度放不下并排的两个面板：让面板占满可用宽度，并且同一时刻只显示一个
   （头部那个 .mob-switch 按钮负责互切）。.mobOff 只在窄屏里有定义，
   桌面端即使带着这个 class 也不受影响。 */
.mob-switch { display: none; }
@media (max-width: 900px) {
  .panel { width: min(calc(100vw - 20px), 430px); }
  #panelL, #panelR { top: auto; bottom: 10px; height: min(64vh, 560px); left: 10px; right: 10px; }
  .mob-switch { display: inline-flex; }
  .mobOff { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}
