:root {
  /* 声明页面自己适配深浅两套配色：不声明的话，移动端浏览器的「自动深色」会把
     自己的强制改色叠在页面之上 —— 图片被加反色滤镜泛白、卡片按钮被改成纯黑、
     半透明的选中背景直接被吃掉 */
  color-scheme: light dark;
  --bg: #F4F6F8;
  --card: #FFFFFF;
  --text: #1F2430;
  --text-2: #5A6280;
  --border: #E2E6EC;
  /* 加深一档的描边：给「必须一眼看出是按钮」的控件用（导出按钮等） */
  --border-2: #C7D0DC;
  --track: #E6EAEE;
  --bar-a: #8FAEA6;
  --bar-b: #67897F;
  --hover: #F0F3F6;
  /* 下面三个与 LvchaxsBS 主题字典同值，专供排序按钮（SortOptionButtonStyle）使用：
     PrimaryBrush 蓝条 / AccentSoftBrush 选中底 / HoverBackgroundBrush 悬停玻璃（#9E = 62%） */
  --accent: #3B82F6;
  --accent-soft: rgba(59, 130, 246, .13);
  --glass: rgba(255, 255, 255, .62);
  /* 今日增减：多了绿、少了红（与 LvchaxsBS 的 SuccessBrush / DangerBrush 同值） */
  --good: #10B981;
  --bad: #EF4444;
}

html[data-theme="dark"] {
  --bg: #1A1D22;
  --card: #22262C;
  --text: #E4E8EE;
  --text-2: #A9B1CE;
  --border: #333941;
  --border-2: #4C545F;
  --track: #2E343B;
  --bar-a: #8FB5AB;
  --bar-b: #BBD6CE;
  --hover: #2A2F36;
  --accent: #5B93FF;
  /* 选中底色用深色 accent 的蓝色半透明，而不是半透明白 —— 白 8% 在深底上几乎看不见，
     排序按钮选中后只剩蓝条、看不出选中底 */
  --accent-soft: rgba(91, 147, 255, .16);
  --glass: rgba(56, 56, 56, .62);
  --good: #4ADE80;
  --bad: #F87171;
}

/* 主题只由 <html> 上的 data-theme 决定（index.html 头部脚本首帧写好、按钮手动切换），
   不再跟随系统深浅色。深色变量就一份，见上面 html[data-theme="dark"]。 */

/* 主题切换过渡：切换那一下给 <html> 临时挂 .theme-transition（平时不挂，避免影响 hover / 折叠等动画），
   整页所有元素用**同一条曲线**一起变：底色、卡片、描边、阴影、图标填充都是 .22s linear。
   · 用 linear 是为了让每个颜色的中点都正好落在 110ms，各元素亮度推进比例始终一致；
   · 文字（color）不跟着插值 220ms：深字与浅底、浅字与深底同步插值时中途会撞成同一个颜色，
     那一段字就真的看不见。改成在第 110ms（背景正好到中点、深字浅字对比度最平衡处）用 .01s（1 帧）翻面，
     之前深字压浅底、之后浅字压深底，全程都读得清，也不会「先消失再出现」。
   暗月那边 darkmoon4/css/dm-theme.css 有同款规则，两边同一帧挂上。 */
html.theme-transition,
html.theme-transition::before,
html.theme-transition *,
html.theme-transition *::before,
html.theme-transition *::after {
  transition: background-color .22s linear, border-color .22s linear, outline-color .22s linear,
              box-shadow .22s linear, fill .22s linear, background-image .22s linear,
              color .01s linear .1s !important;
}

* { box-sizing: border-box; }

/* 点击/触摸任何按钮都不给反馈：去掉移动端默认的淡蓝色 tap 高亮方块，以及点完留下的焦点方框 */
* { -webkit-tap-highlight-color: transparent; }
*:focus, *:focus-visible { outline: none; }

/* 必须放在所有规则之前又带 !important：
   作者样式表的 display 会盖掉浏览器默认的 [hidden]{display:none}，
   不补这条的话元素加了 hidden 属性也照样显示（关不掉）。 */
[hidden] { display: none !important; }

/* 数量输入框：去掉浏览器自带的上下加减箭头（瞄准网页里干净的输入框观感） */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* 页面底色画在 html::before 这个 fixed 层上，body 自身保持透明：
   根元素（html/body）的背景会被浏览器「传播」到 canvas，那一层不参与逐帧重绘 —— 切主题时
   内容区早就变完了，整页底色要等过渡结束才一下跳过来（实测 t150 时 html 的 computed 是
   rgb(82,85,90)、屏幕上的像素还是 rgb(47,52,58)）。fixed 层是普通元素，和卡片/文字同一条曲线。
   --bg 是各页通用底色；暗月页（body.dm-view）另有固定底色，用 :has 挂到同一层上。
   不支持 :has 的浏览器退回 --bg，与 #fff / #151a21 只差几个色阶。 */
html::before {
  content: '';
  position: fixed;
  /* 不用 inset:0 —— 那只能盖住「布局视口」。移动端往下滑时地址栏收起，可视区会高出一截
     （正好是地址栏的高度），多出来的那一条在本层之外，露的是浏览器默认白色画布，
     看着就是「底部滑上来的背景是浅色的」。上下各多铺一截，视口怎么变都盖得住；
     上溢那截顺带盖住下拉回弹时露出的画布。 */
  left: 0;
  top: -20vh;
  width: 100%;
  height: 140vh;    /* 回退：老浏览器把 vh 当大视口 */
  height: 140lvh;   /* 大视口 ×1.4，地址栏收放的落差全在里面 */
  z-index: -1;
  pointer-events: none;
  background-color: var(--bg);
}
html:has(body.dm-view)::before { background-color: #fff; }
html:has(body.dm-view.dm-dark)::before { background-color: #151a21; }

body {
  margin: 0;
  background: transparent;
  color: var(--text);
  font: 14px/1.5 "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* 展开 / 合并会让卡片高度连续变化，浏览器默认的「滚动锚定」会逐帧补偿 scrollTop，
   表现为视口内容上下一起抽（看着像回弹）；关掉它，高度变化只影响卡片下方，卡片顶不动 */
html, body { overflow-anchor: none; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  padding: 4px 6px;
  background: var(--card);
  border-bottom: 1px solid var(--border);
}

/* ================= 顶部导航（照抄 LvchaxsBS 的 NavButtonStyle） =================
   四项 = 主程序左侧「锄地记录」下的四个子项：每日锄地 / 路线管理 / 材料统计 / 分析总结。
   常态：透明底 + 次要文字；选中（Tag=1）：浅蓝底 + 左侧 2px 蓝竖杠 + 文字加粗
   （★ 文字颜色不变，与 XAML 一样只靠底色、竖杠、字重区分）。 */
.nav { display: flex; }

/* 暂时关闭「每日锄地」「分析总结」两个导航：只隐藏不删，恢复时删掉这条规则即可 */
/* 「每日锄地」「分析总结」的显隐由 JS 控制（云端同步页的开关 + 登录态）：
   未登录或开关未勾选 ⇒ nav.hidden = true；不在这里写死 display:none */

.nav-item {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 6px 2px 5px 4px;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}

/* 图标一律描边（不填充），颜色跟着按钮的 color 走：
   与 XAML 里 Stroke 绑到 Button.Foreground 是同一套做法。 */
.nav-icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linejoin: round;
  stroke-linecap: round;
  flex: none;
}

/* 选中时的左竖杠：从中间展开（scaleY 0→1），与 XAML 的 Rect+ScaleTransform 同一套时序 */
.nav-item::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 50%;
  width: 2px;
  height: 14px;
  margin-top: -7px;
  border-radius: 1px;
  background: var(--accent);
  opacity: 0;
  transform: scaleY(0);
  transition: transform .18s cubic-bezier(0, 0, .58, 1), opacity .08s;
}

/* 悬停底色同样只给真有鼠标的设备（触屏粘滞问题同上） */
@media (hover: hover) {
  .nav-item:hover { background: var(--glass); color: var(--text); }
}

/* 查看别人的时候：每日锄地 / 导入导出 不能进，按钮直接置灰不给点 */
.nav-item:disabled { opacity: .32; cursor: default; }

.nav-item.on { background: var(--accent-soft); font-weight: 700; color: var(--text); }
.nav-item.on::before { opacity: 1; transform: scaleY(1); }

/* 通用 button 的 :active 缩放是给按钮用的，导航项不要跟着弹 */
.nav-item:active { transform: none; }

/* 还没接入内容的页面：一行浅色说明，不铺任何假控件 */
.empty {
  margin: 0;
  padding: 48px 14px;
  text-align: center;
  font-size: 13px;
  color: var(--text-2);
}

button, select, input[type="text"], input[type="search"], input[type="number"] {
  font: inherit;
  color: var(--text);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
}

button {
  cursor: pointer;
  transition: transform .12s ease, background .12s ease;
}
/* 悬停底色只给真有鼠标的设备：触屏上点完按钮 :hover 会一直粘着不消失
   （浅色的 --hover 偏白 ⇒ 点完选择再取消后按钮看着变白，点别处才恢复） */
@media (hover: hover) {
  button:hover { background: var(--hover); }
}
button:active { transform: scale(1.15); }

/* 页面容器：同一时间只显示一页，由导航切换 hidden */
main { padding: 0 0 24px; }

/* 排序条贴着导航，下面才是材料行 */
.page > .sort-bar { padding: 10px 14px 6px; }

/* 材料统计一条不剩时的空态：整行居中（#list 已经有左右留白，这里不再叠 margin） */
#list .list-empty { margin: 10px 0 0; }

/* ================= 排序按钮（照抄 LvchaxsBS 的 SortOptionButtonStyle） =================
   常态：透明底 + 次要文字色；悬停：玻璃底 + 文字提亮；
   选中（Tag=1）：浅蓝底 + 左侧 2px 蓝竖杠 + 文字加粗（★ 不换文字颜色，区分只靠底色和竖杠）。
   ★ 竖杠用「scaleY 0→1 + EaseOut 0.18s」，与 XAML 的 Rect+ScaleTransform 动画同一套时序。 */
.sort-bar { display: flex; align-items: center; }

/* 材料统计排序栏：左 / 右 两组 —— 两组各占一半剩余空间（贴边）：左=排序键与隐藏毕业，右=砂糖/多莉 + 合成 */
#sort-bar { justify-content: space-between; }
.sort-grp { display: flex; align-items: center; }
/* ★ basis 必须是 auto（按内容宽）而不是 0：写 0 时左右两组只按「剩余空间的一半」定宽，
   与自己的内容宽无关 —— 左组按钮多、右组少，左组窄于内容就向右溢出，
   直接压到右边的按钮上（表现为按钮重叠）。auto 保证组宽不小于内容。
   1 0 auto：只长不缩，组内按钮永远不会被压到互相叠字 */
#sort-left { flex: 1 0 auto; min-width: 0; justify-content: flex-start; }
#sort-right { flex: 1 0 auto; min-width: 0; justify-content: flex-end; }

/* 右侧「合成」切换按钮：外观与普通排序按钮完全一致（含选中左蓝条），
   只是 data-k=swap 走场景切换逻辑，不做任何排序 */

.sort-opt {
  position: relative;
  height: 24px;
  padding: 0 10px 0 11px;      /* 左边 11：给左竖杠留位置，与 XAML Padding="11,0,10,0" 一致 */
  margin-right: 4px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;           /* 默认粗体：选中与否都粗，区分只靠蓝底和左竖杠 */
  color: var(--text-2);
  background: transparent;
  /* 去掉浏览器 / X5(QQ浏览器) 自带的按钮外观：不写这些，有些内核会自己描一圈边框、
     再叠上内阴影和内边距，按钮实际变宽 ⇒ 一行放不下时「降序」和「隐藏毕业」会挤到重叠 */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border: 0;
  box-shadow: none;
  border-radius: 4px;         /* CornerRadius=4 */
  cursor: pointer;
  white-space: nowrap;        /* 按钮文字永不换行（窄屏靠压 padding 保一行） */
  flex: 0 0 auto;             /* 空间不够也不许压窄（压窄会变成文字互相叠） */
  -webkit-text-size-adjust: 100%;   /* 别让浏览器按自己的字号设置把按钮文字撑大 */
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

.sort-opt::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2px;
  height: 12px;
  margin-top: -6px;
  border-radius: 1px;
  background: var(--accent);  /* PrimaryBrush */
  opacity: 0;
  transform: scaleY(0);
  transition: transform .18s cubic-bezier(0, 0, .58, 1), opacity .08s;   /* EaseOut */
}

/* 悬停底色只给真有鼠标的设备：触屏上点完再取消后 :hover 粘着不消失（浅色 glass 偏白 ⇒ 按钮变白，点别处才恢复） */
@media (hover: hover) {
  .sort-opt:hover { background: var(--glass); color: var(--text); }
}

.sort-opt.on {
  background: var(--accent-soft);
  font-weight: 700;
}
/* 选中态不叠加悬停玻璃（与 XAML 里 selBg 盖住 hoverBg 的顺序一致） */
.sort-opt.on::before { opacity: 1; transform: scaleY(1); }

/* 通用 button 那条 :active 缩放是给主题/导入导出按钮的，排序按钮不要跟着弹 */
.sort-opt:active { transform: none; }

/* 组之间的竖分隔条：XAML 里是 1×14 的 Border，Margin="6,0,10,0" */
.sep {
  width: 1px;
  height: 14px;
  margin: 0 10px 0 6px;
  background: var(--border);
  flex: none;
}

/* 「砂糖 / 多莉」这一组（路线页头的加成、材料统计合成场景的加成共用）：
   ★ 不瞬间显示/隐藏，而是从它右边那个按钮的右缘逐渐展开、向左逐渐收起：
     收起 = max-width 0 + 透明；展开 = .open。overflow 裁掉内容，过渡才顺。 */
.who-set {
  display: flex;
  align-items: center;
  overflow: hidden;
  max-width: 0;
  opacity: 0;
  white-space: nowrap;
  transition: max-width .22s cubic-bezier(.22, .61, .36, 1), opacity .18s ease;
}
.who-set > * { flex: none; }
.who-set.open { max-width: 190px; opacity: 1; }

/* 一行一族：与 LvchaxsBS 材料统计页同一排法
   —— 【图标|输入框】×3 → 进度条（吃掉剩余宽度）→ 百分比，整行不换行。
   ★ 行本身不加边框/背景/圆角（不要卡片感）。 */
.fam {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 6px 6px;
}

.tier { display: flex; align-items: center; gap: 1px; }

/* 一档 = 图标 +（数量框 / 底下那行今日增减小字） */
.qbox {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-right: 1px;
}

/* 材料图标本身是无背景透明图，不要加圆角（会把边角裁掉） */
.tier img { width: 32px; height: 32px; flex: none; }

/* 数量输入框：照抄 LvchaxsBS 的 QuantityBoxStyle
   —— 默认 背景透明 + 边框透明（看不出是个框），数字居中；
      只在鼠标悬停 / 正在输入时才显出边框，方便辨认点到哪了。
   ★ 窄框：省下来的横向空间全部让给右侧进度条。
   ★ 字号 / 字重 / 字体族与右侧百分比完全一致（.pct），
     不加粗 —— 加粗会让同样 12px 的数字看起来比百分比大一圈。 */
.tier input[type="number"] {
  width: 52px;
  padding: 1px 4px;
  text-align: center;
  font-family: inherit;
  font-size: 12px;
  font-weight: 400;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
}
.tier input[type="number"]:focus {
  outline: none;
  background: var(--hover);
  border-color: var(--bar-b);
}

/* 查看别人的材料：数量只读 —— 外观不变，但点不进去也滚不动，
   免得弹出输入法或者误以为能改（数据本来也不会写出去） */
.tier input[type="number"][readonly] {
  pointer-events: none;
  caret-color: transparent;
}

/* 数量为 0 时框里那个 0 是 placeholder 水印，**不是真值**：
   敲第一个数字它自动让位（不用先删 0），与 LvchaxsBS 的 Opacity=0.4 弱化观感对齐。
   ⛔ 千万别把它写成 value="0" —— 那是真值，点进去还得手动删。 */
.tier input[type="number"]::placeholder,
.tier input[type="number"]::-webkit-input-placeholder {
  color: var(--text-2);
  opacity: .4;
}

/* 数量框下面那行「今日增减」：多了绿、少了红、没变化留空占位。
   ★ 用 visibility:hidden（不是 display:none）—— 照抄 XAML 用 Hidden 而非 Collapsed 的做法，
     52 行的高度才不会一跳一跳；字号/字重同 DeltaTextStyle（10 / SemiBold）。 */
/* 数量下面的增减小数字：
   ★ 左右留等宽的空白，符号挂进左边那块空白（absolute，不占布局）
     ⇒ 数字本身永远压在输入框数字的同一条中轴线上，不会被「+/-」顶偏。 */
.dl {
  position: relative;
  padding: 0 .5em;
  height: 9px;
  line-height: 9px;
  font-size: 9px;
  font-weight: 600;
  white-space: nowrap;
  visibility: hidden;
}
.dl .sgn {
  position: absolute;
  left: 0;
  font-style: normal;
}
.dl.up { color: var(--good); visibility: visible; }
.dl.down { color: var(--bad); visibility: visible; }

/* 百分比 + 底下那行增减百分比：两行右对齐贴在一起 */
.pwrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  flex: none;
}

