:root {
  --sjtu-red: #a41e35;
  --sjtu-red-ink: #78121f;
  --sjtu-red-wash: #fbf3f5;
  --blueprint: #1b3a6b;
  --blueprint-ink: #122949;
  --ink-900: #14171c;
  --ink-700: #383f4a;
  --ink-500: #687181;
  --ink-300: #a8aeb9;
  --rule: #dde1e8;
  --rule-strong: #b9c0cc;
  --grid-line: rgba(20, 23, 28, 0.045);
  --sheet: #fff;
  --ground: #f7f8fa;
  --radius-sm: 3px;
  --radius-md: 6px;
  --shadow-1: 0 1px 2px rgba(20, 23, 28, 0.04);
  --shadow-2: 0 2px 4px rgba(20, 23, 28, 0.04), 0 12px 24px -16px rgba(20, 23, 28, 0.16);
  /* 拉丁字族必须排在中文字族之前，否则中文字体里的半宽拉丁会接管西文与数字 */
  --font-display: "IBM Plex Serif", "Noto Serif SC", "Source Han Serif SC", "Songti SC", serif;
  --font-sans: "IBM Plex Sans", "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
  --container: 1280px;
}

* { box-sizing: border-box; }
/* 顶栏是 sticky 的，锚点跳转要给它让出高度，否则标题被压在栏下面。 */
html { scroll-behavior: smooth; scroll-padding-top: 84px; }
body {
  margin: 0;
  min-width: 320px;
  background: var(--ground);
  color: var(--ink-700);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.75;
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
}
body.menu-open { overflow: hidden; }
button, input, select { font: inherit; letter-spacing: 0; }
button, summary { -webkit-tap-highlight-color: transparent; }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }
svg { display: block; }
[hidden] { display: none !important; }
.icon-menu, .icon-close { display: contents; }
h1, h2, h3, p { margin: 0; }
h1, h2 { color: var(--ink-900); font-family: var(--font-display); }
h1 { font-size: clamp(30px, 4vw, 48px); line-height: 1.2; font-weight: 700; }
h2 { font-size: clamp(24px, 2.5vw, 34px); line-height: 1.28; font-weight: 700; }
h3 { margin: 0; color: var(--ink-900); font-size: 17px; line-height: 1.45; font-weight: 600; }
:focus-visible { outline: 3px solid rgba(27, 58, 107, 0.28); outline-offset: 3px; }

