/* style.css — 原子轨道可视化工具 · 暗色主题 + 响应式

   色彩体系：
     - 背景：深蓝黑 (#0b1020)，点缀蓝紫，强调青/橙。
     - 轨道类型配色由 js/math.js 提供（s 蓝 / p 绿 / d 橙 / f 紫）。
   布局：
     - 桌面（≥1024px）：顶部栏 + 两列主区（3D + 控制面板）+ 公式 + 三列图表。
     - 平板 / 手机：纵向堆叠，3D 视图占主视口高度。
   字体：系统字体 + KaTeX 内嵌数学字体。 */

:root {
  --bg: #0b1020;
  --bg-2: #101629;
  --card: #151c33;
  --card-2: #1a2340;
  --line: #2a3558;
  --line-soft: #202b48;
  --text: #e8ecf7;
  --text-dim: #9aa7c6;
  --accent: #55c2ff;
  --accent-2: #7a9bff;
  --active: #2b3d6b;
  --border-radius: 14px;
  --shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: radial-gradient(1200px 700px at 30% -10%, #1a2d54 0%, #0b1020 55%);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "PingFang SC",
    "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ---------- 顶栏 ---------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 22px;
  border-bottom: 1px solid var(--line-soft);
  background: rgba(12, 17, 34, 0.7);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 10;
}
.brand { display: flex; align-items: center; gap: 12px; }
.logo { font-size: 26px; }
.brand h1 { font-size: 19px; font-weight: 700; margin: 0; letter-spacing: 0.5px; }
.subtitle { font-size: 12px; color: var(--text-dim); align-self: flex-end; margin-bottom: 3px; }
.top-meta { display: flex; align-items: center; gap: 12px; }
.orbit-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 22px; font-weight: 700; color: var(--accent);
  min-width: 78px; text-align: right;
  /* ★ 第 3 条「右上角数字太小」的**真因**不在字号，在字形：
       Georgia 是这一串字体里唯一用**旧式数字**（old-style figures）的 ——
       实测字形包围盒（unitsPerEm 2048）：数字 1/2/0 的 yMax=1105（0.54em，只有 x 高度），
       3/4/5 还带 yMin=−365 沉到基线以下；而同字体的 d/f/h 上伸到 1548（0.76em）。
       于是 "3d" 里数字只有字母的约 71%，"3 个分量"（旁边是汉字，几乎占满整个 em）
       看起来更是只有一半高。CSS 里**没有任何规则**缩小过它。
     Georgia 自带 lnum 特性（GSUB 里已确认存在），这一行就能把它切成全高数字。 */
  font-variant-numeric: lining-nums;
}
/* m 下标（仅复解档的 m=+1）与实轨道名（p_x、d_xy…）
   ★ 第 3 条：实解档的轨道名要与前面的 n **同色同号**。
     复解档渲染成 `3p<sub>m=0</sub>` —— `3p` 同为 22px 强调色，只有下标小；而实解档
     把 `p_x` 单独缩到 0.72em 并改成正文色，于是"3"与"p_x"看着像两个不相干的词，
     而这恰恰是**实数解档唯一的名字**。现在 font-size:1em + color:inherit 之后，
     实解档的 `3p` 与复解档的 `3p` 逐像素一致，`x` 由下面 .orbit-title sub 的 0.73em
     统一管 —— 不再单写一条 .orbit-real sub 去覆盖它（那条正是两档下标大小不一的来源）。
   ★ 0.73em 是配合**多级下标**定的：顶栏符号现在形如 ψ<sub>3d<sub>z²</sub></sub>，
     sub 会逐层复合，0.73² ≈ 0.53 —— 22px → 16px → 12px，两级都还读得出来。
     原先的 0.6em 是给"单级下标"定的，套两层会掉到 0.36em（8px），二级下标就糊了。 */
.orbit-title sub { font-size: 0.73em; font-weight: 400; }
.orbit-title .orbit-real {
  font-size: 1em; font-weight: 400; color: inherit;
  /* ★ 不能再留 margin-left：`.orbit-real` 里的字与外面的字字形要紧贴，
     加上 margin 就变成 `叠加态 3 个分量` 里多出一个空档。
     需要间隔的场合由调用方在文本里写空格。 */
  white-space: nowrap;
}
/* ★ 原先这里还有一条 `.orbit-title .orbit-real.poly`（0.72em），给 l≥4 那种
   "6h 3xyz³−xyzr²" 的长多项式用的。顶栏改成显示**符号**之后（ψ_{6,5,f(r)}），
   那个多项式不再进顶栏，这条规则就没有消费者了 —— 删掉，
   免得日后有人照着它去调一个已经不存在的元素。 */
