/* ==========================================================================
   NZEP 资料库 · assets/portal.css —— 门户页（portal.html）专用样式
   --------------------------------------------------------------------------
   只被 portal.html 引用，不往全站共用的 nzep.css 里加东西。

   版式（2026-10 改版，用户口径：电脑端不要侧边栏，六条主线一屏看全）：
     ≥1000px  整页宽度：左边 3×3 的 bento 网格（资料总览 2×2，是最大的格子），
              右边一栏放「门户公告」与「用户资料卡」。整页高度按视口压缩，
              顶栏与页脚之间的空间正好放下六格 + 两栏，不用滚动。
     ≤999px   单列/两列自然流动：公告与资料卡排在格子上面（可读、可点），
              格子仍是两列，资料总览整行。

   视觉：沿用资料库的纸白底、衬线标题、深色顶栏，另外取两枚本站强调色
   —— 朱红 #c8102e 与墨黑 #0f1115（圆角统一 4px）；登录链接用蓝色 #1a5fb4。
   图标与预览图全是手绘风的内联 SVG（描边 1.6 / 圆头圆角），没有外部图片、
   没有图标字体：离线、无 JS、爬虫看到的都是同一份矢量图。
   ========================================================================== */

/* --------------------------------------------------------------- 整页骨架
   桌面端把页面做成「顶栏 / 内容 / 页脚」三段，内容段吃掉剩余高度：
   格子按行均分，窗口矮的时候是格子变矮，而不是整页长出滚动条。 */
body.pt-page {
  display: flex;
  flex-direction: column;
  /* 高度必须是**确定值**，flex 子项才会按剩余空间收缩：
     只写 min-height 时，内容（比如很长的公告）会把整页顶高。 */
  height: 100vh;
  height: 100dvh;
  min-height: 100vh;
  min-height: 100dvh;
}
body.pt-page .w-topbar { flex: 0 0 auto; }
body.pt-page .w-layout { flex: 1 1 auto; align-items: stretch; min-height: 0; max-width: 84rem; }
/* 页脚宽度（2026-11 修「各组挤在中间、两侧留白很大」）：
   body 是纵向 flex 容器，而 nzep.css 给 .w-footer 的 margin:0 auto 在**交叉轴**上
   会取消 flex 的 stretch —— 页脚于是按 max-content 收缩成 ~860px 的窄条再居中，
   1280 时左右各空 210~270px、1920 时各空 530px，所以各链接组全挤在中间。
   这里给它确定宽度（100%，上限与 .w-layout 相同的 84rem），页脚就与正文左右对齐、
   铺满整行；高度仍由 flex:0 0 auto 决定，桌面一屏的版式不变。 */
body.pt-page .w-footer {
  flex: 0 0 auto;
  width: 100%;
  max-width: 84rem;
}

/* 页脚排布（同上，2026-11）：链接组单独占上面一整行 —— 组与组均分整行
   （.f-nav 的 auto-fit 轨道会把三组拉成等宽、最后一组贴住内容右边），
   品牌块与法律条并排放在下面一行：品牌在左、法律条在右。
   这样三组链接从正文左边缘一直铺到右边缘，不再缩在中间；
   纵向仍然只有两行（链接组 / 品牌+法律条），总高度与改动前基本相同
   （品牌与法律条从上下两行并成一行），一屏仍然放得下。 */
@media (min-width: 1000px) {
  body.pt-page .w-footer {
    grid-template-columns: minmax(11rem, 14rem) minmax(0, 1fr);
    padding: 1rem 1rem 1.4rem;
  }
  body.pt-page .w-footer .f-nav { grid-column: 1 / -1; grid-row: 1; }
  body.pt-page .w-footer .f-brand { grid-column: 1; grid-row: 2; }
  body.pt-page .w-footer .w-legal {
    grid-column: 2; grid-row: 2;
    margin-top: 0; padding-top: 0; border-top: 0;
    align-self: center;
  }
}

/* 桌面端不要侧边栏：body.no-side 已经在 nzep.css 里把整列藏掉（手机端仍是抽屉），
   这里再钉一次，防止别的样式把布局撑回两栏。 */
