/* ============================================================
   地球online —— Liquid Glass 视觉层
   ------------------------------------------------------------
   设计语言参考 macOS 的 Liquid Glass 材质，只取「材质与空间」，
   不取任何题材元素：没有天空、云、日月、天气图标、山川城市。

   三层结构（从下往上）
     1. 壁纸层  深空星野（固定的"桌面图片"）—— 不随主题改变明暗
     2. 材质层  所有承载文字的表面都是半透明磨砂玻璃：背景透过材质
                被模糊、被提亮，而不是被完全遮住
     3. 内容层  文字与控件

   主题只切换"材质"，不切换壁纸：
     浅色 = 明亮磨砂玻璃 + 深色文字
     深色 = 暗色玻璃     + 浅色文字
   压在壁纸上的大标题（.page-head）在两种主题下都用浅色 + 投影，
   因为壁纸恒定偏暗 —— 否则浅色主题下它会糊在背景里。

   ★ 三条不可回退的版面红线（PRD 附录 C）
     1. 课表固定 7 个日列（+ 时段列 = 8 列），不因为某天没课就少列
     2. 首页六宫格永远排满：3 / 2 / 1 列，超宽 6 列；禁止 4 列
     3. 课表格子里不显示 "1-2节 / 3-4节" 这类重复的节次小字
   课表的行高（104 / 208px）、列宽、sticky 表头是版面契约，
   本次视觉重构一律不动这些数值。
   ============================================================ */

/* ============================================================
   0. 设计令牌
   ============================================================ */

:root {
  /* —— 壁纸：浅色（具体渐变写在下面的 html 规则里）——
     深色主题的星野壁纸写在 html[data-theme="dark"] 里。
     星星只在深色主题出现：浅色底上白点等于看不见，硬画只会变成脏噪点。 */
  --wall-1: #e8ecf5;
  --wall-2: #e0e7f3;

  /* —— 材质：浅色（明亮磨砂玻璃）——
     浅色模式下的"玻璃感"不来自可见的模糊（白底上模糊不出来），
     而来自：底比材质暗一档 + 一圈清晰的内描边 + 真的看得见的投影。 */
  --glass-rail: rgba(255, 255, 255, .82);
  --glass: rgba(255, 255, 255, .78);
  --glass-2: rgba(255, 255, 255, .92);
  --glass-3: rgba(14, 20, 34, .055);
  --glass-hover: rgba(255, 255, 255, .94);
  --edge: rgba(255, 255, 255, .95); /* 材质上缘高光 */
  --edge-out: rgba(10, 16, 30, .13); /* 材质外描边 */
  --edge-strong: rgba(10, 16, 30, .20);
  --sep: rgba(10, 16, 30, .085); /* 分隔细线 */
  --seam: rgba(10, 16, 30, .16); /* 侧栏与内容之间那道竖线 */

  /* —— 文字 —— */
  --text: #0f1420;
  --text-dim: rgba(15, 20, 32, .64);
  --text-faint: rgba(15, 20, 32, .44);
  /* 压在壁纸上的文字：浅色壁纸 → 用深色字（深色主题里会翻成浅色） */
  --hero: rgba(15, 20, 32, .94);
  --hero-dim: rgba(15, 20, 32, .60);
  --hero-shadow: 0 1px 0 rgba(255, 255, 255, .70);
  --hero-warn: #9a6408;
  --hero-ok: #0f7a3c;
  --hero-danger: #bf3126;

  /* —— 语义色（对齐 macOS 系统色）—— */
  --accent: #0a68f5;
  --accent-2: #4a9bff;
  --accent-soft: rgba(10, 104, 245, .14);
  --accent-ring: rgba(10, 104, 245, .32);
  --danger: #d92b21;
  --danger-soft: rgba(217, 43, 33, .12);
  --warn: #b8720a;
  --warn-soft: rgba(184, 114, 10, .14);
  --ok: #12813f;
  --ok-soft: rgba(18, 129, 63, .14);

  /* —— 形状与尺寸 —— */
  --side-w: 178px; /* 侧栏宽度：改这一个数就能整体收放。
     下限由「周五 9月18日 · 第 1 教学周」这行决定 —— 它从 x=22 起、宽 137px，
     右边缘落在 159px，加上右侧内边距，低于约 175px 就会折成两行。 */
  --radius-xl: 26px;
  --radius-lg: 20px;
  --radius: 15px;
  --radius-sm: 10px;
  --radius-pill: 980px;

  /* —— 光影：三层递进的"高度"——
     浅色壁纸下, 投影是看得见的, 所以要真的给阴影; 深色主题另有一套
     (那里黑压黑看不见投影, 靠的是"比背景更亮的材质 + 上缘高光")。 */
  --lift-1: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 1px 2px rgba(12, 20, 38, .07), 0 10px 26px rgba(12, 20, 38, .12);
  --lift-2: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 3px 10px rgba(12, 20, 38, .11), 0 22px 48px rgba(12, 20, 38, .18);
  --lift-3: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 14px 34px rgba(12, 20, 38, .20), 0 54px 110px rgba(12, 20, 38, .26);
  --lift-press: inset 0 2px 6px rgba(12, 20, 38, .14);

  /* —— 动效：近似 macOS 的回弹曲线 —— */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --dur: .22s;

  --blur: 30px;
  --sat: 180%;

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text",
    "Segoe UI", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display",
    "Segoe UI Variable Display", "Segoe UI", "PingFang SC", "Microsoft YaHei",
    system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, "Courier New", monospace;

  /* 兼容旧变量名：万一别处还引用着，不至于解析不到 */
  --bg: var(--wall-2);
  --panel: var(--glass);
  --panel-2: var(--glass-3);
  --line: var(--sep);
  --line-strong: var(--edge-strong);
  --radius-old: 10px;
  --shadow: var(--lift-1);
}