.skip-link {
  position: fixed;
  left: 16px;
  top: -80px;
  z-index: 200;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--ink-900);
  color: #fff;
}
.skip-link:focus { top: 12px; }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 32px;
}
.grid-rules {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.grid-rules .container { height: 100%; }
.grid-rules-inner {
  height: 100%;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
.grid-rules-inner span { border-right: 1px solid var(--grid-line); }
.grid-rules-inner span:last-child { border-right: 0; }
.page-layer { position: relative; z-index: 1; }

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 68px;
  border-bottom: 1px solid rgba(221, 225, 232, 0.94);
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(16px) saturate(130%);
}
.header-inner {
  height: 68px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
}
.brand {
  min-width: 0;
  display: inline-flex;
  align-items: center;
  gap: 11px;
}
.brand img { width: 38px; height: 38px; flex: 0 0 auto; }
.brand-copy { min-width: 0; display: block; line-height: 1.2; }
.brand-university { color: var(--ink-500); font-size: 11px; font-weight: 600; }
.brand-title {
  display: block;
  margin-top: 3px;
  overflow: hidden;
  color: var(--ink-900);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.desktop-nav { display: flex; align-items: center; gap: 2px; }
.nav-link, .nav-summary {
  min-height: 38px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 10px;
  border: 0;
  background: transparent;
  color: var(--ink-700);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.nav-link:hover, .nav-summary:hover { color: var(--sjtu-red); }
.nav-group { position: relative; }
.nav-group summary { list-style: none; }
.nav-group summary::-webkit-details-marker { display: none; }
.nav-group[open] .nav-summary { color: var(--sjtu-red); }
.nav-group[open] .nav-summary svg { transform: rotate(180deg); }
.nav-popover {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  width: 228px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  background: #fff;
  box-shadow: var(--shadow-2);
  transform: translateX(-50%);
}
.nav-popover a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  color: var(--ink-700);
  font-size: 13px;
  font-weight: 550;
}
.nav-popover a:hover { background: var(--ground); color: var(--sjtu-red); }
.header-actions { display: flex; align-items: center; gap: 8px; }
.icon-button {
  width: 40px;
  height: 40px;
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--ink-700);
  cursor: pointer;
}
.icon-button:hover { border-color: var(--rule); background: var(--ground); color: var(--sjtu-red); }
.user-chip {
  max-width: 112px;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 9px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  background: #fff;
  color: var(--ink-700);
  font-size: 12px;
  font-weight: 600;
}
.user-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mobile-menu-button { display: none; }
.mobile-panel { display: none; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-500);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.eyebrow::before { content: "+"; color: var(--sjtu-red); font-size: 15px; letter-spacing: 0; }
/* 眉标本身就是一道算式时去掉前缀的 ＋——否则读成「＋1 ＋ X ＋ N」，算式是错的。 */
.eyebrow-formula::before { content: none; }
.eyebrow-formula em { color: var(--sjtu-red); font-style: normal; }
.lede { max-width: 760px; color: var(--ink-500); font-size: 17px; line-height: 1.85; }
.meta { color: var(--ink-500); font-family: var(--font-mono); font-size: 12px; line-height: 1.5; }
.link {
  color: var(--blueprint);
  text-decoration: underline;
  text-decoration-color: rgba(27, 58, 107, 0.32);
  text-underline-offset: 4px;
}
.link:hover { color: var(--sjtu-red); text-decoration-color: currentColor; }

.btn {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.btn-primary { border-color: var(--sjtu-red); background: var(--sjtu-red); color: #fff; }
.btn-primary:hover { border-color: var(--sjtu-red-ink); background: var(--sjtu-red-ink); }
.btn-secondary { border-color: var(--rule-strong); background: #fff; color: var(--ink-900); }
.btn-secondary:hover { border-color: var(--sjtu-red); color: var(--sjtu-red); }
.btn-quiet { padding-inline: 10px; color: var(--blueprint); }
.btn[aria-disabled="true"] { border-color: var(--rule); background: var(--ground); color: var(--ink-500); cursor: default; }

/* 首页 hero = 扉页。老校门整幅压在右侧，左侧化开成纯白，题名落在白上。
   照片是渐进增强：static/img/home-plate.* 不在时模板不加 .hero--plate，
   首屏退回一张纯白题名页，一个字都不少。零 JS。 */
.hero {
  min-height: clamp(520px, calc(100svh - 112px), 700px);
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.82);
}
.hero-inner {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  padding-top: 64px;
  padding-bottom: 64px;
}
.hero-copy { min-width: 0; }
.hero h1 {
  margin-top: 24px;
  font-size: clamp(38px, 4.8vw, 66px);
  font-weight: 700;
  line-height: 1.09;
  letter-spacing: -0.01em;
}
.hero-plus { color: var(--sjtu-red); font-family: var(--font-mono); font-weight: 500; }
.hero .lede { max-width: 480px; margin-top: 24px; color: #4f5969; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 32px; }

/* 用 auto 100% 而不是 cover：cover 在宽屏上会把画面上下各裁掉两成，匾额会被切。
   auto 100% 保证竖向永不裁切，超宽屏上照片只是靠右站着，左边多出来的地方本来就是白的。
   代价是照片左缘直接接到白底上，所以原图左侧必须是纯白，浅灰会露出一条竖直接缝。

   照片按高度铺满、右对齐，所以画面里任何一处离右边缘的距离都只跟 hero 高度 H 有关：
   匾额横向落在图宽的 68%–84%，图宽 = 2.82H，于是匾额永远在离右缘 0.45H–0.90H 处。
   白纱的渐变因此也用 H 的倍数写，而不是百分比——百分比会随视口宽变，H 的倍数不会，
   匾额与白纱的相对位置在任何宽度下都不动。 */
.hero--plate {
  /* 源图是高调洗白过的，直接用会发灰。把饱和与对比拉回来：
     屋檐的砖红、斗拱彩画的青绿、匾额的蓝底金字都要立起来。
     不加 sepia——暖色滤镜会把画面里那片白也染黄，左边文字区就不是纯白了。
     换成已经调过色的图时改成 none。 */
  --plate-tone: saturate(1.45) contrast(1.07) brightness(1.01);
  position: relative;
  overflow: hidden;
  background: #fff;
}
.hero--plate::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--plate) no-repeat right center / auto 100%;
  filter: var(--plate-tone);
}
/* 0.88H 处还是全透明（匾额最左端在 0.90H），1.34H 处已经是纯白（题名右端在 1.4H 外）。 */
.hero--plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to left,
    rgba(255, 255, 255, 0) calc(var(--hero-h) * 0.88),
    rgba(255, 255, 255, 0.62) calc(var(--hero-h) * 1.12),
    #fff calc(var(--hero-h) * 1.34)
  );
}
/* ::after 是最后一个子节点，题名必须显式抬到白纱之上。 */
.hero--plate .hero-inner { position: relative; z-index: 1; }