/* 百分比：只是个数字，不是按钮（本工具只记录数量） */
.pct {
  width: 56px;   /* 要放得下 2 位小数的「100.00%」 */
  text-align: right;
  font-size: 12px;
  color: var(--text-2);
  flex: none;
  padding: 0 4px;
}

/* 增减百分比（+3.20% / -1.50%）：与左边的小数字落在同一条水平线上 */
.dp {
  width: 56px;
  text-align: right;
  padding: 0 4px;
  height: 9px;
  line-height: 9px;
  font-size: 9px;
  font-weight: 600;
  white-space: nowrap;
  visibility: hidden;
}
.dp.up { color: var(--good); visibility: visible; }
.dp.down { color: var(--bad); visibility: visible; }

/* 「期望」时代的小字已废弃（盈亏改到分析页；合成数字走下面的 craft-info 展开区） */

/* ================= 合成信息展开区（点「合成」按钮时展开） =================
   每行 = famwrap{ fam(主行) + craft-info }；craft-info 用 grid 0fr→1fr 做平滑展开。
   三行内容：毕业 / 配平 / 溢出。标签压在第一列图标下面，
   数字与中/高两档输入框对齐（.ccol 复刻 .tier 的 图标宽+输入框宽），低档是原料没有数字。 */
.famwrap { min-width: 0; contain: layout style; }   /* 隔离每一行的重排：一行撑开不再触发整张列表重排，移动端展开更顺 */

/* 合成展开：grid 0fr→1fr 平滑撑开（改回最初的展开效果；移动端不像 max-height 那样逐帧重排卡顿）。 */
.craft-info {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .28s cubic-bezier(0, 0, .58, 1);
}
.craft-in {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  padding: 0 3px;   /* 与 .fam 左右 padding 一致，标签/数字才能对到图标/输入框正下方 */
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;   /* 窄屏放不下时，就地合成那组自动落到下一行（占满整宽） */
}
.crows { display: flex; flex-direction: column; flex: none; align-items: flex-start; }
#list.syn .craft-info { grid-template-rows: 1fr; }
#list.syn .craft-in { opacity: 1; }
/* 只在展开/收起的 320ms 内提示浏览器单独优化网格行高插值（结束即移除，避免常驻几十个图层拖垮移动端内存） */
#list.animating .craft-info { will-change: grid-template-rows; }

.crow { display: flex; align-items: center; height: 16px; }

/* ================= 就地合成（「毕业/配平/溢出」右侧的空白格，配平行） =================
   「合成高阶 / 合成中阶」两个按钮，口径与暗月计算器的「合成」按钮完全一致：
   中阶 = 3 低 → 1 中，高阶 = 3 中 → 1 高；点击弹出数量输入，「1000 100」的第二段是砂糖/多莉的额外产出。 */
.craft-act { display: flex; align-items: center; gap: 4px; margin-left: 2px; }
.craft-do {
  height: 20px;
  padding: 0 8px;
  font-family: inherit;
  font-size: 11px;
  color: var(--text-2);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  white-space: nowrap;
}
.craft-do:hover { color: var(--text); background: var(--hover); }
.craft-do:active { transform: translateY(1px); }
.craft-do[disabled] { opacity: .45; cursor: default; }
/* 每列 = 图标槽 + 数字槽，宽度/间距与主行 .tier 一致（基础档 32 图标 + 48 输入框） */
.ccol { display: flex; align-items: center; flex: none; margin-right: 3px; gap: 1px; }
.clabel, .cskip { width: 32px; flex: none; }
.clabel { text-align: center; font-size: 9.5px; color: var(--text-2); }
.cnum, .cskip2 { width: 48px; flex: none; text-align: center; }
.cnum { font-size: 12px; font-family: inherit; font-weight: 400; }
.cnum.grad, .cnum.bal { color: var(--good); }
.cnum.ov { color: var(--bad); }
.cnum.zero { color: var(--text-2); opacity: .45; }

.bar {
  flex: 1 1 80px;
  min-width: 60px;
  height: 6px;
  border-radius: 3px;
  background: var(--track);
  overflow: hidden;
}

.bar > i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--bar-a), var(--bar-b));
  transition: width .2s ease;
}

