/*
 * WAP 手机端页面（`/wap` 与 `/wap/library`）。
 *
 * 逐字搬自 `WAP原型/index.html` 的 `<style>` 块（那份原型本身就只有内联样式，
 * 没有外链表）。改动只有三处，都在下面标了：
 *
 * 1. **图片路径**：原型的 `../apps/web/public/img/...` 是给「双击打开本地 html」用的
 *    相对路径，站点里一律从 `public/` 起算写成 `/img/...`。
 * 2. **图片地址**：原型的 hero 与四入口直接引了 `http://localhost:3001/api/v1/public/assets/<uuid>`。
 *    正式页面**不抄这些地址** —— 走 `fetchHomeHero()` 拿后台配的 `image` 字段，
 *    开发/生产自动正确。所以这份表里没有任何写死的图片 URL。
 * 3. **`:root` 变量**：原型那套 `--ink` / `--pink` / `--brand` 只在它自己的 `:root` 里。
 *
 * ## 为什么 WAP 页不加载 `style.min.css`
 *
 * 原型用的是 `.hero` `.tab` `.brand` 这类通用类名，而 `style.min.css`（桌面基线）
 * 里也有同名规则。WAP 页走的是**另一套外壳**（不进 `SiteShell`），只加载这一份表，
 * 所以两边永远不会同时出现在一个页面上 —— 不需要给类名加前缀。
 *
 * ⚠️ **如果将来有人把 `style.min.css` 也加进 WAP 页的样式清单，这份表会被大面积覆盖。**
 */