/* 窄屏上照片与题名争同一块横向空间，谁都站不住：1200px 以下改成上图下字。
   照片收成顶部一条带子（按高度铺满、贴右站，露出的正是匾额那一段），
   只在带子下缘化开进白底，文字整段落在纯白上。 */
.hero--plate { --plate-band: clamp(220px, 26vw, 320px); min-height: 0; }
/* 带子里仍用 auto 100%：cover 会把牌楼的柱脚切掉，而 auto 100% 让整座门完整落在带子里，
   左边露出来的是原图自带的那片天空，接到白底上没有接缝。 */
.hero--plate::before { inset: 0 0 auto 0; height: var(--plate-band); }
.hero--plate::after {
  inset: 0 0 auto 0;
  height: var(--plate-band);
  background: linear-gradient(180deg, rgba(255,255,255,0) 60%, rgba(255,255,255,.78) 85%, #fff 100%);
}
.hero--plate .hero-inner { padding-top: calc(var(--plate-band) + 44px); }

@media (min-width: 1200px) {
  .hero--plate {
    --hero-h: clamp(560px, 46vw, 720px);
    min-height: var(--hero-h);
  }
  .hero--plate::before { inset: 0; height: auto; background-size: auto 100%; }
  .hero--plate::after {
    inset: 0;
    height: auto;
    background: linear-gradient(
      to left,
      rgba(255, 255, 255, 0) calc(var(--hero-h) * 0.88),
      rgba(255, 255, 255, 0.62) calc(var(--hero-h) * 1.12),
      #fff calc(var(--hero-h) * 1.34)
    );
  }
  .hero--plate .hero-inner { padding-top: 64px; }
  .hero--plate .hero-copy { max-width: 560px; }
}

/* 建设体系 = 一道横排的算式。七个数各占一格，＋ 落在 1 与 X、X 与 N 之间，
   是行与行之间真正的运算符；格与格之间的细线就是算式的分节。 */
.register { border-top: 1px solid var(--ink-900); }
.register-row { display: grid; grid-template-columns: minmax(0, 1fr); }
.cell { display: block; min-width: 0; padding: 16px 0 18px; border-bottom: 1px solid var(--rule); }
.cell-value {
  display: block;
  color: var(--ink-900);
  font-family: var(--font-mono);
  font-size: 32px;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.cell-unit { margin-left: 5px; color: var(--ink-500); font-size: 12px; font-weight: 400; }
.cell-name { display: block; margin-top: 11px; color: var(--ink-900); font-size: 14px; font-weight: 600; line-height: 1.4; }
.cell-note { display: block; margin-top: 4px; color: var(--ink-500); font-size: 12px; line-height: 1.5; }
a.cell:hover .cell-value, a.cell:hover .cell-name { color: var(--sjtu-red); }
.register-op {
  padding: 11px 0 12px;
  border-bottom: 1px solid var(--rule);
  color: var(--sjtu-red);
  font-family: var(--font-mono);
  font-size: 17px;
  line-height: 1;
}
@media (min-width: 900px) {
  .register-row { display: flex; align-items: stretch; border-bottom: 1px solid var(--rule); }
  .cell { flex: 1 1 0; padding: 22px 18px 24px; border-bottom: 0; border-left: 1px solid var(--rule); }
  .register-row > .cell:first-child { padding-left: 0; border-left: 0; }
  .register-row > .cell:last-child { padding-right: 0; }
  /* ＋ 与数字对齐，不与整格对齐——它是数与数之间的运算符，不是一格的标题。
     跟在 ＋ 后面的那一格去掉左细线：细线分的是 X 组内部的项，
     ＋ 分的是 1、X、N 三段，两种分隔不能长得一样。 */
  .register-op {
    display: flex;
    align-items: flex-start;
    flex: 0 0 auto;
    padding: 26px 18px 0;
    border-bottom: 0;
    font-size: 21px;
  }
  .register-row > .register-op + .cell { border-left: 0; }
}

.section { padding: clamp(64px, 7vw, 96px) 0; border-bottom: 1px solid var(--rule); }
.section-white { background: rgba(255, 255, 255, 0.82); }
.section-heading {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 24px;
  margin-bottom: 42px;
}
.section-heading-main { grid-column: 1 / span 7; }
.section-heading-side { grid-column: 8 / -1; align-self: end; color: var(--ink-500); }
.section-heading-side .link { display: inline-flex; align-items: center; gap: 5px; margin-top: 12px; color: var(--ink-900); font-size: 13px; font-weight: 600; }
.section-heading h2 { margin-top: 15px; }

/* 学科交叉一览：两列各十行，学院右对齐紧贴 ＋，
   二十个 ＋ 因此落在两条竖线上——平台名字里的那个加号，
   在这里变成页面自己的骨架。 */
.crossing-board { display: grid; grid-template-columns: minmax(0, 1fr); border-top: 1px solid var(--rule-strong); }
.crossing-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40px minmax(0, 1.2fr);
  align-items: baseline;
  padding: 15px 0;
  border-bottom: 1px solid var(--rule);
}
.crossing-line-college { min-width: 0; color: var(--ink-500); font-size: 13px; line-height: 1.5; text-align: right; }
.crossing-line-op { justify-self: center; color: var(--sjtu-red); font-family: var(--font-mono); font-size: 14px; line-height: 1.5; }
.crossing-line-major { min-width: 0; color: var(--ink-900); font-family: var(--font-display); font-size: 16px; font-weight: 700; line-height: 1.5; }
@media (min-width: 1024px) {
  .crossing-board { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 64px; }
}

/* 获批与认定：用实体底色收住该段，不让全页列线干扰长标题阅读。 */
#recognition { background: var(--ground); }
.record-list { border-top: 1px solid var(--rule-strong); }
.record-row {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr) 52px 20px;
  gap: 24px;
  align-items: baseline;
  padding: 17px 0;
  border-bottom: 1px solid var(--rule);
}
/* 同一级别只在该组第一行标一次，组与组之间用一条重线分层。 */
.record-row + .record-row-open { border-top: 1px solid var(--rule-strong); }
.record-level { color: var(--ink-900); font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: .04em; line-height: 1.7; }
.record-name { color: var(--ink-900); font-size: 15px; font-weight: 600; line-height: 1.6; }
.record-year { color: var(--ink-300); font-family: var(--font-mono); font-size: 12px; line-height: 1.7; }
.record-mark { color: var(--ink-300); }
a.record-row:hover .record-name, a.record-row:hover .record-mark { color: var(--sjtu-red); }