[data-theme="dark"] {
  /* 深色材质 = 一层很淡的白（不是一层黑）——
     壁纸本身已经很暗，再叠深色只会变成"六块灰板"，玻璃就不存在了。 */
  --glass-rail: rgba(255, 255, 255, .055);
  --glass: rgba(255, 255, 255, .075);
  --glass-2: rgba(255, 255, 255, .115);
  --glass-3: rgba(0, 0, 0, .22); /* 内嵌表面：凹进去的槽，比材质更暗 */
  --glass-hover: rgba(255, 255, 255, .135);
  --edge: rgba(255, 255, 255, .24); /* 上缘高光 */
  --edge-out: rgba(255, 255, 255, .10); /* 一圈极淡的内描边 */
  --edge-strong: rgba(255, 255, 255, .30);
  --sep: rgba(255, 255, 255, .10);
  --seam: rgba(255, 255, 255, .22); /* 侧栏与内容之间那道竖线 */

  --text: #eef2f8;
  --text-dim: rgba(238, 242, 248, .70);
  --text-faint: rgba(238, 242, 248, .46);
  /* 深色壁纸（星野）→ 压在壁纸上的文字翻成浅色 */
  --hero: rgba(255, 255, 255, .97);
  --hero-dim: rgba(255, 255, 255, .58);
  --hero-shadow: 0 1px 2px rgba(0, 0, 0, .45), 0 8px 30px rgba(0, 0, 0, .35);
  --hero-warn: #ffd479;
  --hero-ok: #6ee7a0;
  --hero-danger: #ff9d94;

  /* 深色壁纸下的投影基本看不见, 高度靠"比背景更亮的材质 + 上缘高光" */
  --lift-1: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 2px 5px rgba(2, 4, 10, .22), 0 14px 34px rgba(2, 4, 10, .30);
  --lift-2: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 4px 12px rgba(2, 4, 10, .28), 0 26px 60px rgba(2, 4, 10, .40);
  --lift-3: inset 0 1px 0 var(--edge), inset 0 0 0 1px var(--edge-out),
    0 18px 44px rgba(2, 4, 10, .46), 0 60px 120px rgba(2, 4, 10, .55);
  --lift-press: inset 0 2px 6px rgba(2, 4, 10, .22);

  --accent: #5ea2ff;
  --accent-2: #8ec2ff;
  --accent-soft: rgba(94, 162, 255, .20);
  --accent-ring: rgba(94, 162, 255, .44);
  --danger: #ff6b60;
  --danger-soft: rgba(255, 107, 96, .18);
  --warn: #e8a94a;
  --warn-soft: rgba(232, 169, 74, .18);
  --ok: #4ed07f;
  --ok-soft: rgba(78, 208, 127, .18);
}

* { box-sizing: border-box; }

/* ============================================================
   1. 壁纸层：深空星野
   ------------------------------------------------------------
   星点用多层 radial-gradient 平铺而成，瓦片尺寸取互质的质数，
   避免看出网格。两层星野以不同速度极缓慢漂移 → 视差纵深。
   （固定定位的元素不参与滚动溢出，不会撑出横向滚动条。）
   ============================================================ */

/* 壁纸：浅色主题 = 干净的浅色渐变 + 几团极淡的冷色光晕 */
html {
  background-color: var(--wall-1);
  background-image:
    radial-gradient(70% 48% at 12% -6%, rgba(108, 152, 255, .44) 0%, rgba(108, 152, 255, 0) 62%),
    radial-gradient(58% 42% at 92% 4%, rgba(170, 142, 246, .34) 0%, rgba(170, 142, 246, 0) 60%),
    radial-gradient(56% 38% at 90% 106%, rgba(110, 190, 220, .24) 0%, rgba(110, 190, 220, 0) 62%),
    linear-gradient(168deg, #f1f5fc 0%, var(--wall-1) 46%, var(--wall-2) 100%);
  background-attachment: fixed;
}

/* 壁纸：深色主题 = 深空星野。
   几团弥散的光晕只提供色彩与纵深, 不构成任何具象形状。 */
html[data-theme="dark"] {
  background-color: #05070f;
  background-image:
    radial-gradient(78% 54% at 14% -8%, rgba(74, 116, 226, .46) 0%, rgba(74, 116, 226, 0) 60%),
    radial-gradient(64% 46% at 90% 2%, rgba(132, 92, 220, .32) 0%, rgba(132, 92, 220, 0) 58%),
    radial-gradient(70% 52% at 84% 96%, rgba(38, 112, 196, .30) 0%, rgba(38, 112, 196, 0) 60%),
    radial-gradient(110% 40% at 46% 112%, rgba(96, 146, 244, .22) 0%, rgba(96, 146, 244, 0) 62%),
    linear-gradient(180deg, #0b1226 0%, #070b16 44%, #04060d 100%);
}

body { background: transparent; }

/* 远景星尘：小而密，慢 */
body::before {
  content: "";
  position: fixed;
  inset: -14%;
  z-index: -3;
  pointer-events: none;
  background-image:
    radial-gradient(1.1px 1.1px at 8% 14%, rgba(255, 255, 255, .62), transparent),
    radial-gradient(1.1px 1.1px at 27% 6%, rgba(198, 220, 255, .55), transparent),
    radial-gradient(1.1px 1.1px at 46% 23%, rgba(255, 255, 255, .48), transparent),
    radial-gradient(1.1px 1.1px at 68% 11%, rgba(255, 255, 255, .58), transparent),
    radial-gradient(1.1px 1.1px at 88% 27%, rgba(210, 226, 255, .50), transparent),
    radial-gradient(1.1px 1.1px at 16% 52%, rgba(255, 255, 255, .44), transparent),
    radial-gradient(1.1px 1.1px at 39% 68%, rgba(255, 255, 255, .52), transparent),
    radial-gradient(1.1px 1.1px at 62% 49%, rgba(222, 234, 255, .46), transparent),
    radial-gradient(1.1px 1.1px at 91% 74%, rgba(255, 255, 255, .50), transparent),
    radial-gradient(1.1px 1.1px at 5% 88%, rgba(255, 255, 255, .42), transparent),
    radial-gradient(1.1px 1.1px at 74% 92%, rgba(206, 224, 255, .48), transparent);
  background-size: 397px 397px;
  background-repeat: repeat;
  animation: sh-drift-far 320s linear infinite;
}

/* 中景星点：略大略亮，快一点 */
body::after {
  content: "";
  position: fixed;
  inset: -14%;
  z-index: -2;
  pointer-events: none;
  background-image:
    /* 每颗亮星 = 一个小而实的星核 + 一圈很淡的柔光 */
    radial-gradient(1.9px 1.9px at 22% 33%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, 0) 72%),
    radial-gradient(9px 9px at 22% 33%, rgba(150, 190, 255, .13) 0%, rgba(150, 190, 255, 0) 70%),
    radial-gradient(1.7px 1.7px at 74% 16%, rgba(226, 238, 255, .88) 0%, rgba(226, 238, 255, 0) 72%),
    radial-gradient(8px 8px at 74% 16%, rgba(226, 238, 255, .11) 0%, rgba(226, 238, 255, 0) 70%),
    radial-gradient(2.2px 2.2px at 48% 62%, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 72%),
    radial-gradient(11px 11px at 48% 62%, rgba(255, 240, 220, .12) 0%, rgba(255, 240, 220, 0) 70%),
    radial-gradient(1.6px 1.6px at 88% 79%, rgba(255, 255, 255, .80) 0%, rgba(255, 255, 255, 0) 72%),
    radial-gradient(1.8px 1.8px at 9% 55%, rgba(214, 232, 255, .85) 0%, rgba(214, 232, 255, 0) 72%),
    radial-gradient(8px 8px at 9% 55%, rgba(180, 208, 255, .11) 0%, rgba(180, 208, 255, 0) 70%);
  background-size: 613px 613px;
  background-repeat: repeat;
  animation: sh-drift-near 240s linear infinite;
}

/* 环境光：顶部冷光 + 四周压暗（纯光影，无任何具象元素） */
#app::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(120% 64% at 50% -14%, rgba(120, 160, 255, .14) 0%, rgba(120, 160, 255, 0) 62%),
    radial-gradient(96% 48% at 50% 116%, rgba(90, 130, 230, .11) 0%, rgba(90, 130, 230, 0) 62%);
}