.chip {
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 20;
  background: var(--bar-b);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 9px 16px;
  font-size: 13px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
  cursor: pointer;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 30;
  background: rgba(0, 0, 0, .82);
  color: #fff;
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 13px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.toast.show { opacity: 1; }

/* ================= 卡片 / 通用小件（每日锄地、路线管理、分析总结共用） ================= */
.card {
  margin: 10px 14px 0;
  padding: 12px 14px 14px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}

.muted { font-size: 11px; font-weight: 400; color: var(--text-2); }

.tag {
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 10px;
  font-weight: 600;
  background: var(--accent-soft);
  color: var(--accent);
}

/* ---- 分析总结的日期切换（照主程序：◀ 日期 ▶，点日期弹月历） ---- */
.day-arrow {
  width: 22px;
  height: 22px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: var(--text-2);
  cursor: pointer;
}
.day-arrow:disabled { opacity: .3; cursor: default; }
.day-pick:active { transform: none; }   /* 点它直接弹月历，不要像普通按钮那样按一下放大 */

/* 月历弹窗：有记录的日子正常色可点，没记录的压淡且点不动；
   位置贴着日期按钮右下，右对齐（日期按钮本来就在卡片右上角） */
.cal-head { display: flex; align-items: center; }
.cal-week, .cal-days { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal-week span { text-align: center; font-size: 10.5px; color: var(--text-2); }
.cal-day {
  height: 28px;
  padding: 0;
  font-family: inherit;
  font-size: 12px;
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}
.cal-day.on { background: var(--accent-soft); color: var(--accent); font-weight: 700; }

/* ---- 今日进度（精英 400 / 小怪 2000，一人一行） ---- */
.pv-line { display: flex; align-items: baseline; justify-content: space-between; }
.pv-num { font-size: 12px; font-weight: 600; }
.bar.big { height: 6px; }

/* ---- 页面头（路线列表标题 + 添加按钮） ---- */
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px 2px;
}
.page-title { font-size: 13px; color: var(--text-2); }

/* 路线管理页头：标题 + 添加按钮 + 期望口径切换，一起装进卡片
   （内边距归卡片管，里面的 .page-head 不再自己撑边） */
/* 路线管理页头只有一行：两组二选一靠左，「+ 添加路线」贴右 */
.route-head { padding: 9px 12px 10px; }
.route-head .btn-add { margin-left: auto; flex: none; }
/* 编辑页头：同一张卡片里「标题在左、返回按钮在右」，按钮右缘与列表页的「添加路线」对齐 */
.head-row { display: flex; align-items: center; gap: 8px; }
.head-row .btn-back { margin-left: auto; flex: none; }
/* 编辑页头：切换栏里返回按钮贴右，和列表页的「+ 添加路线」同一位置（两页高度一致） */
.route-head .btn-back { margin-left: auto; flex: none; }

.btn-add {
  height: 26px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
}

/* ---- 每日锄地：一条路线一行（上排名称/标签/累计，下排三个计数器） ---- */

/* 中间那条提示卡（占满整行）：虚线框，内容说明「把下面的路线移上来才能分配怪量」；
   ★ 它是 .farm-row 的一员 ⇒ 拖动排序时占一个槽位，拖动越过它就等于移出 / 移入上方区域 */
/* 拖动时：能拖到它上面跨区 ⇒ 蓝框；拖的这条已经分配了车数、不能再移回列表 ⇒ 红框 */
.farm-row.farm-hint.drag-no { border-color: var(--bad); color: var(--bad); }
/* 跨区拖动松手：被拖的卡先在当前位置淡出，表示“已经移走/移入” */
.farm-hint-text { min-width: 0; }
.farm-row.farm-hint[aria-expanded="true"] .farm-hint-chev { transform: rotate(180deg); }

/* 「其他路线」里的卡片：内容照常显示（含加减），只是按钮点不动 */
.counters.locked button { cursor: default; }

/* 一键移出 / 移入：无文字，只有箭头
   （在「其他路线」里朝上 = 移到上方；在上方朝下 = 移回列表） */
/* 已分配今日怪量的路线不能移回列表 ⇒ 箭头置灰 */
.farm-move svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.farm-top { display: flex; align-items: center; gap: 6px; min-width: 0; }
/* 名称优先占位：最多半行宽，再长就省略号；材料图标不许把它挤没 */
/* 每日锄地里「路线已被删掉、但那天还留着记录」的那一行：只加一个小标签，没有排序手柄 */
/* 材料图标条：占名称剩下的宽度，装不下就横向滑动查看（不换行、不压缩、不挤名称） */
.farm-mats::-webkit-scrollbar { display: none; }
/* 一枚材料 = 图标 + 底下一行小字：这套材料现在的进度 */
.farm-mats img { width: 18px; height: 18px; }

/* 卡片右上角的排序手柄：照主程序 SortHandleButtonStyle 的形状 —— 20×20 点击区、14px 图标、
   纵向居中、往卡片右缘靠；静止偏淡，悬停 100ms 放到 1.2 倍并提亮 */
.sort-handle {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0 -5px 0 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 4px;
  color: var(--text-2);
  opacity: .55;
  cursor: grab;
  touch-action: pan-y;           /* 按住手柄上下滑仍然滚页面（不会误触发排序），进入拖动后由 JS 拦 touchmove */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  transition: transform .1s cubic-bezier(.215,.61,.355,1), opacity .1s;
}
/* 只在真能悬停的设备上放大提亮：触屏拖完手指抬起来后 :hover 会一直挂着，看起来像卡在高亮态 */
@media (hover: hover) {
  .sort-handle:hover { opacity: 1; transform: scale(1.2); }
}
/* 全局 button:hover 会铺一层 --hover 底色，手柄不要：悬停 / 按下都保持透明 */
.sort-handle:hover, .sort-handle:active { background: transparent; }
.sort-ico { width: 14px; height: 14px; display: block; overflow: visible; }

/* 拖动中：被拖的卡保持原样、浮在其它卡上面，整页光标变抓 */
.sorting { position: relative; z-index: 100; user-select: none; -webkit-user-select: none; }
body.sorting { cursor: grabbing; }

.counters { display: flex; gap: 10px; margin-top: 8px; }
.counter { flex: 1 1 0; display: flex; align-items: center; justify-content: space-between; gap: 2px; }
.counter-label { font-size: 11px; color: var(--text-2); flex: none; }
.counter-val { min-width: 18px; text-align: center; font-size: 13px; font-weight: 600; }
.counter-val.zero { color: var(--text-2); opacity: .55; }

/* −1 / +1：与 FlatButtonStyleRound6 同一观感（小、无边框、悬停才显底） */
.counter button {
  width: 26px;
  height: 22px;
  padding: 0;
  font-family: inherit;
  font-size: 10px;
  line-height: 1;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 6px;
}
.counter button:active { transform: none; }

/* ---- 路线管理：列表卡片 ---- */
.route-row {
  margin: 8px 14px 0;
  padding: 9px 12px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
}
/* 长按到位、现在可以拖了：卡片边框换成荧光蓝实线提示
   ★ 必须写在 .route-row / .farm-row 之后（它们用 border 简写会把边框色和线型重置回实线灰）；
   ★ 只改颜色、不动宽度和线型：边框本来就是 1px solid，换色 ⇒ 卡片尺寸、内容、相邻卡片位置都不变 */
.route-row.drag-armed, .farm-row.drag-armed {
  border-color: #00AEFF;
}

.route-top { position: relative; display: flex; align-items: center; gap: 6px; min-width: 0; }
.route-name {
  font-size: 13.5px;
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.route-count { margin-left: auto; font-size: 11px; color: var(--text-2); flex: none; }

/* 卡片上的编辑 / 删除：照主程序 IconEditButtonStyle（铅笔 + 底下一条短横）/
   IconDeleteButtonStyle（垃圾桶）—— 16px 见方、无边框、悬停放大 1.15 倍 */
.icon-btn {
  flex: none;
  width: 22px;
  height: 22px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 5px;
  color: var(--text-2);
  transition: transform .12s ease, color .12s ease;
}
/* 全局 button:hover 会铺一层 --hover 底色（style.css 顶部的 button 规则），
   卡片上的图标按钮一律不要底色：静止 / 悬停 / 按下都保持透明 */
.icon-btn, .icon-btn:hover, .icon-btn:active { background: transparent; }
.icon-btn svg { width: 15px; height: 15px; display: block; }
.icon-btn.del { color: var(--bad); }
.icon-btn:active { transform: scale(1); }
/* 路线卡片的编辑按钮：静止偏淡（半透明没那么抢眼），可悬停设备上悬停恢复不透明 */
.icon-btn.edit { opacity: .4; transition: transform .12s ease, color .12s ease, opacity .12s ease; }
@media (hover: hover) {
  .icon-btn.edit:hover { opacity: 1; }
}
/* 路线卡片合并/展开按钮：绝对定位在排序手柄正下方，与手柄同一竖列。
   尺寸取 20×20（与手柄同宽）、图标 14px（与手柄同尺寸）⇒ 两者图标中心落在同一条竖线上；
   颜色与透明度固定成手柄的静止态（--text-2 + .55），悬停 / 按下都不改色、不铺底色。 */
.icon-btn.collapse {
  position: absolute;
  top: calc(100% + 10px);  /* 紧贴 route-top 下方、垂直居中于材料第一行（第一行中心距 route-top 底 20px，按钮 20 高 ⇒ 10px） */
  right: -5px;             /* 与手柄 margin-right:-5px 同理，右缘一起外溢 5px ⇒ 同一列、同一条竖线 */
  width: 20px;
  height: 20px;
  z-index: 5;
  color: var(--text-2);
  opacity: .55;
  background: transparent;
}
.icon-btn.collapse svg { width: 14px; height: 14px; }
/* 按下时不缩回：hover 已放大 1.15，若沿用全局 .icon-btn:active 的 scale(1)，
   点一下会「缩一下再弹回来」，就是肉眼可见的回弹。保持同一倍率即无回弹 */
.icon-btn.collapse:active { transform: scale(1.15); }
.icon-btn.collapse:active { color: var(--text-2); background: transparent; }
.icon-btn.collapse .chev { transition: transform .18s cubic-bezier(.215,.61,.355,1); }
.icon-btn.collapse:not(.collapsed) .chev { transform: rotate(180deg); }

/* 路线卡片的展开 / 合并内容：两块都常驻 DOM，切 .collapsed 时用 grid 行高 0fr ⇄ 1fr 过渡。
   用 grid 而不用 max-height —— max-height 是「数值」插值，上限（2000px）远大于真实高度，
   数值在过渡早期就冲过真实高度，观感是「弹一下就不动了」；0fr→1fr 插值的是真实高度，全程匀速顺滑。
   · .expanded-part = 每材料一行的数量明细      · .collapsed-part = 一行横排图标 */
.route-body { margin-top: 8px; }
.expanded-part, .collapsed-part {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;          /* 收到 0 时把内容裁干净（放在容器上，内层 .collapse-scroll 的横向滑动不受影响） */
  opacity: 0;
  /* 慢入慢出、无过冲的曲线：之前 cubic-bezier(0,0,.58,1) 起步极快、尾巴拖长，
     观感像「弹一下再停」；这里改成材质标准曲线，全程匀称。透明度与高度同时长，避免内容先闪出来 */
  transition: grid-template-rows .28s cubic-bezier(.4, 0, .2, 1), opacity .28s cubic-bezier(.4, 0, .2, 1);
}
/* 子项必须 min-height:0，grid 行高才压得到 0 */
.expanded-part > *, .collapsed-part > * { min-height: 0; }
/* 桌面选敌底栏也走这同一套：给它同样的两块 DOM 与 .collapsed 状态即可，
   过渡时长、opacity 互换、只切 class 不重绘都跟路线卡片完全一样。 */
.route-row:not(.collapsed) .expanded-part,
#rt-picker-inline:not(.collapsed) .expanded-part { grid-template-rows: 1fr; opacity: 1; }
.route-row:not(.collapsed) .collapsed-part,
#rt-picker-inline:not(.collapsed) .collapsed-part { grid-template-rows: 0fr; opacity: 0; }
.route-row.collapsed .expanded-part,
#rt-picker-inline.collapsed .expanded-part { grid-template-rows: 0fr; opacity: 0; }
.route-row.collapsed .collapsed-part,
#rt-picker-inline.collapsed .collapsed-part { grid-template-rows: 1fr; opacity: 1; }

/* 合并后的图标行：一行横排（每个材料取最高品质图标），放不下横向滑动（照每日锄地 .farm-mats）；
   右侧 28px 给合并按钮让位（只占水平空间，折叠时不影响高度） */
.collapsed-part { padding-right: 28px; }
.collapse-scroll {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 0;            /* 上下 3px ⇒ 与普通单行 drop-row 同高，合并卡片高度不变 */
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.collapse-scroll::-webkit-scrollbar { display: none; }
.collapse-scroll .ci { width: 18px; height: 18px; flex: none; }

/* 掉落明细：一套材料一行 = 三档材料图标 + 每车期望数量（品质高的在左，同主程序卡片）
   同族的多个变体（大/小、丘丘暴徒+丘丘王…）在数据上合并成一行，所以行里只有图标和数字 */
.drop-rows { margin-top: 8px; }
.drop-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: center;
  gap: 6px;
  padding: 3px 28px 3px 0;    /* 右侧留 28px 给合并/展开按钮，所有行统一 ⇒ 材料列对齐不被挤歪 */
  font-size: 10.5px;
  color: var(--text-2);
}
.drop-row + .drop-row { border-top: 1px solid var(--border); }
/* 附带掉落（路线里没有怪把它当主材料）只把期望数字压淡，图标保持原样：
   一眼能看出这数量是别的怪顺带来的 */
.drop-row.extra .drop-cell b { opacity: .45; }
.drop-cell { display: flex; align-items: center; gap: 4px; min-width: 0; }
.drop-cell img { width: 18px; height: 18px; flex: none; }
.drop-cell b {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ---- 毕业期望：一行只留最高品质那一个图标（三档已折成同一份等效进度）；
        后面三列走 grid 定宽轨道 ⇒ 跨行同一列必然对齐：
        图标 ｜ 当前 X% ｜ 每车 +Y ｜ 剩余车数 N（三列都靠左，起始位置固定；
        末列用 minmax(0,1fr) 保证窄屏能压缩，但文字左对齐 ⇒ 起点始终固定） ---- */
.drop-row.grad {
  display: grid;
  grid-template-columns: auto 7.2em 7.8em minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}
.drop-row.grad .drop-cell { gap: 0; }
.grad-num, .grad-per, .grad-trip {
  font-weight: 600;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.grad-num { color: var(--text); }
.grad-per { color: var(--text-2); }
.grad-trip { color: var(--text-2); }   /* 和「每车 +Y%」同一档次要色，不抢「当前X%」的主色 */
/* 附带掉落同样压淡（与掉落模式里 b 的 45% 一致） */
.drop-row.extra .grad-num,
.drop-row.extra .grad-per,
.drop-row.extra .grad-trip { opacity: .45; }

/* ---- 每车材料容器底部：当前材料数量（高/中/低 三档各带一个输入框，可就地修改） ----
   每个被这条路线掉落的族占一格：三个档位图标 + 三个输入框；
   一行能排几个就排几个（grid 按可用宽度自适应换行，不写死列数） */
.route-progress {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.rp-title { font-size: 11px; color: var(--text-2); margin-bottom: 6px; }
/* 每个材料族是一个独立的分组块（浅底 + 细边 + 圆角），块内是紧凑的高/中/低三档
   图标 + 数量输入框；块与块之间留空隙，一眼能分清哪三个图标属于同一个材料。 */
.rp-grid { display: flex; flex-wrap: wrap; gap: 10px 12px; }
.rp-item {
  display: flex; align-items: center; gap: 4px; min-width: 0;
  padding: 3px 4px;
  background: rgba(128, 128, 128, .05);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.rp-tier { display: flex; align-items: center; gap: 3px; flex: 0 0 auto; min-width: 0; }
/* 图标尺寸与「每车材料」里的材料图标一致（18px） */
.rp-tier img { width: 18px; height: 18px; flex: none; }
/* 数量输入框：照抄导航「材料一览」的做法 —— 默认背景透明 + 边框透明（看不出是个框，
   数字像纯文本），只在鼠标悬停 / 正在输入时才显出边框，方便辨认点到哪了。
   固定 44px 宽 ⇒ 四位数字（最大 9999）也完整显示，不再只露 3 位。 */
.rp-tier input {
  width: 44px; flex: none; box-sizing: border-box;
  height: 22px; padding: 0 3px;
  text-align: center;
  font-family: inherit; font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
}
.rp-tier input:hover { border-color: var(--border); }
.rp-tier input:focus { outline: none; background: var(--hover); border-color: var(--bar-b); }

/* ---- 编辑路线（整页占用：列表整块让位，靠右上角「‹ 路线列表」回去） ---- */
/* 头部直接复用 .page-head（标题左、按钮右），窄屏的内边距也跟着一起走 */
.btn-back {
  height: 26px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.field { display: block; margin-top: 12px; }
.field-label { display: block; font-size: 11.5px; color: var(--text-2); margin-bottom: 5px; }

.field input[type="text"],
.field input[type="password"] {
  width: 100%;
  height: 30px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 13px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
}

/* 路线名称 + 删除：删除固定在输入框右侧那一格，新建路线时隐藏 */
.name-row { display: flex; align-items: center; gap: 8px; }
.name-row input[type="text"] { flex: 1 1 auto; min-width: 0; }
.name-row .icon-btn { width: 30px; height: 30px; }

/* 编辑器里的一只怪：外面套一层展开壳（.mon-wrap），新增 / 删除时用 grid 行高 0fr ⇄ 1fr 过渡。
   和路线卡片同一套做法：0fr→1fr 插值的是真实高度，展开结束停在内容高上，不会像 height 动画
   那样因为取整 / 行高重排而在结尾「再缩一下」。
   .mon-clip 必须 min-height:0，行高才压得到 0；overflow:hidden 把内容裁干净。 */
.mon-wrap {
  display: grid;
  grid-template-rows: 0fr;
  align-self: start;             /* 在 #rt-monsters 的 grid 里不被行高拉高，收起才真的收下去 */
  transition: grid-template-rows .28s cubic-bezier(.4, 0, .2, 1);
}
.mon-wrap.open { grid-template-rows: 1fr; }
.mon-wrap > .mon-clip { min-height: 0; overflow: hidden; }

/* 编辑器里的一只怪：图标 + 三个等级数量。
   一行一只怪，行间用 1px 分割线分隔（与「每车材料」掉落行的 divider 同款），
   不再用卡片底色 + 间距 —— 这样敌人数量列表和每车材料视觉一致。 */
.mon-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
}
#rt-monsters .mon-wrap + .mon-wrap > .mon-clip > .mon-box {
  border-top: 1px solid var(--border);
}
.mon-box > img { width: 30px; height: 30px; flex: none; }
/* 怪物名 + 三个等级数量：名字一行、输入框一行，窄屏也不会把名字挤没 */
.mon-info { flex: 1 1 auto; min-width: 0; }
.mon-name {
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mon-lvs { display: flex; gap: 6px; margin-top: 4px; }
.mon-lv { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.mon-lv span { font-size: 9.5px; color: var(--text-2); }
.mon-lv input {
  width: 48px;
  height: 24px;
  padding: 0 2px;
  text-align: center;
  font-family: inherit;
  font-size: 12px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 5px;
}
.mon-del {
  margin-left: auto;
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 12px;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 6px;
  flex: none;
}
.mon-del:active { transform: none; }

/* 单只怪自己的掉落期望：与「每车材料」同款三档图标 + 数字，
   区别只是这里只算这一只怪，右侧卡片是全部怪按族合计后的结果。
   桌面端跟在等级输入框那一行末尾；那一行放不下完整三档时，
   整块自动换到输入框下面一行（见文件末尾 1100 断点）。移动端隐藏。 */
.mon-drops {
  display: none;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.mon-drop-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(6px, .5vw, 12px);
}
.mon-drop-row + .mon-drop-row { border-top: 1px solid var(--border); padding-top: 2px; }
.mon-drop-row .drop-cell { gap: 3px; }
.mon-drop-row .drop-cell img {
  width: clamp(24px, 1.4vw, 28px);
  height: clamp(24px, 1.4vw, 28px);
}
.mon-drop-row .drop-cell b {
  font-size: clamp(9px, .55vw, 12px);
  font-weight: 500;
  overflow: hidden;
  text-overflow: clip;
}
.mon-drop-row.extra .drop-cell b { opacity: .45; }

.btn-dashed {
  width: 100%;
  height: 30px;
  margin-top: 8px;
  font-family: inherit;
  font-size: 12px;
  color: var(--text-2);
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: 8px;
}

.editor-actions { display: flex; gap: 8px; margin-top: 14px; }
.editor-actions button {
  flex: 1 1 0;
  height: 32px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 7px;
  border: 1px solid var(--border);
}
.btn-primary { color: #fff; background: var(--accent); border-color: transparent; }
.btn-plain { color: var(--text-2); background: transparent; }
/* 编辑器「保存」：不用蓝底（中性卡底 + 正文色），只在新建路线时出现 */
.btn-save { color: var(--text); background: var(--card); }
/* 编辑器「删除路线」：和保存同款中性底，红色字（只在编辑已有路线时出现） */
.btn-del-route { color: var(--bad); background: var(--card); }

/* ---- 选材料面板 ---- */
.picker {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-end;
  background: rgba(0, 0, 0, .42);
}
.picker-panel {
  width: 100%;
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  padding: 12px 14px 14px;
  background: var(--card);
  border-radius: 14px 14px 0 0;
}
.picker-close {
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 13px;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 6px;
}
.picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  gap: 6px;
  margin-top: 10px;
  overflow-y: auto;
}
.picker-cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 1px;
  padding: 4px 2px 3px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
}
.picker-cell { width: 100%; }
.picker-cell img { width: 34px; height: 34px; }
/* ---- 常驻的选敌人区：编辑路线时出现在 2/3 列表下面 ---- */
.picker-inline {
  margin-top: 16px;
  padding: 16px 18px 18px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
}
.picker-inline-head {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;          /* 窄屏放不下时按钮整体换到下一行 */
  margin-bottom: 12px;
}
#rt-picker-inline #picker-title { font-size: 16px; font-weight: 700; }
/* 敌人按钮跟标题同一行：紧跟在标题后面横向排，不独占一行 */
.picker-inline #picker-variants { margin-bottom: 0; }
.picker-inline .picker-chips { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 10px; margin-top: 0; }
.picker-inline .chip-mon {
  padding: 8px 18px;
  font-size: 15px;
  line-height: 24px;
  color: var(--text);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.picker-inline .chip-mon.on {
  background: var(--accent-soft);
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}
.picker-inline .picker-grid { margin-top: 0; }

/* 移动端：选敌人还是老样子 —— 编辑区里点「添加敌人」，从底部弹出面板；
   桌面（≥1100px）才是常驻在列表下面的底栏，这里把它彻底藏掉。 */
@media (max-width: 1099px) {
  #rt-picker-inline { display: none; }
  /* 展开 / 合并只属于桌面常驻底栏，移动端底部弹层不显示 */
  #rt-picker-inline .picker-collapse { display: none; }
  #rt-picker-inline.sheet-open {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 41;
    max-height: 74vh;
    margin: 0;
    padding: 14px 14px 16px;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 28px rgba(0, 0, 0, .2);
    animation: sheetUp .26s cubic-bezier(.4, 0, .2, 1);
  }
  /* 多选时的具体敌人按钮排在图标墙下面（面板底部），和老版弹层一致：
     标题行不生成盒子，让标题 / 图标墙 / 选项直接排成弹层的一列，再用 order 定顺序。
     桌面端不受影响，选项仍在标题同一行右侧。 */
  #rt-picker-inline.sheet-open .picker-inline-head { display: contents; }
  /* 弹层里不参与展开 / 合并：展开块打平成 contents，让 #picker-grid 仍按老规则
     直接排在图标墙那一层；合并块整个不显示。 */
  #rt-picker-inline .picker-expanded,
  #rt-picker-inline.collapsed .picker-expanded { display: contents; opacity: 1; overflow: visible; }
  #rt-picker-inline .picker-collapsed { display: none; }
  #rt-picker-inline.sheet-open .picker-head-left {
    order: 0;
    flex: 0 0 auto;
    margin: 0 0 10px;
    padding-right: 36px;   /* 右上角 ✕ 的位置 */
  }
  #rt-picker-inline.sheet-open #picker-variants {
    order: 2;
    flex: 0 0 auto;
    margin-top: 12px;
  }
  /* 老版弹层的敌人胶囊是 12px 小按钮；桌面底栏那套 15px / 8×18 只在桌面用。
     选中态的淡蓝底由 .picker-inline .chip-mon.on 管，这里只改未选中的底色。 */
  #rt-picker-inline.sheet-open .picker-chips { gap: 6px; margin-top: 0; }
  #rt-picker-inline.sheet-open .chip-mon {
    padding: 5px 11px;
    font-size: 12px;
    line-height: normal;
  }
  #rt-picker-inline.sheet-open .chip-mon:not(.on) { background: var(--bg); }
  #rt-picker-inline.sheet-open .picker-sheet-close {
    position: absolute;
    top: 12px;
    right: 12px;
    margin: 0;
    width: 28px;
    height: 28px;
    font-size: 14px;
  }
  #rt-picker-inline.sheet-open #picker-grid {
    order: 1;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .picker-shade { position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, .42); }
}
@keyframes sheetUp {
  from { transform: translateY(100%); }
  to { transform: none; }
}
@media (min-width: 1100px) {
  #btn-add-mon { display: none !important; }
  .picker-sheet-close { display: none !important; }
  .picker-shade { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  #rt-picker-inline.sheet-open { animation: none; }
}

/* 标题 + 右侧提示：提示贴着标题后面、与标题底部对齐，比标题小、灰、半透明 */
.picker-head-left { display: flex; align-items: flex-end; gap: 10px; min-width: 0; }
.picker-tip {
  font-size: 12px;
  font-weight: 400;
  line-height: 1;
  padding-bottom: 2px;
  color: var(--text-2);
  opacity: .65;
}

/* 多选族右侧的小圆点：一个选项一个点，选中的点用边框那一档蓝 */
.pc-dots {
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.pc-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-2);
  opacity: .2;
}
.pc-dot.on { background: var(--accent); opacity: 1; }
@media (max-width: 1099px) {
  .pc-dots { right: 2px; gap: 2px; }
  .pc-dot { width: 3px; height: 3px; }
}

/* 精英族与小怪族之间的一条分界线：上面是精英、下面是小怪，不配文字 */
.picker-sep {
  grid-column: 1 / -1;
  height: 0;
  margin: 3px 0 4px;
  border-top: 1px solid var(--border);
}
.picker-cell:active { transform: none; }
/* 这一族已经有敌人被选进路线：蓝底 + 蓝边，和右侧选中按钮同一个底色 */
.picker-cell.used { background: var(--accent-soft); border-color: var(--accent); }
/* 正在挑的那一族（待选）：只描蓝边，还不是选中；蓝底 + 蓝边才是真的选上了 */
.picker-cell.active { border-color: var(--accent); }
/* 图标底下这枚小字：这套材料现在的进度（与材料统计页同一口径） */
.pc-pct {
  font-size: 9px;
  line-height: 1;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 这条路线里已经用到的材料：进度字改成强调蓝，回来加料时一眼能找到 */
.picker-cell.used .pc-pct { color: var(--accent); font-weight: 600; }

/* 第二步：掉这套材料的怪物（大/小、驮兽…各一枚胶囊） */
.picker-hint { margin-top: 10px; font-size: 11.5px; color: var(--text-2); }
.picker-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chip-mon {
  padding: 5px 11px;
  font-family: inherit;
  font-size: 12px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.chip-mon:active { transform: none; }
/* 已选中：与路线列表卡片同一套选中效果（淡底 + 蓝边 + 左侧竖条），文字保持原色 */
.chip-mon.on {
  background: var(--accent-soft);
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}

/* 面板底部两个动作按钮（同编辑器保存/取消那排的尺寸）
   两个都是中性底色；「添加其他材料」点不动的时候压成深一层的底，能点的时候与左边完全一致 */
.picker-actions { display: flex; gap: 8px; margin-top: 12px; }
.picker-actions button {
  flex: 1 1 0;
  height: 32px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 7px;
  border: 1px solid var(--border);
}
.picker-actions .btn-plain:disabled {
  color: var(--text-2);
  background: var(--bg);
  border-color: var(--border);
}

/* ---- 清除数据弹窗：沿用选材料面板的遮罩 / 面板 / 底部按钮那排，只是居中不贴底 ---- */
.clear-dlg { align-items: center; justify-content: center; padding: 14px; }
.clear-panel { max-width: 340px; border-radius: 14px; }
/* 合成数量弹窗：与清除弹窗同一套面板（居中、同宽度、同一排底部按钮） */
.craft-dlg { align-items: center; justify-content: center; padding: 14px; }
.craft-dlg .field { margin-top: 10px; }
.craft-dlg .io-note { margin: 2px 0 0; }
.clear-opts { margin-top: 4px; }
.clear-opt {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 10px 0;
  font-size: 13px;
  border-bottom: 1px solid var(--border);
}
.clear-opt:last-of-type { border-bottom: 0; }
/* 复选框：不要实心填充块 —— 勾上之后框退掉，只留一个对号。
   对号取正文色（--text），浅色主题是深灰、深色主题是浅白，两边都清楚。 */
.clear-opt input[type="checkbox"],
.io-all input[type="checkbox"],
.io-rt input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  flex: none;
  border: 1.3px solid var(--border-2);
  border-radius: 4px;
  background: none;
  cursor: pointer;
  transition: border-color .18s ease;
}
.clear-opt input[type="checkbox"]:hover,
.io-all input[type="checkbox"]:hover,
.io-rt input[type="checkbox"]:hover { border-color: var(--text-2); }
.clear-opt input[type="checkbox"]:checked,
.io-all input[type="checkbox"]:checked,
.io-rt input[type="checkbox"]:checked { border-color: transparent; }
.clear-opt input[type="checkbox"]::after,
.io-all input[type="checkbox"]::after,
.io-rt input[type="checkbox"]::after {
  content: "";
  position: absolute;
  left: 4.9px;
  top: 1.5px;
  width: 4.6px;
  height: 9px;
  border: solid var(--text);
  border-width: 0 1.8px 1.8px 0;
  opacity: 0;
  transform: rotate(42deg) scale(.35);
  transform-origin: 50% 55%;
  transition: opacity .16s ease, transform .2s cubic-bezier(.2, .9, .3, 1);
  pointer-events: none;
}
.clear-opt input[type="checkbox"]:checked::after,
.io-all input[type="checkbox"]:checked::after,
.io-rt input[type="checkbox"]:checked::after {
  opacity: 1;
  transform: rotate(42deg) scale(1);
}
.clear-opt input[type="checkbox"]:focus-visible,
.io-all input[type="checkbox"]:focus-visible,
.io-rt input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 2px;
}
.clear-opt > span { flex: 1 1 auto; min-width: 0; }
.clear-opt em {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  font-style: normal;
  line-height: 1.45;
  color: var(--text-2);
}
/* 确定清除：与「删除路线」同一套中性底 + 红字；一个分类都没勾时压灰、点不动 */
.clear-panel .btn-danger { color: var(--bad); background: var(--card); }
.clear-panel .btn-danger:disabled {
  color: var(--text-2);
  background: var(--bg);
  border-color: var(--border);
}

/* ---- 分析总结 ---- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 16px; }
.stat-num { font-size: 24px; font-weight: 700; line-height: 1.1; }
.stat-label { margin-top: 3px; font-size: 11px; color: var(--text-2); }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
.split-item { padding: 10px 12px; background: var(--hover); border-radius: 9px; }
.split-label { font-size: 12px; color: var(--text-2); }
.split-num { display: flex; align-items: baseline; gap: 1px; margin-top: 3px; white-space: nowrap; }
.split-num b { font-size: 18px; font-weight: 700; }
.split-num span { font-size: 12px; color: var(--text-2); }
/* 完成度贴在「进度条右上方」：跟在数字行末尾、靠右 */
.split-num .split-pct { margin-left: auto; padding-left: 6px; font-size: 11px; }
.split-item.elite .split-num b { color: #A055DE; }
.split-item.mob .split-num b { color: #4E7EC9; }
.split-item .bar { margin-top: 8px; }

.ana-row:last-child { border-bottom: 0; }
/* 中间的这条路线产出的材料图标：沿用每日锄地那套（图标 + 进度小字），多了可以横向滑 */
.ana-num { margin-left: auto; font-size: 11.5px; color: var(--text-2); flex: none; white-space: nowrap; }

/* 材料变化：直接照搬「材料统计」那一行 —— 三档图标 + 数量 + 增减小字 + 进度条 + 右侧百分比，
   ★ 唯一区别是数量只读（分析页不能改），左侧本来就没有怪物名。
   行本身与材料统计共用 .fam，间距/留白由上面的 #ana-mats 统一管，这里不再单独压行内边距 */
/* 头部左侧：标题 + 对比口径小字（同一行、基线对齐） */
.ana-head-l .muted { font-size: 11px; font-weight: 400; }
/* 头部右侧：增减对比 / 亏损对比 二选一 —— 复用排序条 .sort-opt 的外观
   （左侧竖杠选中指示 + 选中段 accent-soft 高亮，无连体轨道，和「升序/降序」「砂糖/多莉」一致） */
.ana-mode-btn {
  position: relative;
  height: 24px;
  padding: 0 10px 0 11px;      /* 左边 11：给左竖杠留位置，与 .sort-opt 对齐 */
  margin-right: 4px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;           /* 默认粗体：选中与否都粗，区分只靠蓝底和左竖杠 */
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 4px;          /* CornerRadius=4，同 .sort-opt */
  cursor: pointer;
  white-space: nowrap;         /* 按钮文字永不换行（窄屏靠压 padding 保一行） */
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
}
.ana-mode-btn.on::before { opacity: 1; transform: scaleY(1); }



/* 账号卡片标题行：左边昵称（太长省略），右边 UID */
.acc-nick {
  min-width: 0;
  font-size: 14px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- 导入 / 导出 ----
   两块：材料数量（一键带走）、路线（勾选哪几条走）。
   载体二选一：短码 / JSON 文件，按钮沿用排序按钮那套外观。 */
.io-fmt { display: flex; align-items: center; gap: 6px; margin: 10px 0 0; }

.io-block { margin-top: 14px; }
.io-block-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.io-title { font-size: 12.5px; color: var(--text-2); }

/* 账号同步状态：一行一条，左标签右数值 */
.sync-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  font-size: 11.5px;
}

/* 改密码：展开在原卡片里，和上面几段同一套留白 */
.acc-pass-box { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }

/* 导出按钮：虚线 + 透明底 + 灰字太弱，几乎看不出是按钮；
   这里改成实线描边 + 浅底 + 正文色，保持中性配色，不引入语义色 */
.io-block .btn-dashed {
  color: var(--text);
  background: var(--track);
  border: 1px solid var(--border-2);
}
.io-block .btn-dashed:active { filter: brightness(.96); }

/* 全选：复选框 + 小字，整块可点 */
.io-all { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--text-2); }
.io-all input { margin: 0; }

/* 一条路线：勾选框 + 名字 + 右侧「N 只/车」 */
.io-rt {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 0;
  font-size: 13px;
  border-bottom: 1px solid var(--border);
}
.io-rt:last-of-type { border-bottom: 0; }
.io-rt-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.io-rt-num { flex: none; font-size: 11px; color: var(--text-2); }

/* 短码 / 粘贴框：等宽字体，长串能整段看到、能选中复制 */
#io-out,
#io-in {
  width: 100%;
  padding: 8px 10px;
  font-family: ui-monospace, Consolas, "Courier New", monospace;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 7px;
  resize: vertical;
  word-break: break-all;
}
#io-out { color: var(--text-2); }

.io-note { margin-top: 10px; font-size: 11px; line-height: 1.5; color: var(--text-2); }

/* 空状态：还没建路线 / 今天还没打 */
.empty-tip {
  margin: 10px 14px 0;
  padding: 26px 14px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-2);
  background: var(--card);
  border: 1px dashed var(--border);
  border-radius: 10px;
}