.badge {
  background: linear-gradient(135deg, #2b3d6b, #3b2f6b);
  border: 1px solid #4a5a96;
  color: #dde6ff;
  font-size: 12px;
  padding: 6px 12px;
  border-radius: 999px;
}

/* ---------- 布局 ---------- */
.layout { max-width: 1500px; margin: 0 auto; padding: 18px 22px 40px; }
.grid-main {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 18px;
}
.grid-charts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-top: 18px;
}
/* ★ min-width:0 不能省。1fr 实为 minmax(auto, 1fr)，而 auto 的最小宽度 = 项目的
   min-content 尺寸；栅格项里放了 canvas（有固有像素宽度）时，列就不肯收缩，
   于是"抽屉一打开，三张卡片宽度不一致"——中间那张撑住原宽、两侧被压扁。 */
.grid-charts > * { min-width: 0; }

/* ---------- 卡片 ---------- */
.card {
  background: linear-gradient(180deg, var(--card), var(--card-2));
  border: 1px solid var(--line);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
}
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  gap: 10px;
  flex-wrap: wrap;
}
.card-head-right { display: flex; align-items: center; gap: 14px; }
.card-title { font-size: 14px; font-weight: 700; color: var(--text); letter-spacing: 0.3px; }

/* ---------- 3D 视图 ---------- */
/* 高度由 layout.js 按"窗口真实可见高度 − 画布顶端位置"算出，写进 --viewer-h，
   目的是让整块画布正好落在浏览器窗口里（不写死像素/视口单位）。
   变量尚未算出时用 44vh 兜底，属于渐进增强，不是硬编码尺寸。
   另：align-self:start 让它**不被同行更高的面板拉伸**——面板的高度是从它这里量出去的
   （--panel-h），它自己再被面板反向影响就会形成循环。这条是"单向依赖"的关键。 */
.viewer-card { display: flex; flex-direction: column; min-height: 0; align-self: start; }
.viewer {
  position: relative;
  flex: none;
  height: var(--viewer-h, 44vh);
  min-height: 0;
  border-radius: 10px;
  overflow: hidden;
  background: radial-gradient(600px 400px at 50% 40%, #16223f 0%, #0b1020 70%);
  border: 1px solid var(--line-soft);
}
.viewer canvas { display: block; width: 100% !important; height: 100% !important; }

/* 三维视图上的标注标签（参考球 / 节面高亮）——点一下就撤销。
   没有它，画上去的辅助几何就只能靠智能体才能清掉。 */
.viewer-chips {
  position: absolute;
  left: 10px;
  bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
  z-index: 5;
  pointer-events: none;              /* 容器不拦截拖拽旋转，只有标签本身可点 */
}
.viewer-chip {
  pointer-events: auto;
  font: inherit;
  font-size: 12px;
  color: #ffe6a8;
  background: rgba(20, 28, 50, .82);
  border: 1px solid rgba(255, 210, 74, .45);
  border-radius: 999px;
  padding: 4px 11px;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.viewer-chip:hover { background: rgba(255, 210, 74, .18); border-color: rgba(255, 210, 74, .8); }
.viewer-chip.hidden { display: none; }

/* ---------- 控制面板 ---------- */
/* ★ 面板高度与左侧三维卡片**等高**：高度由 layout.js 量出三维卡片后下发 --panel-h
   （见那里关于"为什么不会自激"的说明）。变量还没算出来时退回 auto（渐进增强），
   窄屏单列布局下 layout.js 会主动移除它、让内容自然排布。
   .panel-body 负责在内容超出时**内部**滚动 —— 不这样做，面板就会把整行栅格撑高、
   把底下的公式与图表往下推，而 3D 画布高度是按"窗口可见高度"算死的，于是右侧多出
   一大截空白。 */
.panel {
  align-self: start;
  display: flex;
  flex-direction: column;
  height: var(--panel-h, auto);
}
.panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }
/* 面板内的细滚动条：默认滚动条在深色面板上很扎眼，且占宽会挤压滑块 */
.panel-body { scrollbar-width: thin; scrollbar-color: rgba(106, 126, 201, .5) transparent; }
.panel-body::-webkit-scrollbar { width: 8px; }
.panel-body::-webkit-scrollbar-track { background: transparent; }
.panel-body::-webkit-scrollbar-thumb {
  background: rgba(106, 126, 201, .45); border-radius: 4px;
}
.panel-body::-webkit-scrollbar-thumb:hover { background: rgba(106, 126, 201, .7); }
.set { margin: 12px 0; }
.set.tight { margin: 4px 0 6px; }
.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
  font-size: 14px;
}
.row label { color: var(--text-dim); }
.val {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--accent);
  background: var(--active);
  border-radius: 8px;
  padding: 2px 10px;
  min-width: 44px;
  text-align: center;
  font-size: 14px;
}
/* 提示文字（如 φ 无影响时的说明） */
.hint { color: var(--text-dim); font-size: 12px; margin-top: 6px; line-height: 1.5; }
.hint b { color: var(--accent); font-variant-numeric: tabular-nums; }
/* 提示行里的内联按钮（如「采用推荐阈值」）：做成链接样式，不占额外一行 */
.link-btn {
  border: none; background: none; padding: 0 2px; margin-left: 4px;
  color: var(--accent); font: inherit; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { filter: brightness(1.25); }
/* 数字输入框：与滑块并用，可直接键入精确值 */
.num-val {
  width: 64px;
  padding: 3px 8px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--active);
  color: var(--accent);
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
  outline: none;
  transition: border-color 0.15s ease;
}
.num-val:focus { border-color: var(--accent); }
/* 非法输入提示 */
.num-val.invalid { border-color: #ff6b6b; color: #ff9b9b; }
/* 隐藏数字框的上下箭头（仍可键入） */
.num-val::-webkit-outer-spin-button,
.num-val::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.num-val { -moz-appearance: textfield; appearance: textfield; }
/* 禁用的滑块组（φ 不生效时置灰） */
.set.dim { opacity: 0.45; }
.set.dim input[type="range"] { cursor: not-allowed; }
.set.dim .val { color: var(--text-dim); }
.divider {
  display: flex;
  align-items: center;
  color: var(--text-dim);
  font-size: 12px;
  margin: 14px 0 10px;
  gap: 10px;
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }

/* ---------- 滑块 ---------- */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 6px;
  border-radius: 6px;
  background: var(--active);
  outline: none;
  margin: 0;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border: 2px solid #dbeaff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border: 2px solid #dbeaff; cursor: pointer;
}