/* 少量亮星缓慢呼吸，让背景"活着"但不抢注意力 */
#app::after {
  content: "";
  position: fixed;
  inset: -14%;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(2.6px 2.6px at 31% 27%, rgba(255, 255, 255, .98) 0%, rgba(255, 255, 255, 0) 70%),
    radial-gradient(13px 13px at 31% 27%, rgba(178, 208, 255, .16) 0%, rgba(178, 208, 255, 0) 70%),
    radial-gradient(2.2px 2.2px at 67% 71%, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, 0) 70%),
    radial-gradient(11px 11px at 67% 71%, rgba(255, 236, 214, .13) 0%, rgba(255, 236, 214, 0) 70%),
    radial-gradient(2.8px 2.8px at 17% 84%, rgba(222, 234, 255, .96) 0%, rgba(222, 234, 255, 0) 70%),
    radial-gradient(14px 14px at 17% 84%, rgba(200, 220, 255, .15) 0%, rgba(200, 220, 255, 0) 70%);
  background-size: 733px 733px;
  background-repeat: repeat;
  animation: sh-twinkle 11s ease-in-out infinite;
}

@keyframes sh-drift-far {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-34px, -22px, 0); }
}
@keyframes sh-drift-near {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-72px, -48px, 0); }
}
@keyframes sh-twinkle {
  0%, 100% { opacity: .38; }
  50% { opacity: .92; }
}

/* 非首页：壁纸退到更远，避免和密集内容抢注意力 */
html:not([data-route="home"]) body::before { opacity: .55; }
html:not([data-route="home"]) body::after { opacity: .40; }
html:not([data-route="home"]) #app::after { opacity: .5; animation: none; }

/* 星星只在深色主题里出现。
   浅色壁纸下白点等于看不见，硬画成灰点只会变成脏噪点 —— 所以直接不画,
   顺带也省掉了三层的动画开销。 */
html:not([data-theme="dark"]) body::before,
html:not([data-theme="dark"]) body::after,
html:not([data-theme="dark"]) #app::after { display: none; }

/* ============================================================
   2. 基础排版
   ============================================================ */

body {
  margin: 0;
  padding: 0;
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, select, textarea { font: inherit; color: inherit; }

::selection { background: var(--accent-soft); }

:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* 滚动条也收进这套语言里 */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--edge-strong);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); background-clip: content-box; }

.boot { padding: 80px 0; text-align: center; color: var(--hero-dim); }

#app {
  display: flex;
  min-height: 100vh;
  align-items: stretch;
}

/* ============================================================
   3. 左侧导航：一块竖向的玻璃导轨
   ============================================================ */

.sidebar {
  width: var(--side-w);
  flex: 0 0 var(--side-w);
  background: var(--glass-rail);
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  box-shadow:
    inset -1px 0 0 var(--seam), /* 侧栏与内容的分界：单独一根看得见的竖线 */
    inset 0 1px 0 var(--edge),
    2px 0 24px rgba(3, 6, 14, .18);
  padding: 20px 14px 14px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

/* 右侧内边距故意留得比左侧小：
   「周五 9月18日 · 第 1 教学周」实测要 140px，侧栏 184px 时可用宽度正好卡在 140px，
   一点余量都没有 —— 字体渲染稍有差别就会折成两行。让出 6px 就稳了。 */
.brand { padding: 0 2px 16px 8px; box-shadow: inset 0 -1px 0 var(--sep); margin-bottom: 14px; }
.brand-name {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -.2px;
}
/* 顶行: 应用名 + 收起侧栏的按钮 */
.brand-row { display: flex; align-items: center; gap: 6px; }
.brand-row .brand-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.side-toggle {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.side-toggle:hover { background: var(--glass-hover); color: var(--text); }
.side-toggle:active { transform: scale(.9); }
.brand-date { margin-top: 4px; }
.brand-sub { font-size: 12px; color: var(--text-dim); line-height: 1.5; }
.save-flag {
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 4px;
  min-height: 15px;
  font-variant-numeric: tabular-nums;
  transition: color var(--dur) var(--ease);
}
.save-flag.saving { color: var(--warn); }
.save-flag.saved { color: var(--ok); }
.save-flag.error { color: var(--danger); }

.side-nav { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 18px; padding-top: 2px; }
.side-group-name {
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: .8px;
  padding: 0 10px 6px;
  font-weight: 600;
}
.side-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--text-dim);
  font-size: 14px;
  margin-bottom: 3px;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.side-item:hover {
  background: var(--glass-hover);
  color: var(--text);
  box-shadow: inset 0 1px 0 var(--edge), 0 1px 2px rgba(3, 6, 14, .10);
}
.side-item:active { transform: scale(.985); }
/* 选中项：一块被点亮的小胶囊（macOS 侧栏选中态） */
.side-item.active {
  background: linear-gradient(180deg, var(--accent-soft), var(--accent-soft));
  color: var(--accent);
  font-weight: 600;
  box-shadow:
    inset 0 0 0 1px var(--accent-ring),
    inset 0 1px 0 rgba(255, 255, 255, .35),
    0 2px 10px rgba(10, 104, 245, .18);
}
.side-icon { display: flex; align-items: center; flex: 0 0 auto; }
.side-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.side-foot {
  box-shadow: inset 0 1px 0 var(--sep);
  padding: 10px 10px 0;
  font-size: 11px;
  color: var(--text-faint);
  line-height: 1.7;
  font-variant-numeric: tabular-nums;
}

/* ---------------- 侧栏收起 / 展开 ---------------- */

/* 收起 = 用负外边距把整列让出去, 主区自动补位(不是盖住, 是真的让开)。
   让出的过程走 transition, 收起后再 visibility:hidden —— 这样收起后
   键盘 Tab 也不会跑到看不见的导航上。 */
@media (min-width: 861px) {
  .sidebar { transition: margin-left .3s var(--ease), visibility 0s linear 0s; }
  html[data-side="hidden"] .sidebar {
    margin-left: calc(-1 * var(--side-w));
    visibility: hidden;
    transition: margin-left .3s var(--ease), visibility 0s linear .3s;
  }
}

/* 收起后贴在屏幕左边的小标签: 点一下把侧栏叫回来 */
.side-tab {
  position: fixed;
  left: 0;
  top: 46%;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 13px 7px 13px 6px;
  border: none;
  cursor: pointer;
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--glass-hover);
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  box-shadow: var(--lift-2);
  color: var(--text-dim);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-50%) translateX(-100%);
  transition: transform .3s var(--ease), opacity .2s var(--ease), color var(--dur) var(--ease);
}
html[data-side="hidden"] .side-tab {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(-50%) translateX(0);
}
.side-tab:hover { color: var(--accent); }
.side-tab-text { writing-mode: vertical-rl; font-size: 11px; letter-spacing: .5px; }