:root {
  --wap-ink: #080812;
  --wap-ink-soft: #131422;
  --wap-paper: #f5f5f8;
  --wap-muted: #a6a6b5;
  --wap-line: rgba(255, 255, 255, .12);
  --wap-pink: #d51acb;
  --wap-blue: #3c8fff;
  --wap-orange: #ff8e3c;
  --wap-brand: linear-gradient(131deg, #f85e76 3%, #a324b0 23%, #7807cd 45%, #514fd8 72%, #2baedf 100%);
}

* { box-sizing: border-box; }
html { background: #1c1d2c; }
body {
  margin: 0;
  min-width: 320px;
  background: #1c1d2c;
  color: #fff;
  font-family: Inter, "PingFang SC", "Microsoft YaHei", sans-serif;
}
button { font: inherit; }

.wap {
  min-height: 100dvh;
  max-width: 480px;
  margin: 0 auto;
  overflow: hidden;
  background: radial-gradient(circle at 84% 2%, rgba(108, 71, 240, .35), transparent 27rem), var(--wap-ink);
  padding-bottom: calc(78px + env(safe-area-inset-bottom));
}

/* ---------- 顶部品牌条 ---------- */
.topbar {
  height: calc(64px + env(safe-area-inset-top));
  padding: calc(13px + env(safe-area-inset-top)) 18px 12px;
  display: flex;
  align-items: center;
  /*
   * `space-between`：「立即咨询」要落在右上角、与品牌同一行（用户 2026-09-22）。
   * 原来是 `center` —— 顶栏里只有品牌一个元素时两者看不出区别，加了按钮才分得出来。
   */
  justify-content: space-between;
  gap: 10px;
}
.brand { display: inline-flex; align-items: center; gap: 10px; min-width: 0; color: #fff; text-decoration: none; }
.brand img { width: 80px; height: auto; object-fit: contain; }
.brand > span {
  max-width: 150px;
  background: var(--wap-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.4;
}

main { padding: 2px 14px 24px; }

/* ---------- Hero 轮播 ---------- */
/*
 * 高度不再写死：**上下的内边距 + 中间那段图**，图高由图自己的 `aspect-ratio` 撑出来。
 *
 * 试过写死 `min-height`，不行 —— 图区高度固定、宽度却随视口变（430 宽时比例 2.06、
 * 360 时 1.70，只有 390 恰好是 1.86），`contain` 在两头都会留白。
 * 让图区按原图比例撑高，任何视口都既不裁切也不留白。
 */
.hero {
  position: relative;
  /*
   * 上 58 = 标题一行 + 边距；**下 0** —— 图片直接铺到框的底边
   * （用户 2026-09-22：「轮转图的下方和框之间的留白去掉」）。
   *
   * 原来下边距是 22px，用来给圆点单独留一条；现在圆点改成**叠在图上**
   * （`.hero-foot` 的 `bottom: 9px` 没动，图铺满之后它自然落在图的下沿）。
   * 圆点自身是半透明白底，压在图上仍看得清。
   *
   * 图贴到底边不会被圆角切坏：`.hero` 是 `overflow: hidden` + `border-radius: 22px`，
   * 底部的两个圆角照常裁。
   */
  padding: 58px 0 0;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 22px;
  background: linear-gradient(140deg, #171221, #071323);
  box-shadow: 0 22px 42px rgba(0, 0, 0, .32);
}
.hero::after {
  content: "";
  position: absolute;
  inset: auto -15% -45% 42%;
  height: 75%;
  background: radial-gradient(ellipse, rgba(107, 73, 255, .38), transparent 68%);
  pointer-events: none;
}
.hero-copy { position: absolute; z-index: 2; top: 16px; left: 18px; right: 18px; }
/*
 * `.hero-kicker`（「OK BASE · AI SERVICE」那行）已按用户要求删除（2026-09-22）。
 *
 * 标题**合成一行**（用户 2026-09-22：「轮转图上下的文字，都应该像 web 端一样，
 * 上下各一行」）。原来两条 span 各是 `display: block`，「用Ai学习」「用Ai实战」
 * 各占一行、整块 62px；web 端那边 `.accent` 本来就是 `inline-block`，两条并肩。
 *
 * 字号同时收了一档（clamp 上限 32 → 28px），否则两段并肩放不进 324px。
 */
.hero-title { margin: 0; font-family: "Arial Black", "PingFang SC", sans-serif; font-size: clamp(22px, 6.2vw, 28px); line-height: 1.2; letter-spacing: -.04em; white-space: nowrap; }
.hero-title span {
  background: linear-gradient(90deg, var(--wap-pink), var(--wap-blue));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero-title b { color: white; font-weight: 800; }
/*
 * `.hero-sub`（图下方的副文案）已按用户要求删除（2026-09-22），规则一并拿掉。
 * 元素不在 TSX 里了，留着就是死代码。
 */
/*
 * 图占的中间那一条，**文字在它上下方，各一行**（用户 2026-09-22）。
 *
 * `.hero-art` 是个**容器**（有链接时是 `<a>`、没有时是 `<span>`）——
 * 「轮转图的链接也要加上」，而 `<img>` 自己没法挂 `href`，所以尺寸规则留在容器上、
 * 拉伸交给里面的 `img`。
 *
 * `inset` 是「上=标题底、下=副文案顶、左右贴边」的直白写法。最早那套
 * `63px -5px 7px 4px` 配 `width/height` 百分比补偿是凑出来的值（左边留 4px、
 * 下方留 7px、右边靠负偏移找补），已经换掉。
 *
 * ## 高度是这样定的（改数值前先把这条读完）
 *
 * 图片用 `contain` 显示完整，而 `contain` 只在「容器比例 ≠ 图比例」时留白。
 * 所以图区**按原图比例自动撑高**（`aspect-ratio: 766/414`），不再写死高度 ——
 * 写死过一次，结果是 430 宽时比例 2.06、360 时 1.70，只有 390 恰好对上。
 *
 * `.hero` 的高度 = 下面的 `padding` + 图区高度：
 *
 *   上 padding 58  = 标题一行 34 + 上边距 16 + 8 间隙
 *   图区            = hero 内宽 / 1.85（由 aspect-ratio 撑）
 *   下 padding 0   —— 图片铺到框底，圆点叠在图上
 *
 * **改标题或副文案的字号/行数，都要把这两个 padding 重算一遍** ——
 * 少算了文字会与图重叠（`.hero-foot` 是从底部反向定位的，图却从顶部往下排）。
 */
.hero-art {
  /*
   * **占流，不绝对定位** —— 它的高度要参与 `.hero` 的高度计算（见 `.hero` 那条）。
   * `aspect-ratio` 取的是**原图自己的比例** 766/414：图区与图同比例，
   * `contain` 于是既不满出裁切、也不留白。
   */
  position: relative;
  z-index: 1;
  display: block;
  aspect-ratio: 766 / 414;
}
.hero-art img {
  /*
   * `display: block` **不能省** —— 少了它图下方会多出 5px 的空隙。
   *
   * `<img>` 默认是 `inline`，行盒会按基线对齐，图片底部与行盒底之间留出
   * 那段「降部空间」。实测：`.hero-art` 被撑到 221px，而它按
   * `aspect-ratio: 766/414` 算出来应该是 216px —— 差的正是这 5px，
   * 表现成「图片下方和框之间还有一条留白」，也就是用户 2026-09-22 说的那个。
   *
   * （`display: block` 同时消掉 `vertical-align` 那一族问题。）
   */
  display: block;
  width: 100%;
  height: 100%;
  /*
   * 用户 2026-09-22：「把图片显示完整」—— 所以是 `contain` 而不是 `cover`。
   *
   * 上一版用 `cover` 是为了消掉留白，但它裁掉了图片的上下两端。`contain` 保留整张图，
   * 代价是「容器比例 ≠ 图比例时会留白」—— 所以容器的宽高必须按原图给：
   * 原图 766x414（比例 1.85），这一条约 360 宽，高就取 360 / 1.85 ≈ 195px。
   * 下面 `.hero` 的 min-height 是照这个数反推的（见那条的注释）。
   */
  object-fit: contain;
  object-position: center bottom;
}
/*
 * 图下方那一行，现在**只剩圆点**（副文案和「立即咨询」先后都搬走了）。
 *
 * 所以是 `flex-end` 而不是 `space-between` —— 只剩一个子元素时 `space-between`
 * 会把它推到左边。
 */
.hero-foot { position: absolute; z-index: 3; bottom: 9px; left: 18px; right: 18px; display: flex; align-items: center; justify-content: flex-end; }
.topbar-consult {
  border: 0;
  border-radius: 999px;
  padding: 8px 12px;
  color: white;
  background: var(--wap-brand);
  box-shadow: 0 8px 18px rgba(142, 50, 213, .34);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
}
.dots { display: flex; gap: 5px; }
.dot { width: 5px; height: 5px; padding: 0; border: 0; border-radius: 50%; background: rgba(255, 255, 255, .35); cursor: pointer; }
.dot.is-active { width: 16px; border-radius: 5px; background: #fff; }

/* ---------- 区块标题 ---------- */
.section-label { display: flex; align-items: baseline; justify-content: space-between; margin: 25px 3px 12px; }
.section-label h2 { margin: 0; font-size: 17px; letter-spacing: .03em; }
.section-label span { color: #aaa8b7; font-size: 11px; }

/* ---------- 服务入口 2×2 ---------- */
.entry-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.entry {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--wap-line);
  border-radius: 16px;
  background: #161624;
  color: white;
  text-align: left;
  cursor: pointer;
  padding: 0;
  text-decoration: none;
  display: block;
}
.entry img { aspect-ratio: 359 / 144; width: 100%; height: auto; display: block; object-fit: contain; object-position: center; opacity: .93; transition: transform .25s ease; }
.entry:hover img, .entry:focus-visible img { transform: scale(1.045); }
.entry span { display: flex; align-items: center; justify-content: space-between; height: 39px; padding: 0 11px; font-size: 12px; font-weight: 700; }
.entry em {
  color: #b9b4cf;
  font-size: 16px;
  font-style: normal;
  /*
   * 箭头**不参与收缩**。不写的话窄屏上它会被文字挤扁，而文字是溢出的那一方 ——
   * 结果是箭头**盖在字上面**（实测 360/320px），比截断难看得多。
   * 固定住它，溢出的责任就全落在文案那边（`overflow: hidden` 截断）。
   */
  flex: 0 0 auto;
}

/* ---------- 内容区最底部那张横图 ---------- */
/*
 * 用户 2026-09-24：与小程序 mini 同款的底部横图，点击开**在线咨询弹窗**。
 * 图是 `public/img/wap-banner.webp`（468×101）；小程序那份是同图源的拷贝
 * （`mini/assets/banner.webp`）—— **两份要一起换**，改一份另一份不会跟着变。
 *
 * 它渲染成 `<button>` 而不是 `<div>`：点击有动作，按钮才有键盘可达性与焦点环。
 * 所以要清掉按钮自带的边框/底色/内边距，并 `display: block` ——
 * 行内盒会在图下方留出基线那 5px 空隙（本仓在 `.hero-art img` 上踩过同一个坑）。
 */
.home-banner { display: block; width: 100%; margin: 18px 0 0; padding: 0; border: 0; background: none; cursor: pointer; }
.home-banner img { display: block; width: 100%; height: auto; border-radius: 12px; }
.home-banner:active { opacity: .88; }
.home-banner:focus-visible { outline: 2px solid var(--wap-blue); outline-offset: 2px; }

/* ---------- 企业案例：分类选择的格子 ---------- */
/*
 * 用户 2026-09-24：「选择不同的分类，再显示对应的分类里面的案例」——
 * `/wap/cases` 从「全部案例」改成这个分类格子，点进去才是那个分类的内容。
 * 与小程序 `pages/cases` 的 `.boards` 同一套版式。
 *
 * 格子的宽高比 **50/27（≈1.85:1）** —— 2026-10-22 用户要求整体高度缩小 10%
 * （原来是 5/3 ≈1.67:1）。小程序那边因为 `aspect-ratio` 不可靠，是用 JS 按
 * `(windowWidth - 38) * 0.27` 算出来的高度；web 直接用 `aspect-ratio`
 * （两列、gap 10px、main 左右各 14px 内边距，算下来比例相同）。
 *
 * 格子里只有一行字：**☑️ + 板块名**居中（原来的 `[企业定制案例]` 已删除，2026-10-22）。
 */
.board-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.board-tile {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 50 / 27;
  overflow: hidden;
  /* 底边原来给 `[企业定制案例]` 留了 26px，那行删掉后改成四边等距，名称才真居中。 */
  padding: 10px;
  border: 1px solid var(--wap-line);
  border-radius: 16px;
  color: white;
  text-align: center;
  text-decoration: none;
}
/*
 * 背景：**站内那支品牌渐变 + 60% 不透明**（用户 2026-09-24）。
 *
 * 用 `::before` 叠一层、对它单独设 `opacity`，而不是给整块 `.board-tile` 设 ——
 * 后者会把**标题和 [企业定制案例] 一起淡化**，在深色底上字会发灰。
 * 这样「背景半透明」与「文字清晰」互不牵扯。
 *
 * 颜色直接吃 `--wap-brand`（与首页 hero 标题那支出处相同），**不另抄一份色值**：
 * 五段粉→紫→蓝是设计常量，抄一遍以后改一处必然漏一处。
 * 底色不再铺 `#161624` —— 用户要的就是能透出页面底色的半透明感。
 */
.board-tile::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--wap-brand);
  opacity: .6;
}
/* 文字与那行小标要压在渐变层之上（`::before` 是绝对定位，不抬 z 会盖住文字）。 */
.board-tile__name { position: relative; z-index: 1; font-size: 18px; font-weight: 800; line-height: 1.35; }
.board-tile:active { opacity: .88; }
.board-tile:focus-visible { outline: 2px solid var(--wap-blue); outline-offset: 2px; }

/*
 * 资料库那张卡的**头像区**。web 上它走的不是「一句描述」那条路，而是
 * 5 个用户头像 + 「海量资料 免费获取」（见 `HomePageHero`）。
 *
 * ## 为什么这里**不用 flex**（试错记录，别再改回去）
 *
 * 底栏 `.entry span` 本身是 `display: flex; justify-content: space-between`，
 * 而这一格要在 178px 里塞下 5 个头像 + 一句话 + 箭头。用 flex 试过三种写法：
 *
 * | 试过的 | 结果 |
 * |---|---|
 * | 默认（`0 1 auto`） | 顶到箭头上，文字盖住箭头 |
 * | `min-width: 0` + `overflow: hidden` | 不重叠了，但文字被压成一列两三个字 |
 * | `flex: 1 1 auto` + `min-width: 62/78px` | 同上，`min-width` 只是把那个窄盒子撑大一点 |
 *
 * 根因是 **flex 的收缩按盒子算，不会因为字排不下就换行** —— 盒子被压缩之后，
 * 中文就一个两个地往下掉。所以换成**纯行内流**：头像 `inline-block`、
 * 文字 `inline`，宽度交给行内排版自己算。中文能在任意字之间断行，
 * 于是它会自然折成两行、占满剩余宽度。
 *
 * ⚠️ 底栏要同时挂 `.entry__foot--users`（`display: block`）—— 见下面那条。
 *
 * 头像压到 18px 才排得进：web 上那个 67px 是**整块卡片**的尺寸，
 * 这里是卡片的一条 39px 底栏。
 */
/*
 * ⚠️ 选择器必须是 `.entry span.entry__users`（0-2-1），**不能是 `.entry__users`**。
 *
 * 这个元素**本身就是 `<span>`**，所以同文件上面那条 `.entry span`（0-2-0）
 * 也匹配它 —— 单类选择器（0-1-0）压不过，`display: flex` 会把这里的 `inline` 顶掉。
 *
 * 这一条我踩了两次（字号那次也是同一个原因），所以写死在这里：
 * **这个卡片里凡是 span 上的覆盖规则，一律用 `.entry span.<类>` 的形状。**
 */
.entry span.entry__users { display: inline; }

.entry span.entry__users-text {
  margin-left: 8px;
  font-size: 10.5px;
  font-weight: 400;
  color: #d7d5e0;
}

.entry span.entry__users-text b { color: #fff; }

/*
 * 资料库那张卡**整个底栏**改成块级布局。
 *
 * 另外三张卡的底栏是 flex（`justify-content: space-between` 把描述和箭头推向两端），
 * 但那张卡里塞的是头像 + 文案，flex 的收缩语义在这儿帮倒忙（见上面那段试错记录）。
 * 换成 block 之后文字按行内流自然折行，箭头则脱离流钉在右下角。
 */
.entry span.entry__foot--users {
  display: block;
  /*
   * `.entry span` 是固定 39px 高，两行文字放不下（10.5px × 1.3 × 2 ≈ 27px + 头像一个行高）。
   * 改成自适应、只保底 39px —— 代价是这一张卡比另外三张略高，但网格里
   * `align-items` 默认 `stretch`，同行两张会一起被撑到一样高，看不出参差。
   */
  height: auto;
  min-height: 39px;
  padding: 6px 24px 6px 11px;
  line-height: 1.3;
}

.entry span.entry__foot--users em {
  position: absolute;
  right: 11px;
  top: 50%;
  transform: translateY(-50%);
}

.entry__users img {
  display: inline-block;
  vertical-align: middle;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  object-fit: cover;
  /* 头像互相压一点 —— 5 个平铺要 90px，压完约 66px。 */
  margin-right: -6px;
  background: #0d0d18;
}

/* ---------- 实时动态双列 ticker ---------- */
.notices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); overflow: hidden; border: 1px solid var(--wap-line); border-radius: 17px; background: rgba(255, 255, 255, .055); }
.notice { min-width: 0; padding: 13px 12px 12px; }
.notice + .notice { border-left: 1px solid var(--wap-line); }
.notice-title { display: flex; gap: 6px; align-items: center; margin: 0 0 8px; font-size: 12px; font-weight: 800; }
.notice-title i { width: 7px; height: 7px; border-radius: 50%; background: var(--wap-brand); flex: 0 0 auto; }
.notice-title span { background: var(--wap-brand); -webkit-background-clip: text; background-clip: text; color: transparent; }
.ticker { height: 39px; overflow: hidden; }
.ticker p { overflow: hidden; margin: 0; color: #d1cedb; font-size: 10px; line-height: 19px; text-overflow: ellipsis; white-space: nowrap; }

/*
 * 滚动动画。**不是固定 8 秒** —— 原型的 `animation: ticker 8s linear infinite` 是按
 * 「永远 3 行」写死的。这里用与行数绑定的时长（由组件内联给出 `--ticker-lines` 与
 * `--ticker-duration`），行数变了节奏不会跟着乱。
 *
 * 帧位与原型的 0/34/50/84/100 一一对应：每行停留 34%，移动占 16%。
 * 行数为 1 时不做动画（`lines <= 1` 由组件判断，不给这个类）。
 */
.ticker-track.is-animated {
  animation: wap-ticker var(--ticker-duration, 8s) linear infinite;
}
@keyframes wap-ticker {
  0%, 34% { transform: translateY(0); }
  50%, 84% { transform: translateY(calc(-1 * var(--ticker-line-height, 19px))); }
  100% { transform: translateY(calc(-2 * var(--ticker-line-height, 19px))); }
}

/* ---------- 资料库选择页（`/wap/library`，两个方形图入口） ---------- */
/*
 * 与 mini 的 `pages/library-hub` 同构：两个方形按钮上下排、在内容区里居中。
 *
 * ## 边长是**两条线取小的**（2026-10-11 修，用户报「没有缩小适配屏幕」）
 *
 * 1. **宽度线** —— 内容宽的 62%；
 * 2. **高度线** —— 顶栏与底栏之间那块里，两个方块各自分到的高度再缩 20%
 *    （mini 的 `ENTRY_SIDE_RATIO`），夹在 96px（mini 的下限）与 300px（桌面预览宽屏）之间。
 *
 * 原来只有宽度线，于是边长在任何屏上都等于「内容宽 × 62%」—— 在 390×844 上
 * 恰好等于 mini 的值，看不出问题；**短屏上却不会缩**：320×568 是 181（mini 123）、
 * 375×667 是 215（mini 163），方块会顶到底栏。mini 那套 JS 算式里 `ENTRY_SIDE_MAX`
 * 本来就取了「宽度」与「高度」两条上限的较小者，这里把它翻成 CSS。
 *
 * `236px` 的构成（与 mini 的 `MAIN_PADDING_H` + `LABEL_BLOCK_H` + `ENTRY_GAP` + 底栏让位同源）：
 * 顶栏 64 + 底栏让位 78 + `main` 上下内边距 26 + 标题块 56 + 两个方块间距 12。
 * 实测它给出的 320×568 → 123、375×667 → 163，与 mini 的算式**逐值一致**。
 *
 * 两行 `width` 是**渐进增强**：老内核不认 `dvh` / `min()` 时整条声明被丢掉，
 * 只剩上面那条纯宽度线（等于改动前的行为）—— 不要为了「干净」把兜底删掉。
 *
 * ⚠️ 方块上**没有** border / border-radius / background —— 图里已经带了整块按钮的
 * 圆角边框与底色，再画一圈描边会叠出双线、圆角对不上还会露角
 * （mini 的 `library-hub.wxss` 专门记过这一笔）。要改外观就去改图。
 */
.wap-hub-entries {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  /* 撑满标题以下那一整块，让两个方块在中间垂直居中（mini 的 `.entries { flex: 1 }`）。 */
  min-height: calc(100dvh - 236px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
.wap-hub-entry {
  display: block;
  /* 兜底：纯宽度线。 */
  width: clamp(96px, 62%, 300px);
  width: clamp(
    96px,
    min(62%, calc((100dvh - 236px - env(safe-area-inset-top) - env(safe-area-inset-bottom)) / 2 * 0.8)),
    300px
  );
  aspect-ratio: 1;
  overflow: hidden;
}
.wap-hub-entry img { display: block; width: 100%; height: 100%; }

/* ---------- 资料库 / Ai岗位 的目录网格（选择页点进去那一层） ---------- */
/*
 * **一行 3 个**（用户要求；原来是一行一个）。
 *
 * 390px 宽下每格约 116px —— 目录名大多是 4–6 个汉字（「AI工具的安装」
 * 「大模型基础」），放得下；超长的走 `word-break` 断行，不会撑破格子。
 * `minmax(0, 1fr)` 而不是 `1fr`：`1fr` 的最小尺寸是内容宽度，
 * 一个超长目录名会把整列撑开、把另外两列挤扁。
 */
.wap-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.wap-list a {
  display: flex;
  align-items: center;
  justify-content: center;
  /* 高度只有原来的三分之二（84 → 56，用户要求）。内边距同比收。 */
  min-height: 56px;
  padding: 8px 8px;
  border: 1px solid var(--wap-line);
  border-radius: 14px;
  background: #161624;
  color: #fff;
  font-size: 13px;
  line-height: 1.35;
  /* 格子窄，文字必须居中并允许断行 —— 否则长目录名会横向溢出。 */
  text-align: center;
  word-break: break-word;
  text-decoration: none;
}

/*
 * 这里**曾经有一个** `.wap-list em`（那个「›」小三角，从右侧挪到下方再转 90°）。
 * 用户要求去掉，所以组件里也不再渲染那个 `<em>` —— 样式和 DOM 一起删，
 * 免得留下一条谁也不知道给谁用的规则。
 */

.wap-group { margin: 20px 0 10px; font-size: 12px; color: #aaa8b7; letter-spacing: .04em; }
.wap-empty { padding: 24px 14px; border: 1px dashed var(--wap-line); border-radius: 14px; color: var(--wap-muted); font-size: 13px; text-align: center; }

/*
 * ---------- 课程卡（`/wap/course`，对应桌面那个「全部技术咨询方案」弹框） ----------
 *
 * 与资料库那页的纯文字网格**不是一套**：这里的卡片**带封面**（用户要求
 * 「有文字也要有图」），所以是「图上 + 标题下」的竖版卡，一行 2 个 ——
 * 3 个的话封面只剩 100px 宽，课名的封面图根本看不清是什么。
 *
 * ⚠️ 不复用 `shell-fixes.css` 的 `.notes-all-modal__*`：那是桌面弹窗的类，
 * WAP 页**不加载那份样式表**，引用了也没效果。
 */
.wap-course-group + .wap-course-group { margin-top: 6px; }

.wap-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.wap-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--wap-line);
  border-radius: 14px;
  background: #161624;
  color: #fff;
  text-decoration: none;
}

/*
 * 封面。**比 16:9 扁得多**（用户反馈「图片太大了」）。
 *
 * 两列栅格下每张卡只有约 178px 宽，16:9 的封面就是 100px 高 —— 加上标题
 * 一张卡 140px，一屏只放得下两组。压成 2:1 之后封面约 89px，一屏能看到四组，
 * 而图仍然是能认出是什么的那张。
 *
 * 固定比例（而不是 `max-height`）是为了让**有图没图的卡片一样高** ——
 * 后台新建的课大多没有封面，参差的栅格比图小更难看。
 */
.wap-card__cover {
  display: block;
  aspect-ratio: 2 / 1;
  overflow: hidden;
  background: rgba(255, 255, 255, .04);
}

.wap-card__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 没配封面：留一个空位，而不是让卡片塌下去。 */
.wap-card__cover--empty {
  background: repeating-linear-gradient(
    135deg,
    rgba(255, 255, 255, .035) 0 8px,
    transparent 8px 16px
  );
}

.wap-card__title {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 8px 10px;
  font-size: 12.5px;
  line-height: 1.35;
  word-break: break-word;
}

/* 极窄屏（<340px）三列太挤，退两列。320px 是本仓声明支持的最窄宽度。 */
@media (max-width: 339px) {
  .wap-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/*
 * 极窄屏下把资料库卡的头像收起来，空间全让给「海量资料免费获取」。
 *
 * 320px 时半张卡只有 139px：5 个头像（66px）+ 箭头（14px）之后只剩约 40px，
 * 而那句文案要 80px —— 结果是文字被压成一列一个字（实测截图）。
 * `overflow: hidden` 保证了它「不重叠」，但把六个字竖着排出来同样没法看。
 *
 * 本仓声明的支持下限是 360px（`docs/fullstack-requirements.md` §303），
 * 所以这条只是兜底，不影响正常机型 —— 那里头像与文案都完整显示。
 */
@media (max-width: 359px) {
  .entry__users img { display: none; }
}

/* ---------- 桌面预览（原型就这么写的：宽屏画成一张手机卡） ---------- */
/*
 * 这里**没有** `.tabbar` 了 —— 它的「卡片内收窄」那一半跟着 tab 的其余样式
 * 一起搬进了 `WapTabBar.module.css`（那里必须用 `:global(.wap)` 才选得中，
 * 因为 module 的类名是哈希过的）。搬家的原因见那个文件的开头：
 * 这个组件现在也挂在 `(site)` 的详情页上，而那里加载着 `style.min.css`。
 */
@media (min-width: 481px) {
  body { padding: 20px; }
  .wap { border-radius: 28px; box-shadow: 0 28px 70px rgba(0, 0, 0, .45); }
}

@media (max-width: 355px) {
  .hero { min-height: 238px; }
  .hero-title { font-size: 24px; }
}

/*
 * 尊重系统的「减少动态效果」。本仓其它自动播放处（`useRevealOnScroll`）也查这个 ——
 * ticker 一直在动对前庭敏感的人不友好，关掉动画比留着更合适（文案本来就全在 DOM 里）。
 */
@media (prefers-reduced-motion: reduce) {
  .ticker-track.is-animated { animation: none; }
  .entry img { transition: none; }
}

/* ---------- 轮播的左右切换按钮 ---------- */
/*
 * 按钮的**外观与定位**复用 `shell-fixes.css` 里已有的 `.hero__nav`
 * （半透明圆钮、`position: absolute` + 左右 10px + 垂直居中）—— 那份是全站加载的，
 * 所以这里只需要补 WAP 缺的那几条。
 *
 * ⚠️ **为什么不能靠桌面那份**：桌面把图标的尺寸与旋转挂在
 * `.hero .hero__art .hero__nav img`（0,3,1）上 —— 那是 (0,2,1) 的
 * `.hero__art img { width: 100% }` 会赢，所以必须带 `.hero__art` 前缀。
 * 但 **WAP 的按钮不在 `.hero-art` 里面**（那里是图片自身或包着图的 `<a>`，装不下），
 * 于是那条命中不了，图标会退回 chevron 的原尺寸、而且不旋转（看着是两个向下的 V）。
 * 这里按 WAP 的结构重写，特异性 (0,2,1) 与 `.hero-art img` 同档但写在后面。
 */
/*
 * **z-index 必须比 `.hero-copy`(2) 和 `.hero-foot`(3) 都高。**
 *
 * `.hero-copy` 是 `left: 20px; right: 18px` —— 它横跨整条 hero，虽然里面只有文字，
 * 但那一层会把右按钮整个盖住。实测点不到，Playwright 报的是
 * `div.hero-copy intercepts pointer events`（左按钮在 `.hero-copy` 的 left 20px 之外，
 * 所以只有右边坏 —— 这种「一边好一边坏」最容易误判成选择器写错）。
 */
.hero .hero__nav {
  z-index: 4;
  /*
   * **尺寸放大一倍**（用户 2026-09-22）：30x30 → 60x60。
   *
   * `shell-fixes.css` 里那份基础样式是小屏 30px、桌面 30px（两档），
   * 这里按 WAP 覆盖成 60 —— 手机上图占满整宽，30px 的按钮太小、不好点。
   * 特异性 (0,2,0) 高于那边的 (0,1,0)，且 `prototype-wap.css` 只在 WAP 页加载。
   */
  width: 60px;
  height: 60px;
}

.hero .hero__nav img {
  width: 28px;
  height: auto;
}

/* chevron.svg 是个向下的 V，左右各转 90 度。 */
.hero .hero__nav--prev img {
  transform: rotate(90deg);
}

.hero .hero__nav--next img {
  transform: rotate(-90deg);
}