.module-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }
.module-card {
  position: relative;
  min-height: 196px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 26px;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: rgba(255,255,255,.78);
  transition: background 180ms ease, color 180ms ease;
}
.module-card:hover { background: #fff; }
.module-card::after {
  content: "+";
  position: absolute;
  right: 22px;
  bottom: 18px;
  color: var(--sjtu-red);
  font-family: var(--font-mono);
  font-size: 18px;
  opacity: 0;
  transition: opacity 180ms ease;
}
.module-card:hover::after { opacity: 1; }
.module-label { color: var(--ink-500); font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em; }
.module-card h3 { margin-top: 12px; font-family: var(--font-display); font-size: 21px; }
.module-summary { max-width: 290px; margin-top: 18px; color: var(--ink-500); font-size: 13px; }

.news-strip { border-top: 1px solid var(--rule-strong); }
.news-row {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr) 180px 28px;
  gap: 20px;
  align-items: center;
  min-height: 78px;
  border-bottom: 1px solid var(--rule);
}
.news-row-title { color: var(--ink-900); font-weight: 600; line-height: 1.5; }
.news-row-source { color: var(--ink-500); font-size: 13px; }
.news-row svg { color: var(--ink-300); }
a.news-row:hover .news-row-title, a.news-row:hover svg { color: var(--sjtu-red); }

.page-hero { padding: 64px 0 52px; border-bottom: 1px solid var(--rule); background: rgba(255,255,255,.76); }
.breadcrumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 28px; color: var(--ink-500); font-size: 12px; }
.breadcrumbs a:hover { color: var(--sjtu-red); }
.breadcrumbs span + span::before, .breadcrumbs a + span::before { content: "/"; margin-right: 8px; color: var(--ink-300); }
.page-title-grid { display: grid; grid-template-columns: repeat(12, minmax(0,1fr)); gap: 24px; align-items: end; }
.page-title-main { grid-column: 1 / span 8; }
.page-title-side { grid-column: 10 / -1; text-align: right; }
.page-title-main h1 { margin-top: 14px; }
.page-title-main .lede { margin-top: 16px; }
.page-count { color: var(--sjtu-red); font-family: var(--font-display); font-size: 44px; font-weight: 700; line-height: 1; }
.page-count-label { margin-top: 7px; color: var(--ink-500); font-size: 12px; }