/* ============================================================
   4. 主区
   ============================================================ */

.main {
  flex: 1;
  min-width: 0;
  max-width: 1280px;
  padding: 30px 30px 80px;
}

/* 宽屏: 内容区跟着撑开, 不留一大片空白 */
@media (min-width: 1500px) {
  .main { max-width: none; padding: 34px 44px 90px; }
}
/* 超宽屏: 六格排成一排 6 列 —— 不能排成 4 列, 那样第二行会空出 2 格 */
@media (min-width: 1900px) {
  .home-grid { grid-template-columns: repeat(6, 1fr); }
  .home-card { min-height: 236px; }
}

/* 压在壁纸上的大标题：浅色 + 投影（两种主题都如此，否则读不出来） */
.page-head { margin-bottom: 22px; }
.page-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -.6px;
  color: var(--hero);
  text-shadow: var(--hero-shadow);
}
.page-desc {
  margin: 6px 0 0;
  color: var(--hero-dim);
  font-size: 13.5px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
}
/* 侧栏收起时, 保存状态会挪到顶栏(压在壁纸上)。
   这一处的颜色要按"壁纸是深的"来配, 不能用主题里的深绿/深红。 */
.page-head .save-flag {
  font-size: 13.5px;
  color: var(--hero-dim);
  margin-top: 3px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
}
.page-head .save-flag.saving { color: var(--hero-warn); }
.page-head .save-flag.saved { color: var(--hero-ok); }
.page-head .save-flag.error { color: var(--hero-danger); }

/* ============================================================
   5. 通用组件
   ============================================================ */

.panel {
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-1);
  padding: 16px 18px;
  margin-bottom: 16px;
}

.panel-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.panel-title { font-size: 15px; font-weight: 700; letter-spacing: -.1px; }
.panel-title .count { color: var(--text-faint); font-weight: 400; font-size: 13px; margin-left: 4px; }
.panel-head .spacer { flex: 1; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 820px) { .grid-2 { grid-template-columns: 1fr; } }

/* —— 按钮：胶囊形玻璃 + 上缘高光 —— */
.btn {
  border: none;
  background: var(--glass-2);
  border-radius: var(--radius-pill);
  padding: 6px 15px;
  cursor: pointer;
  white-space: nowrap;
  color: var(--text);
  font-size: 13.5px;
  box-shadow:
    inset 0 0 0 1px var(--edge-out),
    inset 0 1px 0 var(--edge),
    0 1px 2px rgba(3, 6, 14, .14);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover {
  background: var(--glass-hover);
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 1px var(--accent-ring),
    inset 0 1px 0 var(--edge),
    0 4px 14px rgba(3, 6, 14, .18);
}
.btn:active { transform: translateY(0) scale(.97); box-shadow: inset 0 2px 5px rgba(3, 6, 14, .18); }
.btn.primary {
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  color: #fff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .45),
    0 2px 10px var(--accent-ring);
}
.btn.primary:hover { filter: brightness(1.06); color: #fff; }
.btn.ghost {
  background: transparent;
  color: var(--text-dim);
  box-shadow: none;
}
.btn.ghost:hover { background: var(--glass-hover); color: var(--text); box-shadow: inset 0 0 0 1px var(--edge-out); }
.btn.danger { color: var(--danger); background: var(--danger-soft); box-shadow: inset 0 0 0 1px var(--danger-soft); }
.btn.danger:hover {
  background: var(--danger-soft);
  color: var(--danger);
  box-shadow: inset 0 0 0 1px var(--danger), 0 3px 12px rgba(217, 43, 33, .18);
}
.btn.small { padding: 3px 10px; font-size: 12px; }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn:disabled:hover { box-shadow: inset 0 0 0 1px var(--edge-out), inset 0 1px 0 var(--edge); background: var(--glass-2); }

/* —— 输入控件：向内凹的玻璃 —— */
.input, .select, .textarea {
  background: var(--glass-3);
  border: none;
  border-radius: var(--radius-sm);
  padding: 7px 11px;
  width: 100%;
  color: var(--text);
  box-shadow:
    inset 0 0 0 1px var(--edge-out),
    inset 0 1px 2px rgba(3, 6, 14, .10);
  transition: box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  background: var(--glass-2);
  box-shadow:
    inset 0 0 0 1px var(--accent),
    0 0 0 3.5px var(--accent-ring);
}
.textarea { resize: vertical; min-height: 90px; line-height: 1.6; }
select.select { cursor: pointer; }

.row { display: flex; gap: 8px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.row.grow > * { min-width: 0; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field > label { font-size: 12px; color: var(--text-dim); }
.field-narrow { width: 116px; }

.empty { color: var(--text-faint); padding: 16px 0; text-align: center; }
.hint { color: var(--text-faint); font-size: 12px; }
.muted { color: var(--text-dim); }
.grow { flex: 1; min-width: 0; }
.count { color: var(--text-faint); font-weight: 400; font-size: 13px; font-variant-numeric: tabular-nums; }

/* 截止时间按钮: 看起来像普通文字, 但可以点 */
.due-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--text-dim);
  cursor: pointer;
  border-bottom: 1px dashed var(--edge-strong);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.due-btn:hover { color: var(--accent); border-bottom-color: var(--accent); }

.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--glass-3);
  box-shadow: inset 0 0 0 1px var(--edge-out);
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
}
.tag.accent { background: var(--accent-soft); box-shadow: none; color: var(--accent); font-weight: 600; }
.tag.tiny { font-size: 11px; padding: 1px 6px; }

/* 分段控件：标签页必须坐在材质上。
   如果让它直接压在壁纸上，浅色主题会用深色文字去配深色背景 —— 直接看不见。 */
.tabs {
  display: flex;
  width: fit-content;
  gap: 4px;
  padding: 4px;
  border-radius: var(--radius-pill);
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  box-shadow: var(--lift-1);
  margin-bottom: 16px;
}
.tabs button {
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  padding: 7px 18px;
  cursor: pointer;
  color: var(--text-dim);
  font-size: 13.5px;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.tabs button:hover { background: var(--glass-hover); color: var(--text); }
.tabs button.active {
  background: var(--glass-2);
  color: var(--accent);
  font-weight: 600;
  box-shadow: inset 0 1px 0 var(--edge), 0 1px 4px rgba(2, 4, 10, .24);
}

/* ============================================================
   6. 首页六宫格
   ============================================================ */

.home-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
@media (max-width: 1000px) { .home-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .home-grid { grid-template-columns: 1fr; } }

.home-card {
  position: relative;
  background: linear-gradient(168deg, var(--glass-hover) 0%, var(--glass) 46%, var(--glass) 100%);
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-1);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  min-height: 196px;
  max-height: 306px;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
/* 斜向镜面高光：Liquid Glass 的标志性细节 */
.home-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(255, 255, 255, .30) 0%, rgba(255, 255, 255, .06) 26%, rgba(255, 255, 255, 0) 54%);
  opacity: .85;
}
.home-card > * { position: relative; z-index: 1; }