/* 窄屏：整行仍然不换行（进度条照旧跟在第三个输入框后面），只把各元素同步收窄 */
@media (max-width: 480px) {
  main { padding: 0 0 20px; }
  .ana-head { padding: 14px 14px 2px; }
  /* 排序条与列表的左右边距对齐导航按钮的内容边距（顶栏 4px + 导航按钮左内边距 3px = 7px），留一点不贴边 */
  #list { padding: 4px 7px 6px; }
  .page > .sort-bar { padding: 8px 7px 6px; }
  /* 顶栏：四个导航按钮在 320px 上也要一行放完，字号与留白一起压一档 */
  .topbar { padding: 3px 4px; }
  .nav-item { font-size: 11px; gap: 2px; padding: 5px 1px 4px 3px; }
  .nav-icon { width: 17px; height: 17px; }
  /* 排序按钮：字号与留白一起压紧 */
  .sort-bar { flex-wrap: nowrap; }
  /* 材料统计那排按钮：永远一行不换行（含展开的砂糖/多莉）；
     间距始终用紧凑档（不随合成展开切换，避免展开瞬间按钮收紧的顿挫感） */
  #sort-bar { flex-wrap: nowrap; }
  .sort-grp { flex-wrap: nowrap; }
  /* 排序按钮：内边距随屏宽自适应 —— 把三组铺开后剩下的横向余量几乎吃干净（留 ~10px 防换行）。
     先给一条固定紧凑值兜底：部分手机浏览器内核（如 QQ 浏览器用的 X5）不支持 clamp()/calc(vw)，
     整条自适应 padding 会被丢掉、退回桌面档 21px 内边距 ⇒ 一行放不下，「降序」和「隐藏毕业」挤到重叠 */
  .sort-opt {
    font-size: 12px;
    margin-right: 0;
    padding: 0 6px 0 7px;
  }
  .sort-opt {
    padding: 0 clamp(3px, calc(7.14vw - 18px), 11px) 0 clamp(4px, calc(7.14vw - 17px), 12px);
  }
  .sep { margin: 0 1px; }
  /* 路线管理页头：两组切换 + 添加路线要挤在一行，添加按钮也压一档 */
  .route-head { padding: 8px 8px 9px; }
  .route-head .btn-add, .route-head .btn-back { height: 24px; padding: 0 7px; font-size: 11px; }
  .fam { gap: 1px; padding: 6px 3px; }
  .tier { gap: 0; }
  .tier img { width: 32px; height: 32px; }
  /* 输入框收窄 + 字号再小一档：右边留给进度条的宽度从 ~30px 提到 ~90px */
  .qbox { margin-right: 0; }
  .tier input[type="number"] { width: 34px; padding: 0 1px; font-size: 11px; }
  /* 合成展开三行：列宽与主行 .tier 对齐（28 图标 + 34 输入框、fam gap 1px、tier gap 0） */
  .crow { height: 15px; }
  .ccol { margin-right: 1px; gap: 0; }
  .clabel, .cskip { width: 32px; }
  .cnum, .cskip2 { width: 34px; }
  .cnum { font-size: 11px; }
  .craft-in { padding: 0 3px; }
  /* 分析页的只读数字跟着输入框同宽同字号 ⇒ 两页的进度条等宽 */
  .bar { flex: 1 1 30px; min-width: 30px; }
  .pct { width: 50px; font-size: 11px; padding: 0 2px; }
  .dp { width: 50px; padding: 0 2px; }
  /* 卡片与行也跟着往两边各收 4px，和材料列表左右对齐 */
  .card, .farm-row, .route-row, .empty-tip { margin-left: 10px; margin-right: 10px; }
  .page-head { padding: 10px 10px 2px; }
  .stats { gap: 4px; }
  .stat-num { font-size: 20px; }
  .stat-label { font-size: 10px; }
  .split { gap: 8px; }
  .split-item { padding: 9px 10px; }
  .counter { gap: 0; }
  .counter-label { font-size: 10px; }
  .counter button { width: 24px; }
  .mon-lv input { width: 44px; }
}