.courses-page .page-hero { padding-block: 40px 34px; }
.courses-page .breadcrumbs { margin-bottom: 20px; }
.course-spotlight {
  border-block: 1px solid rgba(255,255,255,.12);
  background: #102822;
  color: #fff;
}
.course-spotlight-layout {
  display: grid;
  grid-template-columns: minmax(360px, .9fr) minmax(0, 1.2fr);
  min-height: 270px;
}
.course-spotlight-media { min-height: 270px; margin: 0; overflow: hidden; }
.course-spotlight-media img { width: 100%; height: 100%; object-fit: cover; }
.course-spotlight-copy { align-self: center; padding: 30px 0 30px 42px; }
.course-spotlight-kicker {
  color: #69d6c7;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
}
.course-spotlight h2 { margin-top: 10px; color: #fff; font-family: var(--font-display); font-size: 36px; line-height: 1.2; }
.course-spotlight-subtitle { margin-top: 3px; color: rgba(255,255,255,.64); font-size: 13px; }
.course-spotlight-summary { max-width: 660px; margin-top: 14px; color: rgba(255,255,255,.78); font-size: 14px; line-height: 1.75; }
.course-spotlight-meta { display: flex; flex-wrap: wrap; gap: 7px 18px; margin-top: 17px; color: rgba(255,255,255,.68); font-size: 12px; }
.course-spotlight-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px; margin-top: 22px; }
.course-spotlight-primary { border-color: #fff; background: #fff; color: #102822; }
.course-spotlight-primary:hover { border-color: #69d6c7; background: #69d6c7; color: #102822; }
.course-spotlight-link { display: inline-flex; align-items: center; gap: 6px; color: #fff; font-size: 13px; font-weight: 600; }
.course-spotlight-link:hover { color: #69d6c7; }

.content-section { min-height: 42vh; padding: 46px 0 84px; }
.courses-page .content-section { padding-top: 32px; }
.toolbar {
  display: grid;
  grid-template-columns: minmax(260px, 1.5fr) repeat(3, minmax(150px, .7fr)) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 24px;
}
.toolbar.two-filters { grid-template-columns: minmax(260px, 1.5fr) repeat(2, minmax(160px, .7fr)) auto; }
.toolbar.one-filter { grid-template-columns: minmax(260px, 1.5fr) minmax(160px, .7fr) auto; }
.field-wrap { position: relative; min-width: 0; }
.field-wrap > svg { position: absolute; left: 13px; top: 50%; color: var(--ink-500); transform: translateY(-50%); pointer-events: none; }
.field, .select {
  width: 100%;
  height: 44px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink-900);
  font-size: 13px;
}
.field { padding: 0 12px 0 40px; }
.select { padding: 0 34px 0 12px; }
.field:focus, .select:focus { border-color: var(--blueprint); outline: 3px solid rgba(27,58,107,.12); }
.result-note { margin: -8px 0 20px; color: var(--ink-500); font-size: 12px; }

.catalog { border-top: 1px solid var(--rule-strong); }
.catalog-header, .catalog-row {
  display: grid;
  grid-template-columns: minmax(240px, 1.5fr) minmax(190px, 1fr) minmax(140px, .7fr) minmax(140px, .7fr);
  gap: 24px;
  align-items: center;
}
.catalog-header { min-height: 46px; border-bottom: 1px solid var(--rule); color: var(--ink-500); font-size: 11px; font-weight: 600; }
.catalog-row { min-height: 76px; padding: 12px 0; border-bottom: 1px solid var(--rule); }
.catalog-row-title { color: var(--ink-900); font-weight: 600; line-height: 1.5; }
.catalog-cell { min-width: 0; color: var(--ink-700); line-height: 1.55; }
.catalog-cell-muted { color: var(--ink-500); font-size: 13px; }
/* 列数随实际有数据的字段变化：SA 表里声明了但整列为空的字段不出现在表头。 */
.catalog-row[data-columns="3"], .catalog-header[data-columns="3"] { grid-template-columns: minmax(260px, 1.6fr) minmax(200px, 1fr) minmax(160px, .7fr); }
.catalog-row[data-columns="2"], .catalog-header[data-columns="2"] { grid-template-columns: minmax(280px, 1.35fr) minmax(200px, 1fr); }
.catalog-row[data-columns="1"], .catalog-header[data-columns="1"] { grid-template-columns: minmax(0, 1fr); }

.crossings { border-top: 1px solid var(--rule-strong); }
.crossing {
  display: grid;
  grid-template-columns: minmax(190px, 1fr) 62px minmax(300px, 2.2fr);
  gap: 0 12px;
  align-items: baseline;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
}
.crossing-college { color: var(--ink-500); text-align: right; }
.crossing-op { justify-self: center; color: var(--sjtu-red); font-family: var(--font-mono); font-size: 12px; white-space: nowrap; }
.crossing-major { color: var(--ink-900); font-family: var(--font-display); font-size: 18px; font-weight: 700; line-height: 1.5; }
.crossing-focus { grid-column: 3; margin-top: 5px; color: var(--ink-500); font-size: 13px; }

.resource-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.resource-card {
  min-width: 0;
  padding: 24px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  background: #fff;
  box-shadow: var(--shadow-1);
}
a.resource-card { transition: transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease; }
a.resource-card:hover { transform: translateY(-2px); border-color: var(--rule-strong); box-shadow: var(--shadow-2); }
.resource-card .meta { margin-bottom: 12px; }
.resource-card p { margin-top: 11px; color: var(--ink-500); font-size: 13px; }
.resource-card-footer { display: flex; flex-wrap: wrap; gap: 7px 16px; margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--rule); color: var(--ink-500); font-size: 12px; }
.resource-card .btn { margin-top: 22px; }

.plan-list { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; margin-top: 36px; }
.plan-card { min-height: 222px; display: flex; flex-direction: column; padding: 24px; border: 1px solid var(--rule); border-radius: var(--radius-md); background: #fff; }
.plan-card-icon { width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid var(--rule); border-radius: var(--radius-md); color: var(--sjtu-red); }
.plan-card h3 { margin-top: 24px; font-family: var(--font-display); font-size: 19px; }
.plan-card .btn { align-self: flex-start; margin-top: auto; }
.institution-link { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 24px; padding: 28px 0; border-top: 1px solid var(--rule-strong); border-bottom: 1px solid var(--rule-strong); }

.empty-state { padding: 56px 0; border-top: 1px solid var(--rule-strong); border-bottom: 1px solid var(--rule); }
.empty-state h3 { font-family: var(--font-display); font-size: 21px; }
.empty-state p { max-width: 620px; margin-top: 8px; color: var(--ink-500); }

.pagination { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 30px; }
.page-link { min-width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid var(--rule); border-radius: var(--radius-sm); background: #fff; color: var(--ink-700); font-size: 13px; }
.page-link:hover, .page-link.current { border-color: var(--sjtu-red); color: var(--sjtu-red); }

.external-hero { min-height: calc(100svh - 68px); display: grid; align-items: center; padding: 70px 0; background: #fff; }
.external-layout { display: grid; grid-template-columns: repeat(12, minmax(0,1fr)); gap: 24px; align-items: center; }
.external-copy { grid-column: 2 / span 7; }
.external-mark { grid-column: 10 / span 2; color: var(--sjtu-red); font-family: var(--font-mono); font-size: 92px; line-height: 1; text-align: center; }
.external-copy h1 { margin-top: 18px; }
.external-copy .lede { margin-top: 18px; }
.external-copy .btn { margin-top: 28px; }

.plan-viewer-shell { min-height: calc(100svh - 68px); padding: 36px 0 70px; }
.plan-viewer-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; padding-bottom: 22px; border-bottom: 1px solid var(--rule-strong); }
.plan-viewer { margin-top: 20px; overflow: hidden; border: 1px solid var(--rule-strong); border-radius: var(--radius-md); background: #fff; box-shadow: var(--shadow-1); }
.plan-toolbar {
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--rule);
  background: rgba(255,255,255,.98);
}
.plan-tool-group { min-width: 0; display: flex; align-items: center; gap: 5px; }
.plan-tool-group-end { margin-left: auto; }
.plan-tool-button {
  width: 38px;
  height: 38px;
  display: inline-grid;
  place-items: center;
  flex: 0 0 38px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-700);
  cursor: pointer;
}
.plan-tool-button:hover:not(:disabled) { border-color: var(--rule); background: var(--ground); color: var(--sjtu-red); }
.plan-tool-button:disabled { color: var(--ink-300); cursor: default; }
.plan-page-control { height: 38px; display: inline-flex; align-items: center; gap: 7px; color: var(--ink-500); font-family: var(--font-mono); font-size: 12px; }
.plan-page-control input {
  width: 48px;
  height: 34px;
  padding: 0 5px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink-900);
  font-family: var(--font-mono);
  font-size: 12px;
  text-align: center;
}
.plan-zoom-value { width: 46px; color: var(--ink-500); font-family: var(--font-mono); font-size: 11px; text-align: center; }
.plan-open-link {
  min-height: 38px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-left: 5px;
  padding: 0 12px;
  border-left: 1px solid var(--rule);
  color: var(--blueprint);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.plan-open-link:hover { color: var(--sjtu-red); }
.plan-canvas-stage {
  position: relative;
  height: min(72svh, 860px);
  min-height: 480px;
  overflow: auto;
  padding: 28px;
  background: #e8ebf0;
  scrollbar-gutter: stable both-edges;
}
.plan-canvas { display: block; max-width: none; margin: 0 auto; background: #fff; box-shadow: 0 2px 5px rgba(20,23,28,.12), 0 22px 46px -28px rgba(20,23,28,.42); }
.plan-status { position: absolute; inset: 0; display: grid; place-content: center; gap: 7px; padding: 24px; color: var(--ink-500); font-size: 13px; text-align: center; }
.plan-status strong { color: var(--ink-900); font-family: var(--font-display); font-size: 18px; }
.plan-status span { display: block; }
.plan-noscript { padding: 18px; border-top: 1px solid var(--rule); color: var(--ink-500); font-size: 13px; }

.site-footer { background: #fff; }
.footer-main { display: grid; grid-template-columns: 2fr repeat(3, 1fr); gap: 44px; padding-top: 54px; padding-bottom: 48px; border-bottom: 1px solid var(--rule); }
.footer-brand { display: flex; align-items: flex-start; gap: 13px; }
.footer-brand img { width: 44px; height: 44px; }
.footer-brand strong { display: block; color: var(--ink-900); font-family: var(--font-display); font-size: 17px; line-height: 1.4; }
.footer-brand span { display: block; margin-top: 5px; color: var(--ink-500); font-size: 12px; }
.footer-column h3 { margin-bottom: 12px; color: var(--ink-500); font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: .08em; }
.footer-column a { display: block; width: fit-content; margin-top: 7px; color: var(--ink-700); font-size: 13px; }
.footer-column a:hover { color: var(--sjtu-red); }
.footer-bottom { display: flex; justify-content: space-between; gap: 24px; padding-top: 18px; padding-bottom: 22px; color: var(--ink-500); font-size: 12px; }

@media (max-width: 1100px) {
  .desktop-nav { display: none; }
  .mobile-menu-button { display: inline-grid; }
  .mobile-panel {
    position: fixed;
    inset: 68px 0 0;
    z-index: 90;
    overflow-y: auto;
    padding: 22px 24px 42px;
    border-top: 1px solid var(--rule);
    background: rgba(255,255,255,.98);
  }
  .mobile-panel.open { display: block; }
  .mobile-nav-section { padding: 14px 0; border-bottom: 1px solid var(--rule); }
  .mobile-nav-label { margin-bottom: 6px; color: var(--ink-500); font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; }
  .mobile-nav-section a { display: flex; align-items: center; justify-content: space-between; min-height: 44px; color: var(--ink-900); font-weight: 600; }
  .resource-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

@media (max-width: 767px) {
  .container { padding-inline: 20px; }
  .grid-rules { display: none; }
  .site-header, .header-inner { height: 62px; }
  .header-inner { gap: 10px; }
  .brand { flex: 1 1 auto; overflow: hidden; }
  .brand img { width: 34px; height: 34px; }
  .brand-university { display: none; }
  .brand-title { max-width: 190px; font-size: 13px; }
  .mobile-panel { inset-block-start: 62px; }
  .user-chip { display: none; }
  .hero { min-height: 0; }
  .hero-inner { padding-top: 44px; padding-bottom: 48px; }
  .hero-copy { width: 100%; }
  .hero h1 { margin-top: 16px; font-size: 34px; line-height: 1.16; }
  .hero .lede { margin-top: 16px; font-size: 15px; line-height: 1.7; }
  .hero-actions { margin-top: 24px; }
  .hero-actions .btn { flex: 1 1 0; justify-content: center; }
  /* 手机端照片带再收窄一点，且文字与带子之间留出一整段白。 */
  .hero--plate { --plate-band: 208px; }
  .hero--plate .hero-inner { padding-top: calc(var(--plate-band) + 30px); }
  .cell-value { font-size: 27px; }
  .section { padding: 58px 0; }
  .section-heading { display: block; margin-bottom: 30px; }
  .section-heading-side { margin-top: 14px; }
  .crossing-line { grid-template-columns: minmax(0, 1fr) 30px minmax(0, 1.1fr); padding: 13px 0; }
  .crossing-line-college { font-size: 12px; }
  .crossing-line-major { font-size: 14px; }
  /* 手机端把一行折成两行：级别与年份并排在上，名称独占一行。 */
  .record-row { grid-template-columns: minmax(0, 1fr) auto 20px; gap: 4px 12px; padding: 15px 0; }
  .record-level { grid-row: 1; grid-column: 1; }
  .record-year { grid-row: 1; grid-column: 2; }
  .record-mark { grid-row: 1; grid-column: 3; }
  .record-name { grid-row: 2; grid-column: 1 / -1; font-size: 14px; }
  .module-grid { grid-template-columns: 1fr; }
  .module-card { min-height: 154px; padding: 21px; }
  .news-row { grid-template-columns: 78px minmax(0,1fr) 20px; gap: 12px; padding: 13px 0; }
  .news-row-source { display: none; }
  .page-hero { padding: 40px 0 34px; }
  .breadcrumbs { margin-bottom: 20px; }
  .page-title-grid { display: block; }
  .page-title-main h1 { font-size: 32px; }
  .page-title-main .lede { font-size: 15px; }
  .page-title-side { margin-top: 24px; text-align: left; }
  .page-count { font-size: 36px; }
  .courses-page .page-hero { padding-block: 30px 28px; }
  .course-spotlight-layout { grid-template-columns: 1fr; }
  .course-spotlight-media { min-height: 0; aspect-ratio: 16 / 9; }
  .course-spotlight-copy { padding: 25px 0 32px; }
  .course-spotlight h2 { font-size: 30px; }
  .course-spotlight-summary { font-size: 13px; }
  .course-spotlight-actions { gap: 14px 20px; }
  .course-spotlight-primary { width: 100%; justify-content: center; }
  .content-section { padding: 30px 0 64px; }
  .toolbar, .toolbar.two-filters, .toolbar.one-filter { grid-template-columns: 1fr; }
  .toolbar .btn { width: 100%; }
  .catalog-header { display: none; }
  .catalog-row, .catalog-row[data-columns] {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px 14px;
    align-items: start;
    min-height: 0;
    padding: 17px 0;
  }
  .catalog-row-title { grid-column: 1 / -1; }
  .catalog-cell { font-size: 13px; }
  .catalog-cell:empty { display: none; }
  .crossing { display: block; padding: 18px 0; }
  .crossing-college, .crossing-op { display: inline; font-size: 12px; }
  .crossing-op { margin-left: 8px; }
  .crossing-major { margin-top: 6px; font-size: 17px; }
  .crossing-focus { margin-top: 3px; }
  .resource-grid, .plan-list { grid-template-columns: 1fr; }
  .resource-card { padding: 20px; }
  .institution-link { grid-template-columns: 1fr; }
  .institution-link .btn { justify-self: start; }
  .external-hero { min-height: calc(100svh - 62px); }
  .external-layout { display: block; }
  .external-copy { margin-top: 28px; }
  .external-mark { text-align: left; font-size: 64px; }
  .plan-viewer-head { display: block; }
  .plan-toolbar { align-items: stretch; flex-wrap: wrap; gap: 4px 10px; padding: 7px 8px; }
  .plan-tool-group { flex: 1 1 auto; }
  .plan-tool-group-end { justify-content: flex-end; }
  .plan-open-link { width: 38px; min-width: 38px; justify-content: center; margin-left: 0; padding: 0; border-left: 0; font-size: 0; }
  .plan-canvas-stage { height: 64svh; min-height: 420px; padding: 12px; }
  .footer-main { grid-template-columns: 1fr 1fr; gap: 30px 22px; }
  .footer-brand { grid-column: 1 / -1; }
  .footer-bottom { display: block; }
  .footer-bottom span { display: block; margin-top: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