.home-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--lift-2);
}
.home-card:active { transform: translateY(-1px) scale(.994); }
.home-card:hover .card-zoom { opacity: 1; }

/* 卡片里的输入控件保持"可输入"的光标, 提示这里不是点开放大 */
.card-body .checkbox { cursor: pointer; }
.card-body .x-btn { cursor: pointer; }
.card-body .input, .card-body .input-flat, .card-body .scratch { cursor: text; }

.card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  flex: 0 0 auto;
  cursor: pointer;
  margin-left: -6px;
  margin-right: -6px;
  padding: 3px 6px;
  border-radius: var(--radius-sm);
  transition: background var(--dur) var(--ease);
}
.card-head:hover { background: var(--glass-hover); }
.card-title { font-size: 15px; font-weight: 700; letter-spacing: -.1px; }
.card-zoom {
  color: var(--accent);
  opacity: .35;
  font-size: 14px;
  transition: opacity var(--dur) var(--ease);
}
.card-body { flex: 1; overflow-y: auto; overflow-x: hidden; min-height: 0; }
.card-foot { margin-top: 8px; font-size: 12px; color: var(--text-faint); flex: 0 0 auto; }
.card-foot-row { display: flex; align-items: center; gap: 8px; }
.card-foot-row .hint { flex: 1; }
.card-empty { color: var(--text-faint); padding: 12px 0; font-size: 13px; }
.card-empty.ok { color: var(--ok); }
.card-more { color: var(--text-faint); font-size: 12px; padding-top: 4px; }
.card-link { color: var(--accent); text-decoration: none; }
.card-link:hover { text-decoration: underline; }

