/* ============================================================
   智融AI互动教学平台 · 门户样式
   1 字体  2 令牌  3 英雄区  4 组件  5 动效  6 响应式
   本文件只含表现。结构由 build_catalog.py 产出，行为在 portal.js。
   ============================================================ */

/* ---------- 1 字体 ---------- */
/* font-display 保持 swap。若将来改成 optional 或 fallback，必须同时给这两个
   @font-face 加上 unicode-range 限定到拉丁区——否则它们的非零 block period
   会连中文正文一起挡住，首屏闪白，恰好与改用 optional 的目的相反。
   当前 swap 的 block period 为 0，所以没有这个问题。 */
@font-face {
  font-family: 'Archivo';
  src: url('../assets/fonts/archivo-latin-wght-normal.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../assets/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- 2 令牌 ---------- */
:root {
  /* 这几个色值在 tools/html/_portal/portal-bar.css 里另有一份硬编码副本——
     那份样式表服务于 /tools/ 下不加载本文件的独立页面，拿不到令牌层。
     概率统计课件（courseware/probability-statistics-undergrad/assets/css/）
     为离线包又存了第三份。改配色时三处一起改。 */
  --pt-ink: #0A131C;
  --pt-ink-hairline: #1E3244;
  --pt-steel: #3A5570;
  --pt-cinnabar: #C4402B;
  --pt-cinnabar-lift: #E8674E;
  --pt-cinnabar-deep: #A83422;
  --pt-paper: #FAF7F1;
  --pt-bone: #F2EDE4;
  --pt-rule: #E3DED3;
  --pt-surface: #FFFFFF;
  --pt-text: #0A131C;
  --pt-text-dim: #7C8794;
  --pt-text-on-ink: #A6B4C2;
  --pt-shadow: 0 8px 24px rgba(10, 19, 28, .12);

  /* 强调「文字」用这个，强调「填充块」用 --pt-cinnabar。
     两者必须分开：#C4402B 落在深色表面只有 3.13:1，不达 AA。 */
  --pt-accent-text: #C4402B;
  /* 强调文字的 hover 态。浅色变深、深色变亮，两边都是「加强」。
     不要在深色表面上用 --pt-cinnabar-deep 当文字色：#A83422 在暗色卡面
     只有 2.42:1，而浅色模式下是 6.18:1 通过的——只跑浅色的人工验收看不出来。 */
  --pt-accent-hover: #A83422;

  --pt-hero-axis: #4A6480;          /* SVG 坐标标注 */
  --pt-hero-ghost-border: #41586F;  /* 描边按钮 */
  --pt-hero-ghost-text: #DCE5EE;
  --pt-hero-cue: #5f7285;           /* SCROLL ↓ 提示 */

  --pt-sans: 'Archivo', system-ui, -apple-system, 'Segoe UI',
             'PingFang SC', 'Microsoft YaHei', sans-serif;
  --pt-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Consolas, monospace;
}

[data-md-color-scheme="slate"] {
  --pt-paper: #0F1A25;
  --pt-rule: #22323F;
  --pt-surface: #16232F;
  --pt-text: #F2EDE4;
  --pt-text-dim: #8B9AA8;
  --pt-shadow: 0 8px 24px rgba(0, 0, 0, .38);
  /* 深色表面上换成提亮版：#E8674E on #16232F = 4.93:1，达 AA。 */
  --pt-accent-text: #E8674E;
  --pt-accent-hover: #F08A72;   /* 暗色卡面 6.52:1、暗色页面 7.18:1 */
}

/* Material 的默认字体交给我们的栈。font: false 已经关掉了 Google Fonts。

   两种写法都要有，不是冗余：
   1) --md-text-font / --md-code-font 是 Material 自己的变量。font: false 之后
      它们「未被设置」，Material 核心 CSS 里 --md-text-font-family 会回退到系统
      字体。.md-tooltip2 与 code .md-annotation 只认这条派生变量，直接写
      font-family 够不到它们。Material 官方文档也建议用变量而非 font-family。
   2) 直接的 font-family 规则覆盖正文与代码块，这是绝大多数可见文字。 */
:root {
  --md-text-font: 'Archivo';
  --md-code-font: 'IBM Plex Mono';
}
body, input, .md-typeset { font-family: var(--pt-sans); }
code, kbd, pre { font-family: var(--pt-mono); }

/* ---------- 3 英雄区 ---------- */
.pt-hero {
  position: relative;
  overflow: hidden;
  background: var(--pt-ink);
  /* 用 min-height 而非 height：桌面端内容装得下，效果完全一致；但窄屏上标题与
     说明会折行，固定高度会把内容裁掉（实测 320px 下内容需要 445px）。 */
  /* 满屏：减去页面外壳的高度。桌面端是页眉 48 + 标签条 48 = 96px；
     手机上 Material 把标签栏收进抽屉、不渲染，只有页眉 48px——减 96 会让
     英雄区矮一截，底部空出 150-220px。用变量按断点取值。 */
  --pt-chrome: 96px;
  min-height: calc(100vh - var(--pt-chrome));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-bottom: 1.6rem;
}
.pt-hero__lay {
  position: absolute;
  inset: -16% 0;
  width: 100%;
  height: 132%;
  will-change: transform;
}
.pt-hero__grid path { stroke: var(--pt-ink-hairline); stroke-width: .9; fill: none; }
.pt-hero__bell { stroke: var(--pt-steel); stroke-width: 1.6; fill: none; }
.pt-hero__bellfill { fill: var(--pt-cinnabar); opacity: .07; }
.pt-hero__tree path { stroke: var(--pt-steel); stroke-width: 1.2; fill: none; opacity: .55; }
.pt-hero__axis { fill: var(--pt-hero-axis); font: 400 13px var(--pt-mono); }
.pt-hero__front { stroke: var(--pt-cinnabar-lift); stroke-width: 2.8; fill: none; }
.pt-hero__dots circle { fill: var(--pt-cinnabar-lift); }

.pt-hero__in {
  position: relative;
  z-index: 3;
  /* 占满卡片之上的全部空间，并在其内部垂直居中。
     不用 auto margin：文字块与卡片都设 auto 时会互相抢空间，
     结果是文字被顶到顶部、卡片浮在中间。 */
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  max-width: 61rem;
  margin-inline: auto;
  padding: 0 1.5rem;
  will-change: transform, opacity;
}
.pt-hero__kick {
  font: 600 .72rem/1 var(--pt-mono);
  letter-spacing: .22em;
  color: var(--pt-cinnabar-lift);
  margin: 0;
}
.pt-hero__h1 {
  color: var(--pt-bone);
  font-size: clamp(1.9rem, 4.6vw, 3rem);
  font-weight: 800;
  letter-spacing: -.01em;
  line-height: 1.16;
  margin: .7rem 0 0;
}
.pt-hero__en {
  display: block;
  font-size: clamp(.7rem, 1.5vw, .88rem);
  font-weight: 500;
  letter-spacing: .42em;
  text-transform: uppercase;
  opacity: .55;
  margin-top: .55rem;
}
.pt-hero__sub {
  color: var(--pt-text-on-ink);
  font-size: .86rem;
  line-height: 1.85;
  max-width: 30rem;
  margin: .85rem 0 0;
}
.pt-hero__cta { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1.25rem 0 0; }

.pt-btn {
  display: inline-block;
  font-size: .8rem;
  font-weight: 700;
  padding: .6rem 1.15rem;
  border-radius: 2px;
  text-decoration: none;
  transition: background .18s, border-color .18s, color .18s;
}
/* 提到 .md-typeset 之下：Material 的 .md-typeset a（0,1,1）会压过 .pt-btn--solid
   （0,1,0）。链接色改成朱砂之后，正文里的实心按钮会变成朱砂底加朱砂字，整个消失。
   :hover 同理要压过 .md-typeset a:focus,.md-typeset a:hover（0,2,1）——之前只堵了
   基础态，:hover 漏了一半：悬停时文字被 Material 的 a:hover 压回强调色，朱砂字落在
   朱砂深底上只有 1.29:1，不达 AA（实测确认，见计算样式审计）。
   英雄区的按钮不在 .md-typeset 内，不受影响，但四条规则都两处写，以免将来搬动位置时失效。 */
.pt-btn--solid, .md-typeset .pt-btn--solid { background: var(--pt-cinnabar); color: #fff; }
.pt-btn--solid:hover, .md-typeset .pt-btn--solid:hover { background: var(--pt-cinnabar-deep); color: #fff; }
.pt-btn--ghost, .md-typeset .pt-btn--ghost { border: 1px solid var(--pt-hero-ghost-border); color: var(--pt-hero-ghost-text); font-weight: 500; }
.pt-btn--ghost:hover, .md-typeset .pt-btn--ghost:hover { border-color: var(--pt-cinnabar-lift); color: var(--pt-cinnabar-lift); }


/* ---------- 4 组件 ---------- */
/* Material 用 .md-typeset h2 / h3 / a / p 这类「类 + 元素」选择器（0,1,1），
   单个组件类是 0,1,0，一律输。凡是设置了 Material 同名规则也会设置的属性的
   组件规则，都必须写成 .md-typeset .pt-x 形式。英雄区在 .md-typeset 之外，
   其规则另写一份裸类选择器。（实测确认 Material 编译后的 CSS 里没有
   .md-typeset p / ul / li / code 这几条——只有 h1–h6 和 a / a:hover 会撞。） */
/* 英雄区内部的底部一行。不再需要负 margin 去压别人的间距，
   也不再需要抵消 Material 内容区上边距的那两条补丁。 */
.pt-quick {
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: 61rem;
  margin: 0 auto;
  padding: 0 1.5rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .8rem;
}
.pt-quick__c {
  background: var(--pt-surface);
  border: 1px solid var(--pt-rule);
  border-radius: 4px;
  box-shadow: var(--pt-shadow);
  padding: .9rem 1rem;
  text-decoration: none;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: .75rem;
  transition: border-color .18s, transform .18s;
}
.pt-quick__c:hover { border-color: var(--pt-cinnabar); transform: translateY(-2px); }
.pt-quick__n {
  grid-row: 1 / 3;
  align-self: center;
  font: 700 1.5rem/1 var(--pt-mono);
  color: var(--pt-accent-text);
}
.pt-quick__b { font-size: .84rem; font-weight: 700; color: var(--pt-text); }
.pt-quick__s { font-size: .7rem; color: var(--pt-text-dim); }

.pt-sec { margin: 2.4rem 0 0; }
.pt-shd {
  display: flex;
  align-items: baseline;
  gap: .8rem;
  border-bottom: 1px solid var(--pt-rule);
  padding-bottom: .55rem;
  margin-bottom: 1rem;
}
.pt-shd__lbl {
  font: 700 .62rem/1 var(--pt-mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--pt-accent-text);
}
.md-typeset .pt-shd__tt { font-size: 1.15rem; font-weight: 800; color: var(--pt-text); margin: 0; }
.pt-shd__meta { margin-left: auto; font: 400 .68rem/1 var(--pt-mono); color: var(--pt-text-dim); }

.pt-grid { display: grid; gap: .8rem; }
.pt-grid--4 { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.pt-grid--3 { grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }

.pt-card {
  min-width: 0;
  background: var(--pt-surface);
  border: 1px solid var(--pt-rule);
  border-radius: 4px;
  padding: .9rem;
  text-decoration: none;
  display: block;
  transition: border-color .18s, box-shadow .18s, transform .18s;
}
.pt-card:hover {
  border-color: var(--pt-cinnabar);
  box-shadow: var(--pt-shadow);
  transform: translateY(-2px);
}
/* .pt-card--course 刻意不定义任何规则：设计评审时确认过课程卡与工具/应用卡
   共用同一套视觉，区别只在于它多一个线描图标和一行资源计数。保留这个修饰类
   是留一个将来需要区分时的挂钩，不是漏写。改动前请先确认设计意图。 */
.pt-ic { width: 22px; height: 22px; color: var(--pt-accent-text); display: block; }
.md-typeset .pt-card__t {
  font-size: .84rem;
  font-weight: 700;
  color: var(--pt-text);
  margin: .55rem 0 .25rem;
  overflow-wrap: anywhere;
}
.pt-card__d { font-size: .72rem; line-height: 1.65; color: var(--pt-text-dim); margin: 0; }
.pt-card__more { display: block; font: 700 .64rem/1 var(--pt-mono); color: var(--pt-accent-text); margin-top: .6rem; }

.pt-badges { display: flex; gap: .3rem; margin-top: .6rem; flex-wrap: wrap; }
.pt-badge {
  font: 400 .6rem/1 var(--pt-mono);
  padding: .2rem .4rem;
  border-radius: 2px;
  border: 1px solid var(--pt-rule);
  color: var(--pt-text-dim);
}
.pt-badge--beta { border-color: var(--pt-accent-text); color: var(--pt-accent-text); }

/* 课程详情页 */
.pt-crumb { margin: 0 0 .4rem; font: 700 .64rem/1 var(--pt-mono); letter-spacing: .12em; }
.md-typeset .pt-crumb a { color: var(--pt-accent-text); text-decoration: none; }
.md-typeset .pt-crumb a:hover { color: var(--pt-accent-hover); }
.pt-lead { font-size: .84rem; line-height: 1.85; color: var(--pt-text-dim); max-width: 42em; margin: .5rem 0 0; }
.pt-empty { font-size: .8rem; color: var(--pt-text-dim); }

.pt-panel, .pt-about {
  background: var(--pt-ink);
  border-radius: 6px;
  padding: 1.6rem 1.5rem;
}
.pt-lbl {
  display: block;
  font: 700 .62rem/1 var(--pt-mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--pt-cinnabar-lift);
  margin-bottom: .5rem;
}
.md-typeset .pt-panel__name, .md-typeset .pt-about__name { color: var(--pt-bone); font-size: 1.2rem; font-weight: 800; margin: 0; }
.pt-panel__en, .pt-about__en { color: var(--pt-text-on-ink); font-weight: 400; margin-left: .5rem; font-size: .9rem; }
.pt-panel p, .pt-about p { color: var(--pt-text-on-ink); font-size: .78rem; line-height: 1.8; margin: .45rem 0 0; }
.pt-panel a[href^="mailto"], .pt-about a[href^="mailto"] { color: var(--pt-cinnabar-lift); }
.pt-panel .pt-btn, .pt-about .pt-btn { margin-top: 1rem; }

/* 页脚：规格首页分区第 9 条。墨底 + 等宽版本行。 */
.md-footer { background: var(--pt-ink); }
.md-footer-meta { background: var(--pt-ink); }
.md-footer-meta__inner { border-top: 1px solid var(--pt-ink-hairline); }
.md-footer-copyright {
  color: var(--pt-text-on-ink);
  font: 400 .66rem/1.9 var(--pt-mono);
}
.md-footer-copyright__highlight { color: var(--pt-bone); }

/* 首页不需要 Material 的 h1，标题在英雄区里 */
.md-content__inner > h1:first-child { display: none; }

/* ---------- 7 Material 主题接缝 ---------- */
/* Material 默认主色是靛蓝，页眉与标签条会在墨色英雄区上方顶出一条紫蓝带。
   压成墨底，让页眉、标签条与英雄区连成一片。
   注意 --md-typeset-a-color 默认取值就是 --md-primary-fg-color，
   若只改主色，正文链接会一起变成近黑色——必须显式指回强调令牌。 */
/* mkdocs.yml 的 palette 里声明 primary/accent 为 custom，Material 那些
   [data-md-color-primary=indigo] 的规则就不会命中——包括 palette.css 里
   特异性 0,2,0 的 [data-md-color-scheme=slate][data-md-color-primary=indigo]
   { --md-typeset-a-color:#5488e8 }。这是官方推荐做法，比拼特异性稳。
   注意 --md-typeset-a-color 默认取 --md-primary-fg-color，只改主色会把正文
   链接一起变成近黑，必须显式指回强调令牌。 */
[data-md-color-primary=custom] {
  --md-primary-fg-color:        #0A131C;
  --md-primary-fg-color--dark:  #060D14;
  --md-primary-fg-color--light: #132234;
  --md-typeset-a-color:         var(--pt-accent-text);
}
[data-md-color-accent=custom] {
  --md-accent-fg-color:         var(--pt-accent-text);
  --md-accent-fg-color--transparent: rgba(196, 64, 43, .1);
}


/* ---------- 5 动效 ---------- */
/* 入场：纯 CSS，英雄区元素依次错开。JS 无关，禁用脚本也照常播放。 */
.pt-hero__kick, .pt-hero__h1, .pt-hero__sub, .pt-hero__cta {
  animation: pt-in .62s cubic-bezier(.22, .61, .36, 1) both;
}
.pt-hero__kick { animation-delay: .04s; }
.pt-hero__h1   { animation-delay: .12s; }
.pt-hero__sub  { animation-delay: .20s; }
.pt-hero__cta  { animation-delay: .28s; }
.pt-quick__c   { animation: pt-in .62s cubic-bezier(.22, .61, .36, 1) both; }
.pt-quick__c:nth-child(1) { animation-delay: .36s; }
.pt-quick__c:nth-child(2) { animation-delay: .42s; }
.pt-quick__c:nth-child(3) { animation-delay: .48s; }

@keyframes pt-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* 滚动揭示：初值由 CSS 给，.pt-in 由 portal.js 添加。
   .pt-js 只有脚本跑起来才会加到 <body>，所以禁用 JS 时元素保持可见。 */
.pt-js .pt-reveal { opacity: 0; transform: translateY(14px); }
.pt-js .pt-reveal.pt-in {
  opacity: 1;
  transform: none;
  transition: opacity .6s cubic-bezier(.22, .61, .36, 1),
              transform .6s cubic-bezier(.22, .61, .36, 1);
}

/* ---------- 6 响应式 ---------- */
@media screen and (max-width: 76.1875em) {
  /* 标签栏在这个断点以下收进抽屉，页面外壳只剩页眉 48px */
  .pt-hero { --pt-chrome: 48px; }
  .pt-quick { grid-template-columns: 1fr; }
  .md-content__inner > .pt-quick { margin-top: -1.4rem; }
}

@media screen and (max-width: 47.9375em) {
  /* 手机上快速入口改成一行三个紧凑块：竖排三张 82px 的卡加上两个 48px 的
     CTA，在满屏英雄区里装不下——实测 360×720 超出 75px，第三张卡被切在
     屏幕外。而且那么大的卡片与 CTA 按钮的比例也不协调。
     描述行在这里省掉，数字加标签已经够表意。 */
  .pt-quick {
    grid-template-columns: repeat(3, 1fr);
    gap: .45rem;
    margin-top: 1.1rem;
  }
  .pt-quick__c {
    grid-template-columns: auto auto;
    grid-template-rows: auto;
    justify-content: center;
    align-items: baseline;
    column-gap: .3rem;
    padding: .5rem .35rem;
  }
  .pt-quick__n { grid-row: auto; font-size: 1.05rem; }
  .pt-quick__b { font-size: .74rem; }
  .pt-quick__s { display: none; }

  /* 高度交给基础规则的 calc(100vh - var(--pt-chrome))，这里只收内边距。
     早先这行写死 min-height: 340px，是英雄区改成满屏之前的遗留：它会盖掉
     calc，让手机上的英雄区只按内容高度撑开（实测 574/780 = 74%），底部空
     出一条白边。 */
  .pt-hero { padding-bottom: 1.2rem; }
  .pt-hero__sub { font-size: .8rem; }
}

@media screen and (max-width: 29.9375em) {
  .pt-hero { padding-bottom: 1rem; }
  .pt-hero__cta { flex-direction: column; align-items: stretch; }
  .pt-btn { text-align: center; }
  .md-content__inner > .pt-quick { margin-top: -1rem; }
  .pt-grid--4, .pt-grid--3 { grid-template-columns: 1fr; }
}

/* 无障碍：动效全停。视差由 portal.js 一并跳过。 */
@media (prefers-reduced-motion: reduce) {
  .pt-hero__kick, .pt-hero__h1, .pt-hero__sub, .pt-hero__cta,
  .pt-quick__c {
    animation: none !important;
  }
  .pt-js .pt-reveal, .pt-js .pt-reveal.pt-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .pt-hero__lay, .pt-hero__in { transform: none !important; }
}