/* ---------- 分段控件（按钮组） ---------- */
.seg { display: inline-flex; background: var(--active); border-radius: 10px; padding: 3px; gap: 3px; }
/* ★ 第 1 条：面板上这几组「整行选一个」的按钮要**居中**（实轨道 / 视图对象 /
   波函数形式 / 三维渲染）。它们是独占一行的，左对齐时右侧空出一大片，
   视觉上像是没排完版。组内的分段按钮（判据、截面平面…）在 .row 里右对齐，不受影响。 */
.seg.center { display: flex; width: fit-content; margin: 0 auto; }
.seg.small .seg-btn { font-size: 12px; padding: 5px 10px; }
/* 需要换行的分段组（实轨道选择器：l=5 时有 11 个选项，一行排不下） */
.seg.wrap { display: flex; flex-wrap: wrap; }
.seg.wrap .seg-btn { flex: 0 0 auto; padding: 6px 11px; font-size: 12.5px; }
.seg-btn {
  border: none;
  background: transparent;
  color: var(--text-dim);
  padding: 7px 14px;
  border-radius: 8px;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
}
.seg-btn:hover { color: var(--text); }
.seg-btn.active {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #0b1224;
  font-weight: 700;
}
/* 禁用的分段按钮（如 l=0 时的相位色：角度函数是常数，没有正负可分） */
.seg-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.seg-btn:disabled:hover { color: var(--text-dim); }