/* 五档等级输入框在 320~359 的窄屏上再收一档，别把这一行撑出卡片
   （放在 480 断点之后：同权重靠源顺序生效） */
/* 更窄的屏幕（≤359px）排序按钮再收一档内边距，保证三个组 + 砂糖/多莉仍在一行
   （放在 480 断点之后：同权重靠源顺序生效） */
@media (max-width: 359px) {
  .mon-lvs { gap: 4px; }
  .mon-lv input { width: 40px; }
}

/* 481~560：夹在移动端（≤480）与桌面（≥760）之间的窄窗口 / 手机横屏 ——
   这一档走的是桌面样式，但 8 个按钮按桌面档内边距要 509px（再加两侧留白），放不下会溢出；
   收一档内边距与字号就够，760 以上的正常桌面不受影响 */
@media (min-width: 481px) and (max-width: 560px) {
  .page > .sort-bar { padding: 10px 10px 6px; }
  #sort-bar .sort-opt { font-size: 12px; padding: 0 7px 0 8px; }
  #sort-bar .sep { margin: 0 6px 0 4px; }
}

/* ================= 桌面端适配（≥760px 宽窗口 / 电脑浏览器） =================
   移动端布局原样保留；桌面上只做三件事：
   1. 内容整体限宽居中（880px），不再铺满整屏把按钮和文字拉散；
   2. 顶部导航从「等分铺满 + 图标文字竖排」改为「宽度自适应居中 + 横排」；
   3. 计数器一行、悬浮按钮等贴边元素跟随内容宽度，不贴屏幕边缘。 */