/* 格子内的一行: 紧凑, 不做大间距 */
.line {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 0;
  box-shadow: inset 0 -1px 0 var(--sep);
  font-size: 13px;
  min-width: 0;
}
.home-card .line:last-child { box-shadow: none; }
.line-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--edge-strong);
  flex: 0 0 auto;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .10);
}
.line-dot.soon { background: var(--warn); }
.line-dot.overdue { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }
.line-main { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.line-sub { color: var(--text-dim); font-size: 11px; white-space: nowrap; flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.line-grow { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; }
.line.media { gap: 8px; }
.line.quick { padding: 2px 0 7px; }
.input-flat {
  border: none;
  background: transparent;
  padding: 5px 0;
  box-shadow: none;
  border-radius: 0;
}
.input-flat:focus {
  outline: none;
  background: transparent;
  box-shadow: inset 0 -1px 0 var(--accent), 0 0 0 0 transparent;
}
.x-btn {
  background: none;
  border: none;
  color: var(--text-faint);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 0 5px;
  border-radius: 50%;
  flex: 0 0 auto;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.x-btn:hover { color: var(--danger); background: var(--danger-soft); }

/* 课表格子里的课表行 */
.sched-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 0;
  box-shadow: inset 0 -1px 0 var(--sep);
  font-size: 13px;
  min-width: 0;
}
.sched-line:last-child { box-shadow: none; }
.sched-line.now {
  background: var(--accent-soft);
  margin: 0 -7px;
  padding-left: 7px;
  padding-right: 7px;
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 1px var(--accent-ring);
}
.sched-line.dim { opacity: .48; }
.sched-period {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--glass-3);
  border-radius: 6px;
  padding: 1px 6px;
  min-width: 28px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.sched-line.now .sched-period { background: var(--accent); color: #fff; }
.sched-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.sched-meta { color: var(--text-dim); font-size: 11px; white-space: nowrap; flex: 0 0 auto; }

.home-card .scratch { flex: 1; min-height: 96px; margin: 0; }
.progress.tiny { height: 5px; flex: 0 0 72px; }

/* ============================================================
   7. 放大视图（浮层）
   ============================================================ */

html.zoom-open { overflow: hidden; }

.zoom-mask {
  position: fixed;
  inset: 0;
  background: rgba(6, 9, 18, .42);
  backdrop-filter: blur(22px) saturate(140%);
  -webkit-backdrop-filter: blur(22px) saturate(140%);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 26px;
}
.zoom-mask.show { display: flex; animation: sh-fade-in .2s var(--ease); }

.zoom-panel {
  position: relative;
  background: var(--glass-2);
  backdrop-filter: blur(40px) saturate(var(--sat));
  -webkit-backdrop-filter: blur(40px) saturate(var(--sat));
  border-radius: var(--radius-xl);
  box-shadow: var(--lift-3);
  width: min(1100px, 100%);
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: sh-sheet-in .32s var(--ease);
}
.zoom-panel::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(140deg, rgba(255, 255, 255, .22) 0%, rgba(255, 255, 255, 0) 44%);
}
.zoom-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 20px;
  box-shadow: inset 0 -1px 0 var(--sep);
  flex: 0 0 auto;
  position: relative;
  z-index: 1;
}
.zoom-title { font-family: var(--font-display); font-size: 19px; font-weight: 700; letter-spacing: -.3px; }
.zoom-body { padding: 18px 20px; overflow: auto; flex: 1; min-height: 0; position: relative; z-index: 1; }
.zoom-scratch { min-height: 380px; font-size: 14px; }
.zoom-section-title {
  font-size: 11.5px;
  color: var(--text-faint);
  margin: 16px 0 6px;
  letter-spacing: .6px;
  font-weight: 700;
  text-transform: uppercase;
}
.zoom-section-title:first-child { margin-top: 0; }

@keyframes sh-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes sh-sheet-in {
  from { opacity: 0; transform: translateY(14px) scale(.968); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* ============================================================
   8. 列表条目
   ============================================================ */

.list { display: flex; flex-direction: column; }
.item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px;
  box-shadow: inset 0 -1px 0 var(--sep);
  transition: background var(--dur) var(--ease);
}
.item:last-child { box-shadow: none; }
.item .grow { flex: 1; min-width: 0; }
.item .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item.done .title { text-decoration: line-through; color: var(--text-faint); }
.item .sub { font-size: 12px; color: var(--text-dim); }

/* 自绘复选框：原生控件的样子会立刻破坏这套材质 */
.checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border-radius: 6px;
  background: var(--glass-3);
  box-shadow:
    inset 0 0 0 1px var(--edge-strong),
    inset 0 1px 2px rgba(3, 6, 14, .10);
  cursor: pointer;
  position: relative;
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.checkbox:hover { box-shadow: inset 0 0 0 1px var(--accent), inset 0 1px 2px rgba(3, 6, 14, .10); }
.checkbox:active { transform: scale(.92); }
.checkbox:checked {
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .40),
    0 2px 8px var(--accent-ring);
}
.checkbox:checked::after {
  content: "";
  position: absolute;
  left: 5.5px;
  top: 2px;
  width: 5px;
  height: 9.5px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}

/* ============================================================
   9. 首页时段卡片
   ============================================================ */

.period-card {
  border-radius: var(--radius);
  padding: 10px 13px;
  background: var(--glass-3);
  box-shadow: inset 0 0 0 1px var(--edge-out);
  min-width: 156px;
  transition: box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.period-card.now {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-ring), 0 4px 18px var(--accent-ring);
}
.period-card.past { opacity: .48; }
.period-card .p-no { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.period-card.now .p-no { color: var(--accent); font-weight: 700; }
.period-card .p-name { font-weight: 600; }
.period-card .p-meta { font-size: 12px; color: var(--text-dim); }

.due-today { color: var(--danger); font-weight: 600; }
.due-soon { color: var(--warn); }

/* ============================================================
   10. 签到
   ============================================================ */

.checkin-grid { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 8px; }
.game-col {
  border-radius: var(--radius);
  padding: 12px;
  min-width: 138px;
  background: var(--glass-3);
  box-shadow: inset 0 0 0 1px var(--edge-out);
}
.game-col .g-name { font-weight: 600; margin-bottom: 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.day-cells { display: flex; gap: 5px; margin-bottom: 9px; }
.day-cell {
  width: 31px;
  height: 36px;
  border: none;
  border-radius: 9px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 11px;
  color: var(--text-faint);
  background: var(--glass-2);
  box-shadow: inset 0 0 0 1px var(--edge-out), inset 0 1px 0 var(--edge);
  user-select: none;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.day-cell:hover { transform: translateY(-1px); box-shadow: inset 0 0 0 1px var(--accent-ring), 0 3px 10px rgba(3, 6, 14, .16); }
.day-cell:active { transform: scale(.94); }
.day-cell.signed {
  background: linear-gradient(180deg, color-mix(in srgb, var(--ok) 26%, transparent), var(--ok-soft));
  color: var(--ok);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--ok), inset 0 1px 0 rgba(255, 255, 255, .30), 0 2px 10px var(--ok-soft);
}
.day-cell.backfilled {
  background: linear-gradient(180deg, color-mix(in srgb, var(--warn) 26%, transparent), var(--warn-soft));
  color: var(--warn);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--warn), inset 0 1px 0 rgba(255, 255, 255, .28), 0 2px 10px var(--warn-soft);
}
.day-cell.today { box-shadow: inset 0 0 0 2px var(--accent), 0 2px 10px var(--accent-ring); }
.day-cell .d-num { font-size: 12px; font-variant-numeric: tabular-nums; }
.streak { font-size: 12px; color: var(--text-dim); }
.streak b { color: var(--text); font-size: 14px; font-variant-numeric: tabular-nums; }

/* ============================================================
   11. 进度条
   ============================================================ */

.progress {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--glass-3);
  box-shadow: inset 0 1px 2px rgba(3, 6, 14, .14);
  overflow: hidden;
  flex: 1;
  min-width: 60px;
}
.progress > i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 8px var(--accent-ring);
  transition: width .35s var(--ease);
}
.progress > i.full { background: linear-gradient(90deg, var(--ok), color-mix(in srgb, var(--ok) 60%, #fff)); box-shadow: 0 0 8px var(--ok-soft); }

/* ============================================================
   12. 课表
   ------------------------------------------------------------
   ★ 几何契约（不要动）：7 个日列 + 时段列 = 8 列；行高 104 / 208px；
     min-width 860px；sticky 表头。这里只换成玻璃质感。
   ============================================================ */

.timetable-wrap { overflow-x: auto; border-radius: var(--radius); }
.timetable {
  border-collapse: collapse;
  width: 100%;
  min-width: 860px;
  table-layout: fixed;
  background: transparent;
}
/* 六行一样高: 行高写死, 格子里内容多了也不许把行撑高(超出部分裁掉) */
.timetable tbody tr { height: 104px; }
.timetable tbody td { height: 104px; max-height: 104px; overflow: hidden; }
/* 分组模式: 上午/下午/晚上各一行, 行高给足 */
.timetable tbody tr.tt-row-group { height: 208px; }
.timetable tbody tr.tt-row-group > td { height: 208px; max-height: 208px; }

.timetable th, .timetable td {
  border: none;
  padding: 0;
  vertical-align: top;
  box-shadow: inset -1px -1px 0 var(--sep);
}
.timetable th {
  background: var(--glass-2);
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  padding: 8px 4px;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  position: sticky;
  top: 0;
  z-index: 2;
  box-shadow: inset -1px 0 0 var(--sep), inset 0 -1px 0 var(--edge-out);
}
.timetable th .th-day { display: block; }
.timetable th .th-date { display: block; font-size: 11px; color: var(--text-faint); font-weight: 400; margin-top: 1px; font-variant-numeric: tabular-nums; }
.timetable th.today { background: var(--accent-soft); color: var(--accent); }
.timetable th.today .th-date { color: var(--accent); }
.timetable th.weekend { background: var(--glass-3); color: var(--text-dim); }
.timetable td.weekend .tt-slot { background: var(--glass-3); }
.timetable th.tt-corner { width: 78px; background: var(--glass-3); font-weight: 600; color: var(--text-dim); }

/* 上午 / 下午 / 晚上: 第一列整个给这个标签(竖排) */
.timetable td.tt-group {
  width: 46px;
  background: var(--glass-3);
  text-align: center;
  vertical-align: middle;
  color: var(--text-dim);
}
.tt-group-text {
  writing-mode: vertical-rl;
  font-size: 15px;
  letter-spacing: 6px;
  font-weight: 600;
}

/* 分组模式: 一格里左上角的小节次标注(如 1-2节) */
.slot-period {
  display: block;
  font-size: 10px;
  color: var(--text-faint);
  line-height: 1.2;
  margin-bottom: 2px;
}

.timetable td.period-no {
  width: 40px;
  text-align: center;
  background: var(--glass-3);
  color: var(--text-dim);
  font-size: 12px;
  padding: 6px 0;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}

.timetable td { vertical-align: top; }
.timetable td > .tt-slot { height: 104px; max-height: 104px; overflow: hidden; }

/* "上午/下午/晚上各一大格"模式: 一个格子里按两节分段(1-2 / 3-4), 视觉上还是一整块 */
.tt-cell-group {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 104px;
}
.tt-cell-group > .tt-slot {
  flex: 1;
  height: auto;
  min-height: 0;
  max-height: none;
  overflow: hidden;
  box-shadow: inset 0 -1px 0 var(--sep);
}
.tt-cell-group > .tt-slot:last-child { box-shadow: none; }
.timetable tr.tt-row-group > td { height: 208px; }
.timetable tr.tt-row-group > td > .tt-cell-group { height: 208px; }
.timetable td.group-periods {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  font-size: 11px;
  color: var(--text-faint);
  padding: 0;
  font-variant-numeric: tabular-nums;
}
.timetable td.group-periods > span { display: block; }

.tt-slot {
  padding: 4px 5px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 5px;
  position: relative;
  transition: background var(--dur) var(--ease);
}
.tt-slot:hover { background: var(--accent-soft); }

/* 合并后一格里左上角的节次提示(如 1-2) */
.period-no-inline {
  position: absolute;
  top: 3px;
  left: 5px;
  font-size: 10px;
  color: var(--text-faint);
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.tt-slot > .tt-course { margin-top: 12px; }

.timetable td.period-no.merged { font-size: 11px; color: var(--text-faint); }

/* 单元格里的课: 模仿教务系统课表的密度, 三行 = 课程名 / 节次·周次 / 地点 */
.tt-course {
  border-radius: 9px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 16%, transparent), var(--accent-soft));
  box-shadow:
    inset 0 0 0 1px var(--accent-ring),
    inset 3px 0 0 var(--accent),
    inset 0 1px 0 rgba(255, 255, 255, .22);
  padding: 4px 6px 5px;
  font-size: 12px;
  line-height: 1.3;
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow: hidden;
  max-height: 96px;
}
.tt-course .c-name {
  font-weight: 700;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.tt-course .c-meta { color: var(--text-dim); font-size: 11px; }
.tt-course .c-loc { color: var(--text-dim); font-size: 11px; overflow-wrap: anywhere; }
.tt-course .c-teacher { color: var(--text-dim); font-size: 11px; overflow-wrap: anywhere; }
.tt-course.extra {
  background: linear-gradient(180deg, color-mix(in srgb, var(--warn) 18%, transparent), var(--warn-soft));
  box-shadow:
    inset 0 0 0 1px var(--warn),
    inset 3px 0 0 var(--warn),
    inset 0 1px 0 rgba(255, 255, 255, .22);
}
.tt-course.cancelled {
  background: var(--glass-3);
  box-shadow: inset 0 0 0 1px var(--sep), inset 3px 0 0 var(--edge-strong);
  opacity: .72;
}
.tt-course.cancelled .c-name { text-decoration: line-through; color: var(--text-dim); }

.tt-legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 12px;
  font-size: 12px;
  color: var(--text-dim);
}
.tt-legend .swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  margin-right: 6px;
  vertical-align: middle;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .25);
}