.btn {
  border: 1px solid var(--line);
  background: var(--card-2);
  color: var(--text);
  padding: 7px 14px;
  border-radius: 10px;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
/* 2D 图表的分量选择器（第 G 批）：内嵌在提示行里，尽量不抢视觉 */
.chart-term {
  background: var(--active, #1b2440); border: 1px solid var(--line, #2a3558);
  border-radius: 6px; color: var(--text, #e8ecf7); font-family: inherit; font-size: 12px;
  padding: 1px 4px; margin: 0 2px; outline: none; cursor: pointer;
}
.btn-ghost { background: transparent; }
/* 点亮态（「节面」按钮）：与分段控件的 active 同色系，看得出"这个标注正开着" */
.btn-ghost.active {
  background: rgba(255, 138, 212, 0.18);
  border-color: rgba(255, 138, 212, 0.55);
  color: #ffc7ec;
}
.chk { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-dim); cursor: pointer; }
.chk input { accent-color: var(--accent); }

/* ---------- 公式 ---------- */
.formula-card { margin-top: 14px; }
.formula-box {
  overflow-x: auto;
  padding: 2px 4px;
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.formula-box .katex { font-size: 1.06em; }
.formula-note { color: var(--text-dim); font-size: 12.5px; margin-top: 4px; text-align: center; }

/* ---------- 图表卡片 ---------- */
.chart-card { min-height: 0; position: relative; }
/* 图表上的浮动小控件（如截面图的「复位缩放」）—— 照 .viewer-chip 的做法：只在被手动
   调整过时出现。没有它，缩放后只能靠双击或重新选平面才能回到全范围。 */
.chart-chip {
  position: absolute; right: 24px; top: 42px;
  padding: 3px 9px; border-radius: 8px; font-size: 11px;
  background: rgba(10,15,31,0.85); border: 1px solid var(--line);
  color: var(--accent); cursor: pointer; user-select: none;
}
.chart-chip:hover { border-color: var(--accent); }

/* 图表浮动窗（演示讲到"看径向分布 / 截面密度"时把底部那张图放大到浮层）。
   ★ 刻意**不做模态**：不加 inset:0 的模糊遮罩，且整体 pointer-events:none ——
     浮窗之外的点击与滚轮会穿透到三维视图，这样才能"边看三维边看图"。
     关闭靠右上角 ✕ 或 Esc。
   ★ 靠右停靠而不是居中：三维视图在页面左侧，居中会把轨道整个盖住，
     "边看三维边看图"就无从谈起了。 */
.chart-overlay {
  position: fixed; inset: 0; z-index: 1300;
  display: none; align-items: center; justify-content: flex-end;
  pointer-events: none;
  padding: 14px 20px;
}
.chart-overlay.show { display: flex; }
/* ★ 第 12 条：智能体抽屉**也在右侧**，浮窗靠右停靠时两者必然重叠 ——
   学生一边听讲解一边看图，结果文字被图盖住。三件事一起做：
     ① 抽屉打开时（panel.js 会给 body 加 .agent-open）浮窗默认**让到左侧**，
        讲解与图各占一边；
     ② 浮窗可**拖到任意位置**（拖标题栏；一旦拖动就转为 fixed 定位，不再受停靠影响）；
     ③ 可**最小化**成一条标题栏（按钮在右上角）。 */
body.agent-open .chart-overlay { justify-content: flex-start; }
.chart-overlay-box.mini { height: auto; }
.chart-overlay-box.mini .chart-overlay-canvas { display: none; }
.chart-overlay-head { cursor: grab; touch-action: none; user-select: none; }
.chart-overlay-head.dragging { cursor: grabbing; }
.chart-overlay-box {
  pointer-events: auto;                     /* 盒子本体把点击收回来 */
  width: min(820px, 50vw); height: min(660px, 80vh);
  display: flex; flex-direction: column;
  background: var(--card, #151c33); border: 1px solid var(--line, #2a3558);
  border-radius: 14px; box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
  padding: 10px 14px 14px;
}
.chart-overlay-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
}
.chart-overlay-title { font-size: 14px; font-weight: 700; color: var(--text, #e6ecff); }
.chart-overlay-btns { display: flex; align-items: center; gap: 2px; }
.chart-overlay-x {
  border: none; background: none; color: var(--text-dim, #9aa7c6);
  font-size: 15px; cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.chart-overlay-x:hover { color: var(--text, #e6ecff); background: var(--active, #1c2540); }
/* 画布占满剩余高度。min-height:0 是必需的 —— 否则 flex 子项会被内容撑破，
   绘制函数按 clientWidth/clientHeight 取尺寸，撑破后会画到盒子外面 */
.chart-overlay-canvas { flex: 1; width: 100%; min-height: 0; display: block; border-radius: 8px; }
.chart { width: 100%; height: 168px; display: block; margin-top: 6px; border-radius: 8px; }
/* Θ/Φ 两张极坐标图并排画在**同一张**画布上（左 Θ、右 Φ，中间一个乘号）。
   同一张画布意味着只有一个 resize 路径、一次重绘 —— 比放两个 canvas 少一半的
   尺寸同步逻辑。高度比别的图高一些：两个极坐标图并排，各自的可视半径就只有
   卡片宽度的 1/4 上下，再矮就画不出可读的瓣形了。 */
#thetaPhiChart { height: 190px; }

/* ---------- 页脚 ---------- */
.foot { text-align: center; color: var(--text-dim); font-size: 12px; padding: 14px; }

/* ---------- 响应式 ---------- */
@media (max-width: 1024px) {
  .grid-main { grid-template-columns: 1fr; }
  .panel { order: 2; }
  .grid-charts { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .topbar { flex-direction: column; align-items: flex-start; gap: 8px; padding: 12px 16px; }
  .brand h1 { font-size: 17px; }
  .subtitle { display: none; }
  .layout { padding: 12px 12px 30px; }
  .card { padding: 12px; }
  .viewer-card { min-height: 0; }
  /* 高度仍交给 layout.js 算（移动端会读 visualViewport，能正确处理地址栏收放），
     这里只收紧保底高度，避免横屏时画布被压成一条缝 */
  .viewer { min-height: 200px; }
  .grid-charts { grid-template-columns: 1fr; }
  .chart { height: 190px; }
  .orbit-title { font-size: 19px; }
}