@media (min-width: 760px) {
  /* 导航：居中收拢，图标与文字同一行 */
  .topbar { padding: 5px 10px; }
  .topbar .nav {
    max-width: 860px;
    margin: 0 auto;
    justify-content: center;
    gap: 4px;
  }
  .nav-item {
    flex: 0 0 auto;
    flex-direction: row;
    justify-content: center;
    gap: 9px;
    /* 四项文字都是 4 个字，锁定同宽：选中时加粗不再把邻居推开（点一下整排会「抖」一下的原因） */
    min-width: 168px;
    padding: 10px 18px 10px 21px;   /* 左多 3px：给选中竖杠留位 */
    font-size: 14.5px;
  }
  .nav-icon { width: 19px; height: 19px; }
  .nav-item::before { height: 17px; margin-top: -8.5px; }

  /* 鼠标点击不放大：按钮一按体积就变、看着像整排在抖（移动端触屏保留这个反馈） */
  button:active { transform: none; }

  /* 各页内容长短不同，竖向滚动条会忽有忽无：视口一窄 15px，居中的导航就整体挪几像素。
     常驻预留滚动条槽位，切页时宽度恒定（材料统计页最长，这条主要是为它加的） */
  html { scrollbar-gutter: stable; }

  /* 内容整体限宽：所有卡片 / 列表 / 编辑器跟着居中 */
  main { max-width: 880px; margin: 0 auto; }

  /* 每日锄地：三个计数器在宽卡里会被拉得很开，限个顺眼的宽度 */
  .counters { max-width: 520px; }

  /* 右下角悬浮按钮（回到材料页顶部之类）跟内容右缘对齐，不贴屏幕边 */
  .chip { right: max(14px, calc(50% - 440px + 14px)); }

  /* 选怪面板：手机上是贴底弹层，桌面上改成居中弹窗 */
  .picker { align-items: center; justify-content: center; padding: 20px; }
  .picker-panel {
    width: 560px;            /* flex 子项里 width:100% 会缩到内容宽，桌面给固定宽 */
    max-width: 100%;
    max-height: 78vh;
    border-radius: 12px;
    border: 1px solid var(--border);
  }

  /* ---- 桌面屏大，控件与字号整体放大一档（移动端尺寸一点不动） ---- */
  body { font-size: 15px; }

  .page-head { padding: 18px 20px 6px; }
  .page-title { font-size: 16px; }
  .btn-add, .btn-back { height: 36px; padding: 0 16px; font-size: 15px; }

  .card { margin: 16px 20px 0; padding: 18px 20px 20px; border-radius: 16px; }
  .route-head { padding: 14px 18px 12px; }
  .card-head { font-size: 18.5px; }
  .muted { font-size: 13.5px; }
  .pv-name, .pv-num { font-size: 16px; }

  .farm-row, .route-row, .empty-tip { margin: 14px 20px 0; }
  .farm-row, .route-row { padding: 16px 18px 18px; border-radius: 14px; }
  .farm-name, .route-name { font-size: 18.5px; }
  .route-count { font-size: 14px; }
  .farm-mats img { width: 32px; height: 32px; }
  .drop-rows { margin-top: 12px; }
  .drop-row { font-size: 14.5px; gap: 11px; padding: 7px 28px 7px 0; }
  /* 桌面屏够宽：展开行 = 左三列「每车材料」+ 右三列「当前 / 每车 / 剩余车数」同排，
     六条等宽轨道 ⇒ 跨行每一列都对齐（手机上没有 .both，仍是两种口径二选一） */
  .drop-row.both { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  /* 两种口径桌面同排常驻 ⇒ 「每车材料 / 剩余车数」切换删掉，砂糖 / 多莉改为常驻 */
  #exp-mode [data-exp], #exp-mode-ed [data-exp] { display: none; }
  #exp-mode .who-set, #exp-mode-ed .who-set { max-width: 190px; opacity: 1; transition: none; }
  #exp-mode .who-set .sep, #exp-mode-ed .who-set .sep { display: none; }
  /* 「当前进度」与「每车 / 剩余车数」同色：右边三列整体是毕业区，与左边每车材料区分开 */
  .drop-row.both .grad-num { color: var(--text-2); }
  .route-body { margin-top: 12px; }
  .collapse-scroll { padding: 7px 0; }
  .icon-btn.collapse { width: 28px; height: 28px; top: calc(100% + 22px); }   /* 跟手柄同尺寸（28×28），垂直居中于更高的材料第一行（12 + 48/2 - 14 = 22） */
  .icon-btn.collapse svg { width: 21px; height: 21px; }
  /* 毕业期望这三列是辅助信息，桌面不跟着材料行一起放大，也不加粗 */
  .grad-num, .grad-per, .grad-trip { font-size: 12.5px; font-weight: 400; }
  /* 期望数量同理：桌面不要 600 的粗体 */
  .drop-cell b { font-weight: 400; }
  .drop-cell { gap: 9px; }
  .drop-cell img { width: 34px; height: 34px; }
  .collapse-scroll .ci { width: 34px; height: 34px; }
  .icon-btn { width: 32px; height: 32px; }
  .icon-btn svg { width: 21px; height: 21px; }
  .sort-handle { width: 28px; height: 28px; }
  .sort-ico { width: 21px; height: 21px; }

  .counters { gap: 18px; margin-top: 14px; }
  .counter-label { font-size: 14.5px; }
  .counter-val { font-size: 19px; min-width: 26px; }
  .counter button { width: 42px; height: 34px; font-size: 14px; }

  /* 材料统计：图标、输入框、进度条、百分比一起放大，进度条仍然吃掉剩余宽度
     顶部内边距压到 6px：排序条自身已有 8px 下内边距，再叠 18px 会在按钮下面空出一条明显的空行 */
  #list { padding: 6px 28px 3px; font-size: 16px; }
  .page > .sort-bar { padding: 12px 16px 8px; }
  .sort-opt { height: 28px; padding: 0 12px 0 13px; font-size: 13.5px; }
  .sep { height: 16px; }
  .fam { gap: 6px; padding: 8px 8px; }
  .tier { gap: 2px; }
  .tier img { width: 56px; height: 56px; }
  .tier input[type="number"] { width: 54px; font-size: 13px; padding: 4px 4px; }
  /* 合成展开三行（桌面）：列宽 56 图标 + 54 输入框、tier gap 2px、fam gap 6px */
  .ccol { margin-right: 6px; gap: 2px; }
  .clabel, .cskip { width: 56px; }
  .clabel { font-size: 11px; }
  .cnum, .cskip2 { width: 54px; }
  .cnum { font-size: 13px; }
  .crow { height: 20px; }
  .craft-in { padding: 0 8px; }
  .dl { font-size: 10px; height: 12px; line-height: 12px; }
  .pct { width: 64px; font-size: 13px; }
  .dp { width: 64px; height: 12px; line-height: 12px; font-size: 10px; }

  /* 进度条不跟着放大：桌面屏大也保持基础粗细，太粗反而显笨（移动端同款 6px） */
  .bar, .bar.big { height: 6px; }

  /* 编辑路线 */
  .field { margin-top: 16px; }
  .field-label { font-size: 13.5px; margin-bottom: 6px; }
  .field input[type="text"],
  .field input[type="password"] { height: 38px; font-size: 15px; }
  .name-row .icon-btn { width: 38px; height: 38px; }
  .mon-box { padding: 12px 12px; gap: 10px; border-radius: 10px; }
  .mon-box > img { width: 38px; height: 38px; }
  .mon-name { font-size: 14px; }
  .mon-lvs { gap: 8px; margin-top: 6px; }
  .mon-lv span { font-size: 11.5px; }
  .mon-lv input { width: 52px; height: 32px; font-size: 14px; }
  .mon-del { width: 32px; height: 32px; font-size: 15px; }
  .btn-dashed { height: 38px; font-size: 14px; }
  .editor-actions button, .picker-actions button { height: 40px; font-size: 15px; }

  /* 选怪面板 */
  .picker-panel { padding: 16px 18px 18px; }
  .picker-grid { grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 8px; }
  .picker-cell img { width: 38px; height: 38px; }
  .picker-close { width: 30px; height: 30px; font-size: 15px; }

  /* 分析总结 */
  .stat-num { font-size: 32px; }
  .stat-label { font-size: 13px; }
  .split-item { padding: 14px 16px; }
  .split-label { font-size: 13px; }
  .split-num .split-pct { font-size: 12.5px; }
  .split-num b { font-size: 23px; }
  .split-num span { font-size: 14px; }
  .ana-row { font-size: 15.5px; padding: 11px 0; }
  #ana-mats .qv { width: 58px; padding: 5px 6px; font-size: 13px; }

  /* 拖动排序的自动滚动按窗口算的，桌面窗口高，滚动速度也按原逻辑走，无需改 */
}

/* ================= 出现过渡 =================
   导航切页时内容区平滑淡入、材料统计切排序时列表轻淡入，
   均改用 Web Animations API 在 js/app.js 内播放（第一帧即透明、无中间态不闪烁，
   且无需强制回流，移动端大列表不卡）。prefers-reduced-motion 也在 JS 内判断关闭。 */



/* ================= 触屏彻底关闭悬停 =================
/* 触屏内核点完按钮 :hover 会一直粘着不消失（浅色底看着像变白，点别处才恢复），
   所有悬停效果一律只给真有鼠标的设备：触屏下不匹配任何 hover 规则，
   按钮/输入框/卡片在触屏上永远保持静止态外观 */
@media (hover: hover) {
  .nav-item:disabled:hover { background: transparent; color: var(--text-2); }
  .nav-item.on:hover { background: var(--accent-soft); }
  .sort-opt.on:hover { background: var(--accent-soft); }
  .tier input[type="number"]:hover {
    background: var(--hover);
    border-color: var(--border);
  }
  .chip:hover { background: var(--bar-a); }
  .day-arrow:hover:not(:disabled) { background: var(--hover); color: var(--text); }
  .cal-day:hover:not(:disabled) { background: var(--hover); }
  .btn-add:hover { background: var(--hover); }
  .farm-row.farm-hint:hover { background: var(--hover); color: var(--text); }
  .farm-move:disabled:hover { background: transparent; color: var(--text-2); }
  .counter button:hover { background: var(--hover); color: var(--text); }
  .icon-btn:hover { transform: scale(1.15); color: var(--text); }
  .icon-btn.del:hover { color: var(--bad); }
  .icon-btn.collapse:hover { transform: scale(1.15); }
  .icon-btn.collapse:hover,
  .btn-back:hover { background: var(--hover); color: var(--text); }
  .mon-del:hover { background: var(--hover); color: var(--bad); }
  .btn-dashed:hover { background: var(--hover); color: var(--text); }
  .btn-primary:hover { background: var(--accent); filter: brightness(1.06); }
  .btn-plain:hover { background: var(--hover); color: var(--text); }
  .btn-save:hover { background: var(--hover); }
  .btn-del-route:hover { background: var(--hover); }
  .picker-cell:hover { background: var(--hover); border-color: var(--border); }
  /* 已选的格子悬停时仍是蓝底蓝边，否则鼠标一放上去蓝色就没了 */
  .picker-cell.used:hover { background: var(--accent-soft); border-color: var(--accent); }
  /* 待选的格子悬停时也要保持蓝边，否则鼠标一放上去就变回灰边 */
  .picker-cell.active:hover { border-color: var(--accent); }
  #picker-chips .chip-mon:hover { background: var(--card); border-color: var(--accent); }
  #picker-chips .chip-mon.on:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--text); }
  .ana-mode-btn.on:hover { background: var(--accent-soft); }
  .io-block .btn-dashed:hover { border-color: var(--text-2); }
}
/* ================= 触屏悬停硬关闭（JS 检测打标 html.touch） ================= */
/* QQ 浏览器等触屏内核无视 hover 媒体查询：点完按钮 :hover 一直粘着不消失，
   浅色的悬停底色看着就像「变白、点别处才恢复」。不赌浏览器的标准行为，
   JS 检测到触屏后直接把悬停底色钉回各自的静止值（触屏上 hover 常驻 ⇒ 等效于悬停不存在）。
   豁免：自带非透明静止底色的按钮（蓝主按钮/保存/删除路线/悬浮chip）钉回自身底色；
   选中态(.on)的底色是选中样式，不受影响。字色的轻微粘滞不在此处理 */
html.touch button:not(.on):not(.btn-primary):not(.btn-save):not(.btn-del-route):not(.chip):not(.chip-mon):not(.used):hover {
  background: transparent;
}
/* 已选材料格与敌人按钮自带底色，触屏下也要钉回各自的底色，不能变透明 */
html.touch .picker-cell.used:hover { background: var(--accent-soft); border-color: var(--accent); }
html.touch .picker-cell.active:not(.used):hover { background: transparent; }
html.touch .chip-mon:hover { background: var(--card); }
html.touch .chip-mon.on:hover { background: var(--accent-soft); }
html.touch .btn-primary:hover { background: var(--accent); }
html.touch .btn-save:hover { background: var(--card); }
html.touch .btn-del-route:hover { background: var(--card); }
html.touch .chip:hover { background: var(--bar-b); }
html.touch button:hover { transform: none; }

/* ================= 暗月计算器（完整嵌入原作者页面） =================
   顶栏吸顶（sticky），iframe 填满剩下的视口高度，滚动交给暗月自己内部处理，
   边框由顶栏的 border-bottom 承担，不再额外画线。dvh 在地址栏收放时也撑满。 */
.darkmoon-frame {
  display: block;
  width: 100%;
  height: calc(100dvh - 55px);   /* 顶栏实测高：窄屏 55px（含 1px 下边框） */
  border: 0;
  /* 透明：页面底色只有 html::before 那一层（暗月的文档也不画自己的底色），
     iframe 里的控件直接落在这层背景上 —— 从视口最底到内容区是同一个背景面 */
  background: transparent;
  /* ★ 关键：宿主声明了 color-scheme: light dark（见 index.html 的 meta 与 :root），
     这个值会传播进 iframe，浏览器于是给 iframe 铺一块**不透明的 UA 底色**（白），
     暗月文档里再怎么写 background: transparent 都没用（实测：摘掉它全部样式表仍是纯白）。
     把 iframe 的 color-scheme 显式收窄成 light only，它就恢复真透明、直接透出宿主那层底色。
     暗月内部的下拉/输入框自己有 color-scheme: dark，不受影响。 */
  color-scheme: light only;
  /* 暗月里是渐进渲染（骨架 → 图标数字 → 主题），先整块藏着，
     等主题/列表/图标都就位再一次放出来（app.js 加 .dm-ready，另有 6s 兜底） */
  opacity: 0;
}

.darkmoon-frame.dm-ready { opacity: 1; }

@supports not (height: 100dvh) {
  .darkmoon-frame { height: calc(100vh - 55px); }
}

@media (min-width: 760px) {
  /* 桌面档顶栏变成横排图标+文字，实测高 50px */
  .darkmoon-frame { height: calc(100dvh - 50px); }
  @supports not (height: 100dvh) {
    .darkmoon-frame { height: calc(100vh - 50px); }
  }
}

/* 页面显隐只认 hidden 属性：任何给 section 写的 display 都不能把它顶掉 */
.page[hidden] { display: none !important; }

/* 停在暗月计算器页时，整页背景切成暗月那套浅色（它固定浅色主题），
   否则桌面端两侧会露出宿主的深色底，只剩中间一小块是亮的 */
/* 停在暗月计算器页时整页底色切成 #fff / #151a21（规则在文件头部 html:has(body.dm-view)::before，
   和通用底色同一个 fixed 层，切主题时一起渐变）。body 与 iframe 都保持透明 ——
   任何一处再铺底色，就会多出一层「内容区背景」，和整页背景各变各的。 */
/* 暗月页由 iframe 自己铺满，main 的 24px 下内边距会变成底部一条空白 */
body.dm-view main { padding-bottom: 0; }

/* 暗月页入场（与材料列表 flashList 同参数）：iframe 元素上的 CSS 动画由父页面合成器驱动，
   比 WAAPI 更稳（WAAPI 在部分环境下与 iframe 合成层配合会不推进） */
@keyframes dm-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.darkmoon-frame.dm-in { animation: dm-in 240ms cubic-bezier(.22, .61, .36, 1); }

/* 暗月导航按钮用绮良良表情图代替月亮矢量图（原图 340×340 透明底，按图标尺寸等比缩放） */
.nav-img { object-fit: contain; }

/* === DESKTOP-SIDEBAR-START ===
   宽屏桌面：左侧固定导航区 + 右侧铺满的内容区。
   只在 >=1100px 生效，760~1099px 仍用上面的居中桌面档，<=760px 完全保持移动端布局。
   这一段同时被单文件版 dist/MaterialCalc.html 内联，两份必须同步。 */
@media (min-width: 1100px) {
  /* 细滚动条：系统默认的纯黑条在浅色页上太扎眼，深色页上也会亮成一条白杠。
     用正文色压到低透明度、槽位透明；深浅两套同一观感，不做 hover 变色。 */
  :root { --sb-thumb: rgba(31, 36, 48, .32); }
  html[data-theme="dark"] { --sb-thumb: rgba(228, 232, 238, .32); }
  /* 滚动条：只走 ::-webkit-scrollbar（经典 10px 槽 + 圆角滑块）。
     不写 scrollbar-width / scrollbar-color —— Chrome 认了这两个标准属性就会
     抛开下面的自定义样式，改画 2px 的细线，看起来像没有滚动条。 */
  /* 用浏览器自带的细滚动条：thin 在 Chromium 下是很细的一条，
     颜色跟着主题走（浅色深灰、深色浅灰）；不写会退成 15px 的粗条。 */
  html, #route-list, #rt-preview, #rt-preview .route-body, #rt-monsters, #picker-grid {
    scrollbar-width: thin;
    scrollbar-color: var(--sb-thumb) transparent;
  }

  /* ---- 左侧导航 ---- */
  .topbar {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: 208px;
    height: 100dvh;
    padding: 0 12px 20px;
    background: var(--card);
    border-right: 1px solid var(--border);
    border-bottom: 0;
    overflow-y: auto;
  }
  .topbar::before {
    content: "Just 锄 it";
    display: block;
    padding: 26px 12px 20px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border);
    font-size: 21px;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: .4px;
    color: var(--text);
  }
  .topbar {
    display: flex;
    flex-direction: column;
  }
  .topbar .nav {
    flex: 1 1 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    max-width: none;
    margin: 0;
    justify-content: flex-start;
  }
  /* 云端同步钉在侧栏最底部 */
  .nav-item[data-page="account"] { margin-top: auto; }
  .nav-item {
    width: 100%;
    min-width: 0;
    justify-content: flex-start;
    gap: 14px;
    padding: 14px 14px 14px 20px;
    font-size: 16.5px;
    border-radius: 10px;
  }
  .nav-icon { width: 22px; height: 22px; }
  .nav-item::before { height: 26px; margin-top: -13px; left: 6px; }

  /* ---- 右侧内容区：吃掉侧栏以外的全部宽度 ----
     右边只留和左侧导航距窗口同样的 12px，不再多空一截（左边距仍是导航到内容之间那段） */
  main {
    max-width: none;
    margin: 0 0 0 208px;
    padding: 0 12px 40px clamp(28px, 3vw, 56px);
  }
  /* 内容区统一由 main 的左右内边距控边，卡片/列表不再各自叠一份留白 */
  .card, .farm-row, .route-row, .empty-tip { margin-left: 0; margin-right: 0; }
  #list { padding-left: 0; padding-right: 0; }
  .page > .sort-bar { padding-left: 0; padding-right: 0; }
  .chip { right: 28px; }

  /* ---- 桌面宽屏整体放大一档：字体、图标、输入框、按钮 ---- */
  body { font-size: 17px; }
  .card { margin-top: 20px; padding: 22px 26px 24px; border-radius: 18px; }
  .route-head { padding: 18px 22px 16px; }
  .card-head { font-size: 21px; }
  .muted { font-size: 15px; }
  .page-head { padding: 22px 0 8px; }
  .page-title { font-size: 18px; }
  .pv-name, .pv-num { font-size: 18px; }
  .farm-name, .route-name { font-size: 21px; }
  .route-count { font-size: 15.5px; }
  .farm-row, .route-row { padding: 20px 22px 22px; border-radius: 16px; }
  .farm-mats img { width: 36px; height: 36px; }
  .drop-rows { margin-top: 16px; }
  .drop-row { font-size: 16px; gap: 14px; padding: 9px 32px 9px 0; }
  .drop-cell { gap: 12px; }
  .drop-cell img { width: 40px; height: 40px; }
  .collapse-scroll .ci { width: 40px; height: 40px; }
  .icon-btn { width: 36px; height: 36px; }
  .icon-btn svg { width: 24px; height: 24px; }
  .icon-btn.collapse { width: 32px; height: 32px; top: calc(100% + 27px); }
  .icon-btn.collapse svg { width: 24px; height: 24px; }
  .sort-handle { width: 32px; height: 32px; }
  .sort-ico { width: 24px; height: 24px; }
  .grad-num, .grad-per, .grad-trip { font-size: 14px; }

  .counters { gap: 22px; margin-top: 18px; max-width: 640px; }
  .counter-label { font-size: 16px; }
  .counter-val { font-size: 22px; min-width: 30px; }
  .counter button { width: 48px; height: 38px; font-size: 16px; }

  .page > .sort-bar { padding-top: 16px; padding-bottom: 10px; }
  .sort-opt { height: 36px; padding: 0 16px 0 17px; font-size: 15.5px; }
  .sep { height: 20px; }
  .btn-add, .btn-back { height: 44px; padding: 0 20px; font-size: 16.5px; }

  #list { padding-top: 10px; font-size: 18px; }
  .fam { gap: 8px; padding: 10px 10px; }
  .tier { gap: 4px; }
  .tier img { width: 68px; height: 68px; }
  .tier input[type="number"] { width: 64px; font-size: 15px; padding: 5px 4px; }
  .ccol { margin-right: 8px; gap: 4px; }
  .clabel, .cskip { width: 68px; }
  .clabel { font-size: 12.5px; }
  .cnum, .cskip2 { width: 64px; }
  .cnum { font-size: 15px; }
  .crow { height: 24px; }
  .craft-in { padding: 0 10px; }
  .craft-do { height: 26px; font-size: 13px; padding: 0 11px; }
  .dl { font-size: 11px; height: 14px; line-height: 14px; }
  .pct { width: 78px; font-size: 15px; }
  .dp { width: 78px; height: 14px; line-height: 14px; font-size: 11px; }
  .bar, .bar.big { height: 8px; min-width: 80px; }

  .field { margin-top: 20px; }
  .field-label { font-size: 15.5px; margin-bottom: 8px; }
  .field input[type="text"],
  .field input[type="password"],
  .field textarea,
  textarea { height: auto; min-height: 46px; font-size: 17px; }
  .name-row .icon-btn { width: 44px; height: 44px; }
  /* 每行压紧一档：一行从 119px 收到 ~77px，同一屏能多显示三行再滚 */
  /* 左右内边距统一成 6px：怪物卡片右侧不再比左侧多留一截，× 按钮贴右缘、
     和「每车材料」内容贴左缘对齐，横向缝与上下缝视觉一致 */
  .mon-box { padding: 6px 6px; gap: 10px; border-radius: 10px; }
  .mon-box > img { width: 34px; height: 34px; }
  .mon-name { font-size: 14px; }
  .mon-lvs { gap: 8px; margin-top: 5px; }
  .mon-lv span { font-size: 11.5px; }
  .mon-lv input { width: 52px; height: 28px; font-size: 14px; }
  .mon-del { width: 28px; height: 28px; font-size: 15px; }
  .btn-dashed { height: 44px; font-size: 16px; }
  .editor-actions button, .picker-actions button { height: 46px; font-size: 16.5px; }
  .io-note { font-size: 14px; }
  .io-title { font-size: 17px; }
  .acc-nick { font-size: 19px; }
  input[type="checkbox"] { width: 18px; height: 18px; }

  /* 选敌人：常驻在右列底部，图标墙按可用宽度自动换行 */
  /* 左右内边距与上面的预览卡（.route-row 的 18px）对齐，两条容器的内容右边缘才在同一条线上；
     顶部不留白 —— 这一行只剩箭头 / 敌人胶囊，贴着卡片上沿即可 */
  #rt-picker-inline { padding: 0 18px 18px; }
  #rt-picker-inline #picker-title { font-size: 18px; }
  /* 格子与图标按视口宽度走：CSS 视口随浏览器缩放反向变化，用 vw 才能让
     物理尺寸在各缩放档保持一致，列数也不再在 15 / 17 / 20 之间跳。 */
  #picker-grid {
    grid-template-columns: repeat(auto-fill, minmax(clamp(40px, 2.9vw, 76px), 1fr));
    gap: clamp(5px, .42vw, 9px);
  }
  .picker-cell img {
    width: clamp(28px, 2.34vw, 60px);
    height: clamp(28px, 2.34vw, 60px);
  }
  .clear-opt > span { font-size: 17px; }
  .clear-opt em { font-size: 14px; }

  .stat-num { font-size: 36px; }
  .stat-label { font-size: 15px; }
  .split-item { padding: 18px 20px; }
  .split-label { font-size: 15px; }
  .split-num b { font-size: 26px; }
  .split-num span, .split-num .split-pct { font-size: 15px; }
  .ana-row { font-size: 17px; padding: 13px 0; }
  #ana-mats .qv { width: 68px; padding: 6px 8px; font-size: 15px; }

  /* ---- 路线配置：左列路线名导航 + 右列这条路线详情 ----
     三列（路线名 / 怪物配置 / 掉落信息）统一 20px 间隔、顶端对齐，
     每条列表按内容占高，内容多了才各自滚动。 */
  #page-route {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    column-gap: 4px;            /* 路线列表 ↔ 编辑区：四块容器统一 4px 缝 */
    align-items: stretch;
    height: 100dvh;
    /* 上下各留 4px：底栏不死贴屏幕下沿，顶部也和左右缝一致 */
    padding: 4px 0;
    /* 左列到导航右缘同样 4px：抵消 main 的 clamp(28px, 3vw, 56px) 左内边距，
       只作用于路线页，其它页面与导航区本身都不动 */
    margin-left: calc(4px - clamp(28px, 3vw, 56px));
    overflow: hidden;
  }
  #route-list-view { grid-column: 1; grid-row: 1; min-width: 0; }
  #route-editor { grid-column: 2; grid-row: 1; min-width: 0; }
  #route-list-view[hidden], #route-editor[hidden] { display: none !important; }

  /* 整页锁在视口里，三条列表各自独立滚动；只在路线页锁 body。
     路线页整屏不滚，html 那条 10px 细滚动条槽也去掉（槽是透明的，会露出页面底色，
     让右侧看着像「容器没盖满」）；其它页面滚动条保持原样 */
  html:has(#page-route:not([hidden])) { scrollbar-width: none; }
  body:has(#page-route:not([hidden])) { height: 100dvh; overflow: hidden; }
  /* 左右上下统一 4px：桌面 main 默认 padding-right:12px，会让每车材料 / 材料选择
     卡片的右缘盖不住页面底色，露出一条 --bg 竖带；这里只改路线页的右内边距 */
  main:has(#page-route:not([hidden])) { height: 100dvh; padding-bottom: 0; padding-right: 4px; }

  /* 两列页头等高、卡片内边距统一：三列内容从同一条线开始，列间不留多余空白 */
  #route-list-view > .route-head,
  #route-editor > .route-head {
    height: 64px;
    display: flex;
    align-items: center;
    padding: 0 18px;
    margin-bottom: 20px;
  }
  #route-editor > .card:not(.route-head) { padding: 18px 18px 20px; }
  #rt-preview .route-row { margin: 0; padding: 18px 18px 20px; }

  /* 滚动条槽常驻在容器右缘、内容之外（只有真正会滚的列表需要；
     #rt-preview 自己 overflow:hidden、里面 .route-body 才滚，留槽只会把可见卡片右缘
     往里推 ~10px，导致「每车材料」比底部选材料短一截 —— 所以不给它留槽）
     #rt-monsters 同理：stable 会在怪物列表右侧常驻一条空白槽，怪物内容缩在左边、
     和「每车材料」之间看着比底部缝大一圈 —— 去掉后内容撑满卡片，横向缝与底部一致 */
  #route-list {
    scrollbar-gutter: stable;
    overscroll-behavior: contain;
  }

  #route-list-view {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
  }
  #route-list-view > .route-head { flex: none; }
  #route-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 0;
  }

  /* 左列路线列表整体包进一张白卡，和右侧每车材料 / 怪物配置那一摞卡片视觉一致：
     整列是一条白卡，顶部是「+ 添加路线」表头（不再是独立小卡），下面是路线行。
     路线行改成和怪物列表一样的分割线（去掉各自的白卡底色 / 边框），否则白卡套白卡
     会糊成一片、看不出每条路线的边界；首行无顶线。 */
  #route-list-view {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 5px;
    overflow: hidden;          /* 圆角裁掉子元素的直角 */
    padding: 0;
  }
  /* 路线页四块容器统一 5px 小圆角；选择器都带 # 只作用这一页，
     其它页面的 .card / .route-row / .picker-inline 圆角保持原样 */
  #route-editor > .card:not(.route-head),
  #rt-preview .route-row,
  #rt-picker-inline { border-radius: 5px; }
  /* 表头从独立卡片降级成卡片内的表头条：去掉卡片底色 / 边框，底部加一道分隔 */
  #route-list-view > .route-head {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0 14px;
    margin-bottom: 0;
    border-bottom: 1px solid var(--border);
  }
  /* 列表滚动区：四周留出呼吸，路线行不再各自贴边成孤岛 */
  #route-list-view > #route-list {
    padding: 8px 12px 12px;
  }
  /* 路线行：去白卡，改分割线（与怪物列表同款）；选中态是圆角浅蓝底 + 左侧蓝竖杠 */
  #route-list-view .route-row {
    position: relative;
    background: none;
    border: 0;
    border-radius: 10px;
    margin: 0;
    padding: 12px 14px 12px 17px;
  }
  #route-list-view .route-row + .route-row {
    border-top: 1px solid var(--border);
  }
  /* 选中块上下都不压分割线，圆角边不被直角线切开 */
  #route-list-view .route-row.active,
  #route-list-view .route-row.active + .route-row { border-top-color: transparent; }
  /* 左侧蓝竖杠照导航项：从中间展开（scaleY 0→1），同一套时序 */
  #route-list-view .route-row::before {
    content: "";
    position: absolute;
    left: 6px;
    top: 50%;
    width: 2px;
    height: 26px;
    margin-top: -13px;
    border-radius: 1px;
    background: var(--accent);
    opacity: 0;
    transform: scaleY(0);
    transition: transform .18s cubic-bezier(0, 0, .58, 1), opacity .08s;
  }
  #route-list-view .route-row.active::before { opacity: 1; transform: scaleY(1); }
  /* 点选路线时蓝竖杠从中间展开：路线列表每次 renderRoutes 会重建 DOM，
     新元素上的 transition 不会触发，所以由选中那次挂一次 keyframes（时序同导航项） */
  #route-list-view .route-row.active.bar-enter::before {
    animation: rtBarIn .18s cubic-bezier(0, 0, .58, 1) both;
  }
  @keyframes rtBarIn {
    from { opacity: 0; transform: scaleY(0); }
    to   { opacity: 1; transform: scaleY(1); }
  }

  /* 右列：页头固定；掉落信息与表单各按内容占高，过长时各自滚动 */
  #route-editor {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    /* 顶部与左列容器齐平，只留页面统一的 4px 外边距 */
    padding-top: 0;
    /* 右列本身不滚：上面两块各自滚，底栏钉在最下面 */
    overflow: hidden;
  }
  /* 右列是 flex 纵向排列：预览与表单可以缩（缩到内部各自滚），底栏固定不缩 */
  #route-editor > #rt-preview { flex: 1 1 auto; }
  #route-editor > .card:not(.route-head) { flex: 0 1 auto; }
  #route-editor > #rt-picker-inline { flex: 0 0 auto; }
  #rt-preview {
    align-self: stretch;   /* flex 列里必须撑满宽度，否则按内容收缩、内部 grid 会塌 */
    min-height: 120px;     /* 缩到极限也留一条能看的掉落信息 */
    max-height: none;
    /* 卡片本身不滚：标题留在卡片顶部，只有下面的掉落行在卡片里滚 */
    overflow: hidden;
    padding-right: 0;
  }
  #rt-preview .route-row {
    max-height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  #rt-preview .route-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  #rt-preview:empty { display: none; }
  #page-route.route-viewing #rt-preview { grid-row: 1 / span 2; max-height: 100%; }

  /* 表单卡片：第一行是「路线名称 + 操作按钮」，第二行才是怪物列表。
     卡片按内容收拢，怪物少时多高就多高；怪多了卡片受列高限制，只有怪物列表内部滚。 */
  #route-editor > .card:not(.route-head) {
    grid-column: 1;
    grid-row: 2;
    margin-top: 12px;
    min-height: 0;
    align-self: stretch;
    max-height: 100%;
    display: grid;
    grid-template-columns: minmax(0, 220px) minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr);   /* 末行吃掉剩余高度给怪物列表 */
    column-gap: 12px;
    overflow: hidden;
  }
  /* 有怪时才保底高度（缩到极限也留一条怪）；空路线按内容收拢 */
  #route-editor > .card:not(.route-head):has(#rt-monsters .mon-box) { min-height: 180px; }
  /* 还没有掉落信息时上面的预览不占行，表单不能多出 12px，否则与左列按钮错位 */
  #route-editor:has(#rt-preview:empty) > .card:not(.route-head) { margin-top: 0; }
  #route-editor > .card > .field:first-child { display: contents; }
  #route-editor > .card > .field:first-child > .field-label {
    grid-column: 1 / -1;
    grid-row: 1;
    margin: 0 0 10px;
  }
  #route-editor > .card > .field:first-child > .name-row {
    grid-column: 1; grid-row: 2; min-width: 0;
  }
  /* 保存 / 放弃添加 / 删除路线 / 添加怪物统一短一档，紧贴输入框右侧 */
  #route-editor > .card > .editor-actions {
    grid-column: 2; grid-row: 2;
    margin: 0;
    align-self: center;
    gap: 8px;
    flex-wrap: nowrap;
  }
  #route-editor .name-row input[type="text"] { flex: 0 0 100%; max-width: none; }
  #route-editor .editor-actions button {
    flex: 0 0 92px;
    height: 44px;
    padding: 0 4px;
    font-size: 14.5px;
  }
  #route-editor > .card > .field:has(#rt-monsters) {
    grid-column: 1 / -1;
    grid-row: 3;
    /* 抵消卡片左右内边距，让怪物列表撑满卡片（和内容在「每车材料」里贴边一致，
       横向缝与上下缝视觉相同）；上下留白保持 */
    margin: 14px -18px 0;
    min-height: 0;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  /* 怪物列表撑满后不再留滚动条槽、也不显示滚动条：内容贴右缘，
     空出的右缘白条消失，横向缝看起来和上下缝一样窄（滚轮/触控板照常滚） */
  #rt-monsters { scrollbar-width: none; -ms-overflow-style: none; }
  #rt-monsters::-webkit-scrollbar { display: none; }
  #rt-monsters {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;    /* 列表 3 自己滚 */
    overscroll-behavior: contain;
    align-content: start;
  }

  /* 左列页头只留「+ 添加路线」，口径切换交给右列页头那一组 */
  #route-list-view > .route-head .sort-opt,
  #route-list-view > .route-head .who-set,
  #route-list-view > .route-head .sep { display: none; }
  #route-list-view > .route-head .btn-add {
    display: block;
    width: 100%;
    margin: 0;
    /* 和下面路线行同一档尺寸：按钮 46px 高、路线行 52px，不再是一整张大卡片 */
    height: auto;
    padding: 10px 14px;
    border-radius: 12px;
    font-size: 15px;
    font-weight: 600;
    line-height: 24px;
  }
  /* 左列只有这一个按钮，不再套卡片容器：去掉底色/描边/圆角。
     高度跟按钮走，按钮顶端与右列第一张卡片落在同一条上边距上。 */
  #route-list-view > .route-head {
    background: none;
    border: 0;
    border-radius: 0;
    padding: 0;
    height: auto;
    margin-top: 0;        /* 去掉桌面 .card 的 20px 上外边距，按钮顶端与右列首卡齐平 */
    /* 右侧留出与 #route-list 滚动条槽（thin ≈ 10px）等宽的内边距：
       按钮缩到和下方路线卡片一样宽。用内边距而不是 overflow 造槽，
       是因为 overflow 会连滚动条两端的箭头一起画出来。 */
    padding-right: 10px;
  }
  /* 切换条在左列是包着按钮的容器：让它撑满，按钮的 100% 才等于整列宽 */
  #route-list-view > .route-head .sort-bar { flex: 1 1 auto; min-width: 0; }

  /* 预览卡顶部的砂糖 / 多莉：与「N 只 / 车」同一行，比页头那组小一档 */
  #rt-preview .who-inline { display: flex; align-items: center; gap: 6px; }
  #rt-preview .who-inline .sort-opt { height: 32px; padding: 0 14px; font-size: 14px; }
  /* 两列布局里口径切换与砂糖/多莉都已经在卡片里，右列页头没有内容 ⇒ 不占位，
     第 2/3 列表直接吃页面顶部内边距，与左列「+ 添加路线」按钮同一条上边距 */
  #route-editor > .route-head { display: none; }

  /* 左列路线行：压成一行路线名；圆角与选中竖杠沿用上方规则 */
  #route-list-view .route-row {
    margin: 0;
    padding: 12px 14px 12px 17px;
    cursor: pointer;
  }
  /* 路线名照导航项配色：未选中是次要色，悬停提亮，只有当前选中的才是纯白 */
  #route-list-view .route-name { font-size: 16.5px; color: var(--text-2); }
  #route-list-view .route-row.active .route-name { color: var(--text); }
  @media (hover: hover) {
    #route-list-view .route-row:not(.active):hover .route-name { color: var(--text); }
  }
  #route-list-view .route-count,
  #route-list-view .route-body,
  #route-list-view .icon-btn.edit,
  #route-list-view .icon-btn.collapse { display: none; }
  #route-list-view .sort-handle { margin-left: auto; width: 28px; height: 28px; }
  #route-list-view .sort-handle .sort-ico { width: 20px; height: 20px; }
  #route-list-view .route-row.active {
    background: var(--accent-soft);
    box-shadow: none;
  }
  #route-list-view .route-row.active .route-name { font-weight: 700; }
  #route-list-view .empty-tip { margin: 0; padding: 22px 12px; font-size: 15px; }

  /* 两列同屏时页头的返回按钮没有意义，一直隐藏 */
  #route-editor .btn-back { display: none !important; }
  /* 新建态：无图标的「放弃添加」与「保存」并排 */
  #page-route.route-new #btn-rt-cancel-new { display: inline-block !important; }
  /* 列数由下面的桌面 grid 统一压成一列（一行一只），这里保留网格行距等设置 */
  #rt-monsters {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
    column-gap: 12px;
    /* 行距挂在每行自己身上（见下面 .mon-box 的 margin-bottom），不走 grid 的 row-gap：
       行收到 0 高时 row-gap 那条缝还留着，删掉节点时下面会再跳一下。
       最后一行那 12px 由容器的负 margin 抵掉，版面与原来一致。 */
    row-gap: 0;
    margin-bottom: -6px;
  }
  #rt-monsters:empty { margin-bottom: 0; }
  /* 行距放在 .mon-box 的 margin-bottom 上（不是 .mon-clip 的 padding）：
     格子的 padding 不随 0fr 行高收掉，收起来时还会留一条 12px 的边。 */
  #rt-monsters .mon-wrap > .mon-clip > .mon-box { margin: 0; }

  /* 桌面端唯一的编辑布局：左侧表单（一行一只怪）/ 右侧掉落信息同屏并排，
     下面压一条选材料。浏览器缩放只改 CSS 视口宽度，不切换结构。 */
  @media (min-width: 1100px) {
    #route-editor {
      display: grid;
      grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
      grid-template-rows: minmax(0, 1fr) max-content;
      column-gap: 4px;           /* 怪物配置 ↔ 每车材料 */
      row-gap: 4px;              /* 上排 ↔ 底部选材料 */
      align-content: stretch;
      overflow-y: auto;
    }
    /* 上面两块**等高**：怪物配置跟着「每车材料」的高度走，右边缘自然对齐成一条线，
       怪物少时也不再在卡片下面留一大片空白 */
    #route-editor > .card:not(.route-head) { grid-column: 1; grid-row: 1; margin-top: 0; align-self: stretch; }
    #rt-preview { grid-column: 2; grid-row: 1; align-self: stretch; max-height: none; }
    /* 掉落信息与怪物配置下面：铺满整行的一条，图标墙按行铺开；行距交给 row-gap */
    #rt-picker-inline { grid-column: 1 / -1; grid-row: 2; margin-top: 0; }
    /* 右列预览区很宽：标题、材料图标、数量与进度文字放大一档。
       放大量按 vw 给，固定 px 会让 1080p/100% 比 80% 缩放整整大一截。 */
    #rt-preview .route-row {
      /* 「每车材料 / 砂糖 / 多莉」距卡片左缘留 8px 呼吸，不贴边；
         右 / 上 / 下沿用大屏内边距，卡片右缘仍与底部选材料对齐 */
      padding: clamp(18px, 1vw, 26px) clamp(16px, .92vw, 24px) clamp(18px, 1vw, 26px) 8px;
    }
    #rt-preview .route-name { font-size: clamp(18px, 1vw, 26px); }
    #rt-preview .route-count { font-size: clamp(13px, .71vw, 18.5px); }
    #rt-preview .route-body { margin-top: clamp(12px, .67vw, 17px); }
    /* 按「掉落行所在内容列」的宽度查询，而不是视口宽度：缩放只改 CSS 视口，
       这里要判的是这一行到底放不放得下六列 */
    #rt-preview .expanded-rows { container-type: inline-size; container-name: rtdrops; }
    #rt-preview .drop-row.both {
      /* 六个格子默认同排；窄到放不下时由文件末尾的容器查询切成 2 行 × 3 列 */
      gap: clamp(7px, .42vw, 11px);
      padding: clamp(9px, .5vw, 13px) 0;
      font-size: clamp(12px, .67vw, 17px);
    }
    #rt-preview .drop-row.both .drop-cell { gap: clamp(7px, .42vw, 11px); }
    #rt-preview .drop-row.both .drop-cell img {
      width: clamp(30px, 1.67vw, 44px);
      height: clamp(30px, 1.67vw, 44px);
    }
    #rt-preview .drop-row.both .drop-cell b { font-size: clamp(12px, .67vw, 17px); }
    #rt-preview .drop-row.both .grad-num,
    #rt-preview .drop-row.both .grad-per,
    #rt-preview .drop-row.both .grad-trip { font-size: clamp(10.5px, .58vw, 15px); }
    /* 当前材料数量里的图标 / 输入框，尺寸与同处预览区的「每车材料」完全对齐：
       图标 clamp(30,1.67vw,44) 与上面 .drop-cell img 同一把尺子；输入框字号同步放大。 */
    #rt-preview .route-progress .rp-tier img {
      width: clamp(30px, 1.67vw, 44px);
      height: clamp(30px, 1.67vw, 44px);
    }
    #rt-preview .route-progress .rp-tier input {
      /* 至少 44px：四位数量（9999）在放大后的字号下要完整显示，不能只剩 3 位 */
      width: clamp(44px, 2.4vw, 56px);
      height: clamp(26px, 1.4vw, 32px);
      font-size: clamp(12px, .67vw, 17px);
    }
    #rt-preview .route-progress .rp-grid {
      /* 分组块之间的空隙；同时 100% 缩放仍能三族一行 */
      gap: clamp(10px, .6vw, 14px) clamp(10px, .7vw, 16px);
    }
    #rt-monsters { grid-template-columns: minmax(0, 1fr); }
    /* 新建态还没有掉落信息：表单铺满整行 */
    #page-route.route-new #route-editor > .card:not(.route-head) { grid-column: 1 / -1; }
    #page-route.route-new #rt-preview { display: none; }
    /* 查看别人：只留掉落信息，铺满整行 */
    #page-route.route-viewing #rt-preview { grid-column: 1 / -1; grid-row: 1; }
  }
  #page-route.route-viewing #route-editor > .card:not(.route-head) { display: none; }

  /* 一条路线都没有：右列给一块空态 */
  #page-route.route-empty #route-editor { display: none !important; }
  #page-route.route-empty::after {
    content: "还没有路线 —— 点左侧「+ 添加路线」新建一条";
    grid-column: 2;
    grid-row: 1;
    align-self: start;
    margin-top: 20px;
    padding: 64px 24px;
    text-align: center;
    font-size: 17px;
    color: var(--text-2);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 18px;
  }

  /* 侧栏不占垂直空间，暗月 iframe 直接铺满整屏高度 */
  .darkmoon-frame { height: 100dvh; }
}
@supports not (height: 100dvh) {
  @media (min-width: 1100px) {
    .topbar { height: 100vh; }
    .darkmoon-frame { height: 100vh; }
    body:has(#page-route:not([hidden])) { height: 100vh; }
    main:has(#page-route:not([hidden])) { height: 100vh; }
    #page-route { height: 100vh; }
  }
}
/* === DESKTOP-SIDEBAR-END === */

/* === SITE-ICP-START ===
   备案号页脚：跟在内容末尾，内容滚到底才出现，不单独占一条常驻栏。
   高度统一走 --icp-h，内容区与路线页按它扣减，页脚落在视口最底部。 */
:root { --icp-h: 54px; }
.site-icp {
  height: var(--icp-h);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--text-2);
}
.site-icp a { color: inherit; text-decoration: none; }
.site-icp a:active { color: inherit; }

/* 内容少的页面也把 main 撑满一屏，页脚落在视口底部而不是悬在内容后面 */
main { min-height: calc(100dvh - 55px - var(--icp-h)); }
@media (min-width: 760px) {
  main { min-height: calc(100dvh - 50px - var(--icp-h)); }
}
@media (min-width: 1100px) {
  main { min-height: calc(100dvh - var(--icp-h)); }
  /* 路线页不挂备案号（首页已经有）：整页锁在视口内，底栏直接占满到底，
     不再为页脚留那 54px */
  body:has(#page-route:not([hidden])) .site-icp { display: none; }
  #page-route { height: 100dvh; }
  body:has(#page-route:not([hidden])) { height: auto; overflow: hidden; }
  main:has(#page-route:not([hidden])) { height: 100dvh; padding-bottom: 0; }
  @supports not (height: 100dvh) {
    #page-route { height: 100vh; }
    main:has(#page-route:not([hidden])) { height: 100vh; }
  }
}
/* === SITE-ICP-END === */

/* === DM-CENTER-START ===
   暗月计算器页保持原来的居中宽度：内容区最宽 880px，宽屏下在导航栏右侧居中，
   不跟随其他页面铺满整个内容区。 */
@media (min-width: 1100px) {
  body.dm-view main {
    max-width: 880px;
    margin-left: max(208px, calc((100vw - 880px) / 2));
    margin-right: auto;
    /* 暗月页原来就是 content 贴边 880px，桌面档的左右内边距在这里归零 */
    padding-left: 0;
    padding-right: 0;
  }
}
/* === DM-CENTER-END === */

/* 云端同步页、导入导出页与暗月计算器同一套：内容居中 880px，不铺满整个内容区 */
@media (min-width: 1100px) {
  body:has(#page-account:not([hidden])) main,
  body:has(#page-io:not([hidden])) main {
    max-width: 880px;
    margin-left: max(208px, calc((100vw - 880px) / 2));
    margin-right: auto;
    padding-left: 0;
    padding-right: 0;
  }
}

/* 导入导出页的主题切换：图标 + 当前主题文字，跟暗月里的按钮共用 lvcalc.theme */
.theme-toggle { display: flex; align-items: center; justify-content: center; gap: 8px; }
.theme-toggle .theme-ico {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: var(--text-2);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 导航里的主题项：图标与其它导航同尺寸，只描边不填充；手机横排导航放不下第六项，
   主题入口留在导入/导出页底部那张卡片里 */
.nav-item .theme-ico {
  fill: none;
  /* 不跟 currentColor：文字有「110ms 后翻面」的防撞色处理，图标跟着会慢半拍，
     直接取主题变量，换主题那一帧就是新颜色 */
  stroke: var(--text-2);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (max-width: 1099px) {
  #nav-theme { display: none; }
}

/* 主题图标不做颜色过渡：切换那一帧直接换成新颜色，避免比背景慢半拍 */
html.theme-transition .theme-ico { transition: none !important; }

@media (min-width: 1100px) {
  /* 与表单里那句「若每日有固定上限…」同字号（.field-label 桌面 15.5px） */
  .picker-tip { font-size: 15.5px; }
}

/* 选敌人区固定在画面底部（桌面）：右列内容再多，这块也始终贴在可视区最下沿，
   上方的掉落信息与怪物配置从它后面滚过去。 */
@media (min-width: 1100px) {
  #rt-picker-inline {
    position: static;
    margin-bottom: 0;
    /* 标题行一行，下面展开块与合并块**叠在同一格里**：
       这样合并时图标墙往下收，最后一行的位置正好是合并块长出来的地方，
       视觉上就是「同一面墙收到一行高」，而不是合并块从底下顶上来。 */
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    /* 两块各自按自己的行高过渡，别被拉成等高（拉平后两块插值互相干扰，
       中间会凹一下再弹回来） */
    align-items: start;
    /* 高度由图标墙内容撑开：三行材料约 320px。上限要留足这段高度 ——
       格子尺寸跟 vw（宽度）走，视口变矮时三行并不会跟着变矮，上限按 vh 收得
       太紧就会把第三行截掉、平白多出一条滚动条。只有窗口极矮或材料特别多时
       才让图标墙在内部滚。 */
    flex: 0 1 auto;
    max-height: max(340px, 44vh);
  }
  #rt-picker-inline > .picker-inline-head { grid-row: 1; grid-column: 1; }
  #rt-picker-inline > .picker-expanded,
  #rt-picker-inline > .picker-collapsed { grid-row: 2; grid-column: 1; }
  /* 合并块恒为「一行高」，只做淡入淡出 —— 让它跟着 0fr⇄1fr 一起长高的话，
     两块插值在交叉点会互相压出个凹陷，看着像「合并过头又弹回来」。
     恒高之后底栏高度 = max(展开块 223→0, 50.7)，单调下降到一行，不会回弹。 */
  #rt-picker-inline:not(.collapsed) .picker-collapsed,
  #rt-picker-inline.collapsed .picker-collapsed { grid-template-rows: 1fr; }
  /* 展开态它虽然透明但还盖在第一行上，必须关掉命中测试，
     否则点第一行图标点到的是这一层（没有格子那套蓝框反馈） */
  #rt-picker-inline:not(.collapsed) .picker-collapsed { opacity: 0; pointer-events: none; }
  #rt-picker-inline.collapsed .picker-collapsed { opacity: 1; }
  /* 标题行三栏：左标题 / 正中箭头 / 右敌人按钮，两侧等宽 ⇒ 箭头永远落在
     这一行的正中心；敌人按钮再多也不会压到它，放不下时在自己的栏里横向滚。 */
  #rt-picker-inline .picker-inline-head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    column-gap: 14px;
    /* 高度钉死：胶囊出现 / 消失都改不了这一行，底栏不会被顶高 */
    position: relative;
    height: 30px;
    min-height: 30px;
    margin-bottom: 4px;
    overflow: visible;
    cursor: pointer;
  }
  #rt-picker-inline .picker-inline-head > * { grid-row: 1; }
  /* 桌面不写标题：这一行只留正中的展开 / 合并箭头，选材料时具体敌人的按钮
     出现在原来标题的位置（左边），不再甩到最右边 */
  #rt-picker-inline #picker-title { display: none; }
  #rt-picker-inline .picker-head-left {
    grid-column: 1;
    min-width: 0;
    flex-wrap: wrap;
    align-content: center;
  }
  /* 敌人胶囊**脱流**（绝对定位）：它在不在、有几个、多高，都不参与标题行的高度计算，
     底栏永远不可能因为它被顶高。位置仍是标题行左侧、铺满左半边，
     右半边留给正中的展开 / 合并箭头。 */
  #rt-picker-inline #picker-variants {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 30px;
    display: flex;
    align-items: center;
    min-width: 0;
    max-width: calc(50% - 30px);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
  }
  #rt-picker-inline #picker-variants::-webkit-scrollbar { display: none; }
  #rt-picker-inline .picker-chips { flex-wrap: nowrap; align-items: center; }
  #rt-picker-inline .chip-mon {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 4px 14px;
    font-size: 14px;
    line-height: 20px;
  }
  /* 合并行是 justify-items:center，那条分界线得自己撑满整行，否则被压成 0 宽 */
  #rt-picker-inline .collapse-scroll .picker-sep { justify-self: stretch; }

  /* 两块内容常驻 DOM（和路线卡片一样是 .expanded-part / .collapsed-part）：
     切 .collapsed 时各自 grid-template-rows 0fr ⇄ 1fr、opacity 一起插值，
     过渡时长由 toggleCollapseRow() 按图标墙高度算，两块共用同一条曲线。
     这里只把它们当成不主动伸长的 flex 子项，高度完全交给行高过渡。 */
  #rt-picker-inline .picker-expanded,
  #rt-picker-inline .picker-collapsed {
    flex: 0 1 auto;
    min-height: 0;
    padding-right: 0;
  }
  /* 展开态的图标墙保持原样：撑出多少行就是多少行。
     滚动条槽常驻（scrollbar-gutter:stable），和合并态那条细滚动条占的宽度一致 ——
     否则切换时内容区宽度变 8px，整面图标墙会横向重排、看着「左右跳」。 */
  #rt-picker-inline #picker-grid {
    min-height: 0;
    overflow-y: auto;
    scrollbar-gutter: stable;
  }
  /* 合并态就是路线卡片合上后的那一行（.collapse-scroll 原样照用）。
     列定义与展开态的图标墙逐字相同 ⇒ 每个图标落在同一列上，切换时不会横向错位；
     窗口只留一行高，剩下的沿竖向滚动。 */
  #rt-picker-inline .collapse-scroll {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(40px, 2.9vw, 76px), 1fr));
    justify-items: center;
    align-content: start;
    gap: clamp(5px, .42vw, 9px);
    height: auto;
    /* 窗口正好一整行（+2px 给描边留一点呼吸）：高一点就露出下一行，矮一点图标会被裁 */
    max-height: calc(clamp(28px, 2.34vw, 60px) + 2px);
    padding: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* 高度随行高从 0 长起来时，浏览器默认会为了「保持内容可见」把滚动位置往下推，
       表现成第一行材料从底部滑出来。钉死锚点，它就老老实实从顶部展开 */
    overflow-anchor: none;
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: var(--sb-thumb) transparent;
  }
  #rt-picker-inline .collapse-scroll .ci {
    width: clamp(28px, 2.34vw, 60px);
    height: clamp(28px, 2.34vw, 60px);
    border-radius: 8px;
    cursor: pointer;
  }
  /* 选中态跟图标墙同一套：预选 = 蓝框，已选 = 淡蓝底 + 蓝框。
     描边画在图标**内侧**（inset），这样无论滚到哪一行、贴不贴容器边都不会被裁掉 */
  #rt-picker-inline .collapse-scroll .ci.active {
    box-shadow: inset 0 0 0 2px var(--accent);
  }
  #rt-picker-inline .collapse-scroll .ci.used {
    box-shadow: inset 0 0 0 999px var(--accent-soft), inset 0 0 0 2px var(--accent);
  }
  /* 标题行正中的展开 / 合并按钮：路线卡片那个 chevron，尺寸、配色、箭头
     旋转都沿用同一套样式，只是位置落在标题行水平正中。 */
  #rt-picker-inline .picker-collapse {
    grid-column: 2;
    position: static;
    width: 28px;
    height: 28px;
    margin: 0;
    color: var(--text-2);
    opacity: .55;
  }
  #rt-picker-inline .picker-collapse svg { width: 20px; height: 20px; }
  /* 悬停 / 按下只放大，不改色、不铺底色 */
  #rt-picker-inline .picker-collapse,
  #rt-picker-inline .picker-collapse:hover,
  #rt-picker-inline .picker-collapse:active { background: transparent; }
  #rt-picker-inline .picker-collapse:hover,
  #rt-picker-inline .picker-collapse:active { color: var(--text-2); }
  #rt-picker-inline .picker-collapse:hover,
  #rt-picker-inline .picker-collapse:active { transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  /* toggleCollapseRow 会写内联 transitionDuration，这里要用 !important 才压得住 */
  #rt-picker-inline .expanded-part,
  #rt-picker-inline .collapsed-part { transition: none !important; }
}