.week-picker { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.week-cell {
  width: 36px;
  height: 30px;
  border: none;
  border-radius: 9px;
  background: var(--glass-2);
  cursor: pointer;
  font-size: 12px;
  color: var(--text-dim);
  box-shadow: inset 0 0 0 1px var(--edge-out), inset 0 1px 0 var(--edge);
  font-variant-numeric: tabular-nums;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.week-cell:hover { box-shadow: inset 0 0 0 1px var(--accent), 0 3px 10px rgba(3, 6, 14, .16); transform: translateY(-1px); }
.week-cell.on {
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  color: #fff;
  font-weight: 600;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .40), 0 3px 12px var(--accent-ring);
}

.editor {
  border-radius: var(--radius-lg);
  background: var(--glass-2);
  box-shadow: inset 0 0 0 1px var(--accent-ring), var(--lift-2);
  padding: 16px;
  margin-bottom: 16px;
}
.editor h3 { margin: 0 0 12px; font-size: 14px; letter-spacing: -.1px; }
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 14px; }

/* ============================================================
   13. 备忘
   ============================================================ */

.scratch {
  min-height: 150px;
  background: var(--glass-3);
  font-family: var(--mono);
  font-size: 13px;
}

.note-add { display: flex; gap: 8px; margin-bottom: 12px; }

/* ============================================================
   14. 设置 / 数据
   ============================================================ */

.kv { display: grid; grid-template-columns: 130px 1fr; gap: 5px 14px; font-size: 13px; }
.kv dt { color: var(--text-dim); }
.kv dd { margin: 0; word-break: break-all; }

/* ============================================================
   15. 提示条
   ============================================================ */