@media (min-width: 768px) {
  body.pt-page .w-side { display: none; }
}

/* 桌面端隐藏正文里的「页脚介绍块」（#siteFooter，授权说明那一块）：这一页是导航页，
   六格 + 两栏要在顶栏与页脚之间一屏放下；授权说明仍出现在每个内容页，
   而站点页脚（#wFooter）原样保留。手机上它照旧在文末出现。 */
@media (min-width: 1000px) {
  body.pt-page #siteFooter { display: none; }
}

.pt-main {
  padding: .35rem 1rem 0;
  display: flex;
  flex-direction: column;
  width: 100%;
}
body.pt-page #view {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  width: 100%;
}

.pt-portal {
  /* 这一页自己的调色板。父级 nzep.css 的变量保持不动，避免影响别的页面 */
  --pt-red: #c8102e;
  --pt-blue: #1a5fb4;
  --pt-ink: #0f1115;
  --pt-paper: #fbfaf7;
  --pt-line: #d9d5cc;
  --pt-muted: #64625d;
  --pt-pad: .7rem .8rem;

  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  padding: .2rem 0 0;
  color: var(--pt-ink);
}

/* --------------------------------------------------------------- 页头
   只有两行：左边问候语（未登录时是蓝色登录/注册链接），右边一句跳转简介。 */
.pt-head {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .15rem 1.2rem;
}

.pt-greet {
  margin: 0;
  min-height: 2.1rem;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.3rem, 1.05rem + .85vw, 1.7rem);
  line-height: 1.35;
  letter-spacing: -.01em;
  color: var(--pt-ink);
}
/* 会话还没确认：占住位置但一个字都不画，避免先闪一个错的状态 */
.pt-greet[data-pt-state="pending"] > * { visibility: hidden; }
.pt-greet [data-pt-greet] { display: none; }
.pt-greet[data-pt-state="in"] [data-pt-greet="in"],
.pt-greet[data-pt-state="out"] [data-pt-greet="out"] { display: inline; }

.pt-greet-nick {
  font-weight: 700;
  overflow-wrap: anywhere;
}
.pt-greet-out {
  /* 点按区：这一条是页头最显眼的入口，桌面上也给到 44px 的最小高度
     （登录后它根本不显示，所以不影响登录态的一屏版式）。 */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--pt-blue);
  text-decoration: none;
  border-bottom: 1px solid rgba(26, 95, 180, .35);
  transition: border-color .16s ease, color .16s ease;
}
/* 上面那条 display:inline 的切换规则特异性更高，这里再钉一次（桌面端 44px 点按区） */
.pt-greet[data-pt-state="out"] .pt-greet-out {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.pt-greet-out:hover,
.pt-greet-out:focus-visible {
  color: #0f4a91;
  border-bottom-color: currentColor;
}
.pt-greet-out:focus-visible { outline: 2px solid var(--pt-blue); outline-offset: 3px; }

.pt-intro {
  margin: 0;
  font-size: .82rem;
  line-height: 1.6;
  color: var(--pt-muted);
  text-align: right;
}

/* --------------------------------------------------------------- 两栏 */
.pt-cols {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 19rem;
  /* 单行必须**撑满**外层已经算好的高度：auto 行会被公告正文顶高，整页就滚起来了 */
  grid-template-rows: minmax(0, 1fr);
  gap: 14px;
  margin-top: .7rem;
}

/* --------------------------------------------------------------- 格子 */
.pt-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(3, minmax(0, 1fr));
  gap: 12px;
  min-height: 0;
}
/* 预览图：手机/平板上保留（和改版前一样），桌面端六格一屏时让位给图标 */
.pt-preview {
  display: block;
  margin-top: auto;
  padding: .35rem .4rem .3rem;
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background:
    radial-gradient(circle at 1px 1px, rgba(15, 17, 21, .09) 1px, transparent 1.2px) 0 0 / 11px 11px,
    #fff;
  overflow: hidden;
}
.pt-hero .pt-preview {
  border-color: rgba(245, 242, 234, .22);
  background:
    radial-gradient(circle at 1px 1px, rgba(245, 242, 234, .15) 1px, transparent 1.2px) 0 0 / 11px 11px,
    rgba(255, 255, 255, .03);
  margin-top: .25rem;
}
@media (min-width: 1000px) {
  .pt-preview { display: none; }
}