/* 右列是 grid：第二行放底栏，spacer 不参与布局 */
.rt-spacer { display: none; }
@media (min-width: 1100px) {
  #route-editor > .rt-spacer { display: none; }
  /* 第一行吃掉剩余高度（两块各自在里面滚），第二行放底栏 */
  #route-editor {
    grid-template-rows: minmax(0, 1fr) auto;
    align-content: stretch;
    overflow: hidden;
  }
  /* 两块都按内容高、最多占满第一行；超了各自滚，不再被行高拉长 */
  /* 掉落卡片本身不滚：高度铺满第一行，只有卡片里的掉落行滚 */
  #rt-preview { align-self: stretch; max-height: 100%; overflow: hidden; }
  #rt-preview .route-row { height: 100%; }
  /* 和右边「每车材料」等高：两块上下边缘对齐成一条线，怪物少时也不留一大片空白 */
  #route-editor > .card:not(.route-head) { align-self: stretch; max-height: 100%; overflow: hidden; }
  #rt-picker-inline { align-self: end; }
}


/* 「选择敌人掉落的材料」这块底栏第一次出现时从底部升起，
   跟上面新加敌人那一条用同一条曲线，不显得突兀。 */
@keyframes pickerIn {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: none; }
}
.picker-inline.picker-in {
  animation: pickerIn .32s cubic-bezier(.4, 0, .2, 1);
}
@media (prefers-reduced-motion: reduce) {
  .picker-inline.picker-in { animation: none; }
}