.toast {
  position: fixed;
  left: 50%;
  bottom: 30px;
  transform: translate(-50%, 12px) scale(.96);
  background: var(--glass-2);
  backdrop-filter: blur(30px) saturate(var(--sat));
  -webkit-backdrop-filter: blur(30px) saturate(var(--sat));
  color: var(--text);
  padding: 10px 20px;
  border-radius: var(--radius-pill);
  box-shadow: var(--lift-2);
  z-index: 100;
  opacity: 0;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  pointer-events: none;
  max-width: 80vw;
  font-size: 13.5px;
}
.toast.show { opacity: 1; transform: translate(-50%, 0) scale(1); }
.toast.error {
  background: linear-gradient(180deg, color-mix(in srgb, var(--danger) 90%, #fff), var(--danger));
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 12px 34px rgba(217, 43, 33, .34);
}

.warn-box {
  background: var(--warn-soft);
  border-radius: var(--radius);
  box-shadow: inset 0 0 0 1px var(--warn), inset 0 1px 0 rgba(255, 255, 255, .20);
  padding: 12px 14px;
  margin-bottom: 14px;
  font-size: 13px;
}

/* ============================================================
   16. 窄屏：侧栏变成顶部横排
   ============================================================ */

@media (max-width: 860px) {
  #app { flex-direction: column; }
  .sidebar {
    width: auto;
    flex: 0 0 auto;
    height: auto;
    position: static;
    box-shadow: inset 0 -1px 0 var(--edge-out), 0 2px 18px rgba(3, 6, 14, .20);
  }
  .side-nav { flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .side-group { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
  .side-group-name { display: none; }
  .side-foot { display: none; }
  /* 窄屏下侧栏本来就是顶部横排, 没有"收起"这回事 */
  .side-toggle, .side-tab { display: none; }
  .main { padding: 20px 16px 70px; }
  .page-title { font-size: 26px; }
  :root { --blur: 22px; }
  .zoom-mask { padding: 12px; }
}

/* ============================================================
   17. 尊重"减少动态效果"的系统设置
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  body::before, body::after, #app::after { animation: none; }
  .zoom-panel, .zoom-mask.show { animation: none; }
  * { transition-duration: .01ms !important; }
}

/* ============================================================
   18. 顶部横幅: 安装引导 / 别删图标 / 导出提醒 / 有新版本
   ------------------------------------------------------------
   只在手机上出现(PC 版 pwa.notices() 返回空数组, 一条都不渲染)。
   颜色用显式 rgba, 不依赖主题变量 —— 深浅两套背景上都要看得清。
   ============================================================ */

.notice-bar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

.notice {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 8px 12px;
  padding: 11px 13px;
  border-radius: 12px;
  font-size: 13.5px;
  line-height: 1.65;
  border: 1px solid rgba(148, 163, 184, .38);
  background: rgba(148, 163, 184, .14);
}

.notice.warn {
  border-color: rgba(245, 158, 11, .50);
  background: rgba(245, 158, 11, .13);
}

.notice.info {
  border-color: rgba(56, 189, 248, .50);
  background: rgba(56, 189, 248, .13);
}

.notice-text { flex: 1 1 220px; min-width: 0; }

.notice-btn {
  flex: 0 0 auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 13px;
  border-radius: 9px;
  border: 1px solid rgba(148, 163, 184, .55);
  background: rgba(255, 255, 255, .16);
  color: inherit;
  font-size: 13px;
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
}

.notice-btn:hover { background: rgba(255, 255, 255, .28); }
[data-theme="light"] .notice-btn { background: rgba(255, 255, 255, .70); }
[data-theme="light"] .notice-btn:hover { background: rgba(255, 255, 255, .95); }

/* ============================================================
   19. 手机布局（≤860px，按实测视口 375 调）
   ------------------------------------------------------------
   桌面端的 DOM 结构一行不动, 全部靠媒体查询重排 —— 否则
   verify-ui-headless / verify-browser 那 59 项断言会连带失效。

   这一段的规则写在最后, 所以会盖掉第 16 节那个 860px 断点。
   改完必须跑: bun verify-phone.mjs <端口> 375 --shots
   ============================================================ */

@media (max-width: 860px) {
  /* ---- 导航: 从"顶部横排三行"改成"底部标签栏" ----
     顶部那个三行导航实测吃掉约 380px, 手机上太浪费。 */
  .sidebar {
    position: fixed;
    top: auto;            /* 基础样式里有 top:0, 不盖掉的话它会跑到屏幕顶部 */
    left: 0; right: 0; bottom: 0;
    z-index: 40;
    width: auto;
    height: auto;
    padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
    border-radius: 0;
    box-shadow: 0 -2px 18px rgba(3, 6, 14, .22);
  }
  .brand, .side-foot { display: none; }
  .side-nav {
    flex: 0 0 auto;
    height: auto;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 2px;
    padding: 0;
    overflow: visible;
  }
  /* 分组只是逻辑概念, 手机上五格排一行, 不分行 */
  .side-group { display: contents; }
  .side-group-name { display: none; }
  .side-item {
    flex: 1 1 0;
    min-width: 0;
    min-height: 52px;
    max-height: 56px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 6px 2px;
    margin: 0;
    font-size: 11px;
  }
  .side-label { font-size: 11px; max-width: 100%; }
  .side-toggle, .side-tab { display: none; }
  /* 底部给标签栏让位, 否则最后一行会被压住 */
  .main { padding: 14px 12px calc(78px + env(safe-area-inset-bottom)); }
  /* 顶部也要让开: iOS 独立窗口 + status-bar-style:black-translucent 时,
     网页会铺到状态栏底下(这正是不出现地址栏的全屏效果), 但安全区得自己让,
     否则第一条横幅的顶部会被状态栏压住 —— 2026-09-20 真机截图发现的。
     env() 在普通浏览器里是 0, 不影响 PC。 */
  #app { padding-top: env(safe-area-inset-top); }
  :root { --blur: 22px; }

  /* 顶部的应用名(只在手机上出现), 居中。跟着一起让开安全区。 */
  .phone-head {
    display: flex;
    justify-content: center;
    align-items: baseline;
    padding: 4px 0 12px;
  }
  .phone-title {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: .5px;
    text-align: center;
  }

  /* ---- 首页卡片: 不再硬留最小高度; 一行内容不许撑破卡片 ----
     .home-card 的 min-height:196px 在手机上就是每张卡下面一大片空白;
     .line-sub 是 flex:0 0 auto + nowrap, 永远不缩, 是首页溢出的元凶。 */
  .home-grid { gap: 10px; }
  .home-card { min-height: 0; max-height: none; padding: 12px 13px; }
  .card-empty { padding: 8px 0; }

  .line { flex-wrap: wrap; row-gap: 2px; }
  .line-sub { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .sched-line { flex-wrap: wrap; }
  .sched-meta { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

  /* ---- 触摸目标: 手机上小于 40px 很难点中（Apple HIG 建议 44）---- */
  .btn { min-height: 44px; padding: 11px 17px; }
  .btn.small, .btn.ghost.small { min-height: 38px; padding: 9px 13px; }
  .input, .select { min-height: 42px; }
  .checkbox { width: 24px; height: 24px; }
  .x-btn { width: 40px; height: 40px; }
  /* 首页卡片的标题行本身就是"点开看详情"的按钮, 也要够高 */
  .card-head { min-height: 40px; margin-bottom: 4px; }
  /* 课表页/游戏页顶部那排 课表|作业 之类的页签 */
  .tabs button, .tabs .tab { min-height: 40px; }
  /* 卡片里的纯文字链接("去设置 →")也要够高, 不然手指点不中 */
  .card-link { display: inline-flex; align-items: center; min-height: 36px; padding: 0 2px; }

  /* ---- 面板留白收一收, 给内容让宽度 ---- */
  .panel { padding: 12px 13px; }

  /* 窄屏上不要把标题和说明挤成"竖排一个字一行"。
     .panel-head / .row 都是 flex, 默认不换行, 宽度不够时子元素会被压扁。 */
  .panel-head { flex-wrap: wrap; row-gap: 6px; }
  .panel-title { flex: 0 0 auto; white-space: nowrap; }
  .panel-head .spacer { display: none; }
  .row { flex-wrap: wrap; row-gap: 6px; }

  /* ---- 课表 ----
     1) 首列(时段)固定住, 横向滚动时还知道看的是哪一节
     2) 行高改成自适应 —— 写死高度 + overflow:hidden 正是 PRD 附录 B-3
        那条"内容被裁"的成因, 手机上顺手按自适应来。
        注意选择器要和被覆盖的那几条一样具体, 否则盖不住。 */
  .timetable th.tt-corner,
  .timetable td.tt-group { position: sticky; left: 0; z-index: 2; }
  .timetable th.tt-corner { z-index: 3; }
  .timetable th { min-width: 92px; }
  .timetable th.tt-corner, .timetable td.tt-group { min-width: 46px; }

  .timetable tbody tr,
  .timetable tbody td,
  .timetable tbody tr.tt-row-group,
  .timetable tbody tr.tt-row-group > td,
  .timetable tr.tt-row-group > td,
  .timetable tr.tt-row-group > td > .tt-cell-group,
  .timetable td > .tt-slot { height: auto; max-height: none; }
  .timetable td > .tt-slot { overflow: visible; min-height: 76px; }
  /* 一个单元格里塞了两节时, 空的那半格也要留得能点中 */
  .tt-cell-group > .tt-slot { min-height: 44px; }
  .tt-course .c-name { font-size: 12.5px; }
  .tt-course .c-meta, .tt-course .c-loc, .tt-course .c-teacher { font-size: 10.5px; }
}