.pt-tile {
  position: relative;
  display: flex; flex-direction: column; gap: .4rem;
  min-width: 0; min-height: 0;
  padding: var(--pt-pad);
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background: var(--pt-paper);
  color: var(--pt-ink);
  text-decoration: none;
  box-shadow: 3px 4px 0 rgba(15, 17, 21, .045);
  overflow: hidden;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.pt-tile:hover,
.pt-tile:focus-visible {
  color: var(--pt-ink);
  text-decoration: none;
  border-color: var(--pt-ink);
  box-shadow: 5px 7px 0 rgba(15, 17, 21, .08);
  transform: translateY(-2px);
}
.pt-tile:focus-visible { outline: 2px solid var(--pt-red); outline-offset: 2px; }
.pt-tile:active { transform: translateY(0); }

/* 资料总览：2×2，是整页最大的格子（2026-11 从「资料主页」改名为「资料总览」） */
.pt-hero {
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
  background: var(--pt-ink);
  border-color: var(--pt-ink);
  color: #f5f2ea;
  box-shadow: 4px 5px 0 rgba(15, 17, 21, .14);
  padding: .9rem 1rem;
}
.pt-hero:hover,
.pt-hero:focus-visible { color: #fff; border-color: var(--pt-red); box-shadow: 6px 8px 0 rgba(15, 17, 21, .18); }

.pt-tile-top {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  min-height: 1.1rem; flex: 0 0 auto;
  position: relative; z-index: 1;
}
.pt-no {
  font-family: var(--serif);
  font-size: .78rem; line-height: 1.4; letter-spacing: .12em;
  color: var(--pt-muted);
}
.pt-hero .pt-no { color: rgba(245, 242, 234, .55); }

.pt-go {
  flex: 0 0 auto;
  width: 1rem; height: 1rem;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .55;
  transition: transform .16s ease, opacity .16s ease;
}
.pt-tile:hover .pt-go,
.pt-tile:focus-visible .pt-go { opacity: 1; transform: translate(2px, -2px); }

.pt-badge {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .1rem .4rem;
  border-radius: 4px;
  background: var(--pt-red);
  color: #fff;
  font-family: var(--sans);
  font-size: .7rem; font-weight: 600; line-height: 1.5;
  letter-spacing: .05em;
}

.pt-tile-mid {
  display: flex; align-items: center; gap: .7rem;
  min-width: 0; min-height: 0;
  flex: 1 1 auto;
}

.pt-tile-text { display: block; min-width: 0; flex: 1 1 auto; }

.pt-t {
  display: block;
  font-family: var(--serif);
  font-size: 1.02rem; font-weight: 700; line-height: 1.3;
  color: var(--pt-ink);
}
.pt-hero .pt-t { font-size: clamp(1.3rem, 1.05rem + .7vw, 1.65rem); font-weight: 400; color: #fff; }

.pt-k {
  display: block; margin-bottom: .1rem;
  font-family: var(--sans);
  font-size: .7rem; font-weight: 600; line-height: 1.4;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--pt-red);
}

.pt-d {
  display: block; margin-top: .15rem;
  font-size: .76rem; line-height: 1.5;
  color: var(--pt-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pt-hero .pt-d { max-width: 26rem; color: rgba(245, 242, 234, .72); -webkit-line-clamp: 3; }

.pt-more {
  display: inline-block; margin-top: .35rem;
  font-size: .76rem; font-weight: 600; line-height: 1.5;
  color: #f5f2ea;
  border-bottom: 1px solid rgba(245, 242, 234, .4);
}

.pt-nick {
  display: inline-block;
  max-width: 8rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: bottom;
  color: var(--pt-ink); font-weight: 700;
}
.pt-nick:empty { display: none; }
.pt-account[data-pt-state="in"] .pt-nick::before { content: " · "; color: var(--pt-muted); font-weight: 400; }

/* 账号格子在两种状态间只换内容，不换位置 */
.pt-account[data-pt-state="out"] [data-pt-when="in"],
.pt-account[data-pt-state="in"] [data-pt-when="out"] { display: none; }

/* --------------------------------------------------------------- 图标 */
.pt-ico {
  flex: 0 0 auto;
  display: block;
  width: clamp(52px, 7.4vh, 84px);
  height: clamp(52px, 7.4vh, 84px);
  overflow: visible;
}
.pt-hero .pt-ico { width: clamp(72px, 11.5vh, 124px); height: clamp(72px, 11.5vh, 124px); }

.pt-ico .st-ink,
.pt-preview .pv-ink,
.pt-preview .st-ink {
  fill: none;
  stroke: var(--pt-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pt-ico .st-soft {
  fill: none;
  stroke: var(--pt-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .5;
}
.pt-preview .pv-soft,
.pt-preview .st-soft {
  fill: none;
  stroke: var(--pt-ink);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .5;
}
.pt-ico .st-red,
.pt-preview .pv-red,
.pt-preview .st-red {
  fill: none;
  stroke: var(--pt-red);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pt-ico .fl-red,
.pt-preview .pv-red-fill {
  fill: var(--pt-red);
  stroke: none;
}
.pt-preview .pv-frame {
  fill: rgba(255, 255, 255, .55);
  stroke: var(--pt-line);
  stroke-width: 1.2;
}

/* 主入口是深色底：线稿换成浅纸色，朱红保持 */
.pt-hero .st-ink { stroke: #f5f2ea; }
.pt-hero .st-soft { stroke: #f5f2ea; opacity: .45; }
.pt-hero .st-red { stroke: var(--pt-red); }
.pt-hero .pv-ink { stroke: #f5f2ea; }
.pt-hero .pv-soft { stroke: #f5f2ea; opacity: .42; }
.pt-hero .pv-red { stroke: #ff5a70; }
.pt-hero .pv-frame { fill: rgba(255, 255, 255, .03); stroke: rgba(245, 242, 234, .28); }
.pt-hero .pv-red-fill { fill: #ff5a70; }

/* 预览图只在没有高度压力的版式里出现（这里是为将来留的钩子） */
.pt-preview svg { display: block; width: 100%; height: auto; }

/* --------------------------------------------------------------- 右侧面板 */
.pt-side {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  min-width: 0;
}

.pt-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: .75rem .85rem;
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background: #fff;
  box-shadow: 3px 4px 0 rgba(15, 17, 21, .035);
}
.pt-panel[hidden] { display: none !important; }

.pt-panel-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding-bottom: .45rem;
  border-bottom: 1px solid var(--pt-line);
}
.pt-panel-title {
  margin: 0;
  font-family: var(--serif);
  font-size: .9rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--pt-ink);
}

.pt-mini {
  flex: 0 0 auto;
  min-height: 1.9rem;
  padding: .1rem .5rem;
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background: #fff;
  color: var(--pt-blue);
  font-family: var(--sans);
  font-size: .74rem;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
}
.pt-mini:hover { border-color: var(--pt-blue); }
.pt-mini[hidden] { display: none !important; }

/* 资料库简介（2026-11 加）：门户就是站点首页，右栏第一块面板写"这个站是什么"。
   它是**静态 HTML 里的真文字**（爬虫不跑 JS 也读得到），所以必须真渲染出来，
   不能靠脚本注入。为了不把六格挤出一屏：
     · 这块面板放在**右栏**（网格的行高由 .pt-cols 决定，右栏再长也不会顶高网格）；
     · flex:0 1 auto + 正文 overflow:auto —— 窗口特别矮时是它自己内部滚动，
       而不是把整页撑出滚动条。 */
.pt-about { flex: 0 1 auto; }
.pt-about-p {
  flex: 1 1 auto;
  min-height: 0;
  margin: .55rem 0 0;
  overflow: hidden auto;
  /* 手机上的滚动条：这里是**唯一**的滚动容器（面板 body 不再是嵌套滚动层），
     touch-action:pan-y 明确告诉浏览器「竖着滑是滚这个框」，overscroll-behavior:auto
     让框滑到尽头后手势能正常交还给整页（2026-11 用户报「手指在框里滑不动」）。 */
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: auto;
  font-size: .76rem;
  line-height: 1.7;
  color: var(--pt-muted);
}

/* 公告：纯文本 + 换行；太长时在面板内部滚动，绝不把版式撑破 */
.pt-notice { flex: 1 1 auto; }
.pt-notice-body {
  flex: 1 1 auto;
  min-height: 2.6rem;
  margin-top: .55rem;
  overflow: hidden auto;
  /* 同 .pt-about-p：单层滚动容器 + 竖滑授权 + 到头后把手势还给整页 */
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: auto;
}
.pt-notice-body[data-pt-state="pending"] { visibility: hidden; }
.pt-notice-empty {
  margin: 0;
  font-size: .78rem;
  line-height: 1.6;
  color: var(--pt-muted);
}
.pt-notice-empty[hidden] { display: none; }
.pt-notice-text {
  margin: 0;
  font-size: .8rem;
  line-height: 1.75;
  color: var(--pt-ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.pt-notice-text[hidden] { display: none; }

.pt-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2rem;
  padding: .25rem .8rem;
  border: 1px solid var(--pt-ink);
  border-radius: 4px;
  background: #fff;
  color: var(--pt-ink);
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 600;
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
}
.pt-btn:hover { background: var(--pt-ink); color: #fff; text-decoration: none; }
.pt-btn-primary { background: var(--pt-red); border-color: var(--pt-red); color: #fff; }
.pt-btn-primary:hover { background: #a30d26; border-color: #a30d26; color: #fff; }

/* 用户资料卡：头像 + 昵称 + 个人中心；未登录时整块 hidden */
.pt-card { flex: 0 0 auto; }
.pt-card-row {
  display: flex;
  align-items: center;
  gap: .65rem;
  min-width: 0;
  margin: .6rem 0 .55rem;
}
.pt-avatar {
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  border: 1px solid var(--pt-line);
  background: #ebebe7;
  object-fit: cover;
}
.pt-card-meta { min-width: 0; flex: 1 1 auto; }
.pt-card-nick {
  display: block;
  font-family: var(--serif);
  font-size: .98rem;
  line-height: 1.4;
  color: var(--pt-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pt-profile-btn { width: 100%; }

/* --------------------------------------------------- 超级管理员「门户修改」
   入口在门户内容的最下面，**默认 hidden**：普通读者 / 非管理员 / 爬虫拿到的
   HTML 里它都是隐藏的，只有服务端确认 role=admin 后 portal.js 才显示。
   放在 .pt-portal 的纵向 flex 末尾（flex:0 0 auto），管理员看到时只会把
   上面的格子压矮一点，不会把整页撑出滚动条；读者完全不受影响。 */
.pt-admin {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  padding-top: .45rem;
}
.pt-admin[hidden] { display: none; }
.pt-admin-btn {
  min-height: 2rem;
  padding: .15rem .9rem;
  border: 1px dashed var(--pt-line);
  border-radius: 4px;
  background: transparent;
  color: var(--pt-muted);
  font-family: var(--sans);
  font-size: .74rem;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
}
.pt-admin-btn:hover,
.pt-admin-btn:focus-visible {
  border-style: solid;
  border-color: var(--pt-ink);
  color: var(--pt-ink);
}
.pt-admin-btn:focus-visible { outline: 2px solid var(--pt-blue); outline-offset: 2px; }

/* --------------------------------------------------------------- 编辑模态框
   四块纯文本：网站介绍 中/英、门户公告 中/英。桌面两列（2×2），窄屏一列。
   面板自己滚（max-height: 92vh），底下的页面锁住滚动；控件在手机上 ≥44px。
   z-index 高于顶栏抽屉（1000），低于全站 toast（见 nzep.css）。 */
body.pt-modal-open { overflow: hidden; }
.pt-modal {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.pt-modal[hidden] { display: none; }
.pt-modal-mask {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: rgba(15, 17, 21, .52);
}
.pt-modal-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(46rem, 100%);
  max-height: min(92vh, 54rem);
  border: 1px solid var(--pt-ink);
  border-radius: 6px;
  background: var(--pt-paper);
  box-shadow: 0 18px 50px rgba(15, 17, 21, .28);
  overflow: hidden;
}
.pt-modal-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  padding: .8rem 1rem .6rem;
  border-bottom: 1px solid var(--pt-line);
}
.pt-modal-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--pt-ink);
}
.pt-modal-x {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background: #fff;
  color: var(--pt-ink);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
}
.pt-modal-x:hover { border-color: var(--pt-ink); }
.pt-modal-x:focus-visible { outline: 2px solid var(--pt-blue); outline-offset: 1px; }
.pt-modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: .7rem 1rem .2rem;
}
.pt-modal-hint {
  margin: 0 0 .6rem;
  font-size: .74rem;
  line-height: 1.55;
  color: var(--pt-muted);
}
.pt-edit-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .55rem .9rem;
}
.pt-edit-field { min-width: 0; display: flex; flex-direction: column; gap: .22rem; }
.pt-edit-lbl {
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--pt-muted);
}
.pt-modal-input {
  width: 100%;
  min-height: 5.2rem;
  resize: vertical;
  padding: .45rem .5rem;
  border: 1px solid var(--pt-line);
  border-radius: 4px;
  background: #fff;
  color: var(--pt-ink);
  font-family: var(--sans);
  font-size: .8rem;
  line-height: 1.6;
}
.pt-modal-input[aria-invalid="true"] { border-color: var(--pt-red); background: #fff8f8; }
.pt-modal-input:focus { outline: 2px solid var(--pt-blue); outline-offset: 1px; border-color: var(--pt-blue); }
.pt-modal-err {
  margin: .55rem 0 .2rem;
  padding: .35rem .45rem;
  border-left: 3px solid var(--pt-red);
  background: #fdf3f4;
  color: #8d1024;
  font-size: .76rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.pt-modal-err[hidden] { display: none; }
.pt-modal-foot {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  gap: .5rem;
  padding: .65rem 1rem .8rem;
  border-top: 1px solid var(--pt-line);
}
.pt-modal-foot .pt-btn { min-height: 2.25rem; }


/* --------------------------------------------------------------- 断点 */

/* 平板：两列，资料主页整行；面板排到格子上方 */
@media (max-width: 999px) {
  body.pt-page { display: block; height: auto; }
  .pt-main { padding: .5rem .8rem 1.6rem; }
  body.pt-page #view { display: block; }
  .pt-portal { display: block; padding-top: 0; }
  .pt-head { gap: .35rem 1rem; }
  .pt-intro { text-align: left; }
  .pt-cols { display: flex; flex-direction: column; gap: 12px; margin-top: .8rem; }
  .pt-side { order: -1; gap: 10px; }
  .pt-notice-body { max-height: 26vh; min-height: 2rem; }
  .pt-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: none;
    grid-auto-rows: auto;
    gap: 10px;
  }
  .pt-hero { grid-column: 1 / -1; grid-row: auto; }
  .pt-hero .pt-tile-mid { flex-direction: row; align-items: center; }
  .pt-tile { padding: .8rem .85rem; gap: .45rem; }
  .pt-ico { width: 64px; height: 64px; }
  .pt-hero .pt-ico { width: 96px; height: 96px; }
  .pt-d { -webkit-line-clamp: 3; }
}

/* 手机：两列小格，资料主页整行，图标在文字上方 —— 和改版前一样 */
/* 顶栏右上角「登录」：全站桌面端 2.5rem（40px）、手机端 1.65rem（26px）。
   门户页统一撑到 44px 的最小点按高度（只作用于 body.pt-page，别的页面一个字节都不动）。 */
body.pt-page .w-topbar .top-login {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  min-height: 44px;
}

@media (max-width: 767px) {
  .pt-main { padding: .45rem .8rem 1.2rem; }
  .pt-greet { min-height: 1.9rem; font-size: 1.3rem; }
  /* 登录/注册链接自己也要是 44px 高的点按区（选择器要比 data-pt-state 那条更具体） */
  body.pt-page .pt-greet[data-pt-state="out"] [data-pt-greet="out"] {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .pt-intro { font-size: .78rem; }
  .pt-grid { gap: 10px; }
  .pt-hero { padding: .9rem .9rem .8rem; }
  .pt-hero .pt-tile-mid { flex-direction: column; align-items: flex-start; gap: .55rem; }
  .pt-hero .pt-t { font-size: 1.35rem; }
  .pt-hero .pt-ico { width: 104px; height: 104px; }
  .pt-tile { padding: .7rem .75rem; gap: .45rem; }
  .pt-ico { width: 56px; height: 56px; }
  .pt-tile-mid { flex-direction: column; align-items: flex-start; gap: .3rem; }
  .pt-t { font-size: .98rem; }
  .pt-d { margin-top: .15rem; font-size: .74rem; line-height: 1.55; }
  .pt-badge { font-size: .68rem; }
  /* 手机上所有可点的地方都要 ≥44px（小圆角按钮也要） */
  .pt-mini { min-height: 44px; padding: .3rem .7rem; font-size: .78rem; }
  .pt-btn { min-height: 44px; }
  .pt-modal-input { font-size: 16px; }
  .pt-admin-btn { min-height: 44px; padding: .35rem 1rem; }
  /* 模态框在手机上铺满可用宽度，四个字段排成一列；面板自己滚，控件 ≥44px */
  .pt-modal { padding: .4rem; }
  .pt-modal-panel { width: 100%; max-height: 94vh; }
  .pt-modal-head { padding: .55rem .8rem .5rem; }
  .pt-modal-x { width: 44px; height: 44px; }
  .pt-modal-body { padding: .6rem .8rem .2rem; }
  .pt-edit-grid { grid-template-columns: minmax(0, 1fr); }
  .pt-modal-input { min-height: 5.4rem; }
  .pt-modal-foot { padding: .55rem .8rem .7rem; }
  .pt-modal-foot .pt-btn { flex: 1 1 0; min-height: 44px; }
  .pt-avatar { width: 2.75rem; height: 2.75rem; }
}

@media (max-width: 359px) {
  .pt-greet { font-size: 1.15rem; }
  .pt-tile { padding: .65rem; }
  .pt-d { font-size: .72rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pt-tile, .pt-go, .pt-greet-out { transition: none; }
  .pt-tile:hover, .pt-tile:focus-visible { transform: none; }
}

/* ── 2026-10-31：门户公告/简介在窄窗口与长文本下的排版修复 ─────────────────────────────────────
   用户反馈：浏览器缩小时，门户公告文字会溢出、或被压得又挤又紧。
   根因：面板内的文本容器只有 overflow:auto，没有 min-width:0 与断词规则；
   窄窗口下长邮箱/英文长词会把内容顶出容器，字号又偏小显得拥挤。
   这里补齐：文本容器可断词、面板不超出、窄屏适当放大正文字号并让面板内部滚动。 */
.pt-notice, .pt-about { min-width: 0; overflow: hidden; }
.pt-notice-body, .pt-about-p, .pt-notice-text, .pt-modal-input, .pt-panel-body {
  min-width: 0; max-width: 100%;
  overflow-wrap: anywhere; word-break: break-word; hyphens: auto;
}
/* 公告正文**不是**滚动容器：它只是一个自动增高、可断词的文本块。
   （2026-11 用户报「公告框手指滑不动」：这里原来还有 overflow-y:auto，
   在 .pt-notice-body 里面又套了一层滚动层 —— 内层永远没有溢出、外层才是滚动的那个，
   手机上手指的滚动目标于是被内层抢走/绕过。滚动只保留 .pt-notice-body 一层。） */
.pt-notice-text { white-space: pre-wrap; overflow: visible; }
/* 窄屏：面板内部滚动，不允许把整页顶出横向滚动条 */
@media (max-width: 1000px) {
  .pt-cols { grid-template-columns: minmax(0, 1fr); }
  .pt-notice-body, .pt-about-p { max-height: 40vh; }
}
/* 更窄的窗口：宁可放大字号 + 内部滚动，也不要缩成一团 */
@media (max-width: 600px) {
  .pt-about-p { font-size: .84rem; line-height: 1.75; }
  .pt-notice-text { font-size: .84rem; line-height: 1.65; }
  .pt-panel { padding: .7rem .75rem; }
  .pt-notice-body, .pt-about-p { max-height: 46vh; }
}

/* 2026-11 修「手机端关于本站 / 门户公告文本框手指滑不动」─────────────────────────────
   实测 390×844 的根因：≤999px 后右栏是普通纵向堆叠（.pt-cols 变 flex column，
   .pt-side 没有确定高度），两块面板按文字长到满屏；.pt-about-p / .pt-notice-body 上的
   `max-height: 46vh` 永远碰不到，于是 scrollHeight == clientHeight —— **框里没有可滚的东西**，
   手指在框内上下滑，浏览器只能把整页滚走（用户口径就是"滑不动"）。
   这里给两块面板一个视口相关的最大高度：正文区成为真正的滚动窗口，
   短文案时面板仍按内容高度显示（max-height 不会把面板撑高），不会被硬拉成一块空白。
   `max(…, 11rem)` 是给**横屏**兜底：高只有 390 时 30vh 只剩 117px，会把本来就放得下的
   短文也切掉；加一个下限后横屏仍是"放得下就不滚"。
   桌面端（≥1000px）不受影响：那边高度由 .pt-cols 的网格行给定。 */
@media (max-width: 999px) {
  .pt-about { max-height: max(30vh, 11rem); }
  .pt-notice { max-height: max(32vh, 11rem); }
  /* 正文必须能被压进窗口，滚动条才会落在它自己身上（而不是把面板顶高） */
  .pt-about-p, .pt-notice-body { min-height: 0; }
}

/* 2026-10-31：英文界面（/en/）溢出修复 ──────────────────────────────────────────
   英文文案普遍比中文长 1.5–2 倍（站介、公告、按钮、标题），同一套栅格下更容易把容器顶宽。
   这里只针对英文页面做“可折行 + 可收缩”的兜底，不改变中文版与整体排版。 */
html[data-lang="en"] body.pt-page { overflow-x: clip; }
html[data-lang="en"] .pt-tile .pt-t,
html[data-lang="en"] .pt-tile .pt-d,
html[data-lang="en"] .pt-tile .pt-more,
html[data-lang="en"] .pt-panel-title,
html[data-lang="en"] .pt-notice-text,
html[data-lang="en"] .pt-about-p,
html[data-lang="en"] .pt-greet,
html[data-lang="en"] .pt-intro,
html[data-lang="en"] .pt-card-name,
html[data-lang="en"] .pt-profile-btn {
  min-width: 0; max-width: 100%;
  overflow-wrap: anywhere; word-break: break-word; hyphens: auto;
}
html[data-lang="en"] .pt-panel-head { flex-wrap: wrap; row-gap: .35rem; }
html[data-lang="en"] .pt-panel-head .pt-mini { white-space: normal; }
html[data-lang="en"] .pt-btn, html[data-lang="en"] .pt-mini { white-space: normal; text-align: center; }
@media (max-width: 1240px) {
  html[data-lang="en"] .pt-cols { grid-template-columns: minmax(0, 1fr); }
  html[data-lang="en"] .pt-side { order: -1; }
}
@media (max-width: 600px) {
  html[data-lang="en"] .pt-about-p,
  html[data-lang="en"] .pt-notice-text { font-size: .84rem; line-height: 1.7; }
}