/* 三块各自独立排版/绘制：某一块内容变化时不会带着旁边一起重绘，
   展开/收起、删除这些高频操作不容易再出现整片闪烁。 */
@media (min-width: 1100px) {
  #rt-preview,
  #rt-monsters,
  #rt-picker-inline {
    contain: layout paint;
  }
}

/* 桌面端：敌人数量行去掉最左侧那张材料图标，「这只怪自己的掉落期望」
   跟在等级输入框后面；输入框那一行放不下完整三档时，整块自动换到输入框
   下面一行，两种状态都不裁切、不与输入框重叠。
   移动端 <1100 完全保持原样：图标还在，也不显示单怪期望。 */
@media (min-width: 1100px) {
  #rt-monsters .mon-box > img { display: none; }
  #rt-monsters .mon-info { flex: 1 1 auto; }
  #rt-monsters .mon-lvs {
    flex-wrap: wrap;
    align-items: flex-end;      /* 同一行时期望与输入框底部齐平 */
    row-gap: 6px;               /* 换行后期望距输入框 6px */
  }
  #rt-monsters .mon-drops {
    display: flex;
    flex: 1 1 auto;
    min-width: max-content;     /* 完整三档压不掉 ⇒ 放不下时整块换行 */
  }
  #rt-monsters .mon-del { margin-left: 0; }
}

/* 「每车材料」六个格子完整显示每列至少 ~82px（1280 档每列 67.6px 时
   图标+数字已溢出 14px），加上 5 道 7px 间距约 527px。
   内容列比这更窄（缩放放大）才换成 2 行 × 3 列：三档在上、进度文字在下。 */
@container rtdrops (max-width: 530px) {
  #rt-preview .drop-row.both { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

