/* ==========================================================================
   门户区块 · 公共骨架
   落点：web/static/widgets/css/portal_base.css
   由每个区块小部件**各自注册**（见 `BaseWidget::$cssFiles` / `afterRun()`）；
   同页多个小部件注册同一文件时框架自动去重 ⇒ 只出一个 <link>。
   目的：单个小部件被任何主题模板单独调用时也自带骨架，不依赖页面级样式。
   颜色一律走 --c-* 语义 token（换肤生效）；间距/圆角走 tokens 的尺度变量。
   ========================================================================== */

/* 兜底：门户壳只加载 tokens.css 时没有 base.css 的 reset */
.ph,
.ph *,
.ph *::before,
.ph *::after { box-sizing: border-box; }

/* ── iconfont 字体图标：门户设计系统**自托管**（2026-10-11 用户口径：门户不再依赖旧 common-style.css）──
   学科分类件 / lab-center 入口件等用 `<span class="iconfont">` 的门户件，此前隐式靠旧
   `common/css/common-style.css` 的 `@font-face` + `.iconfont{}` 才能显字。这里把同一份声明
   纳入设计系统骨架 ⇒ 布局摘掉 common-style.css 后门户件仍正常。
   字体二进制资源暂留 `common/fonts/`（P5 收口随旧目录一并迁移到设计系统资源目录）。 */
@font-face {
    font-family: 'iconfont';
    src: url('../../common/fonts/iconfont.eot');
    src: url('../../common/fonts/iconfont.eot?#iefix') format('embedded-opentype'),
         url('../../common/fonts/iconfont.woff2') format('woff2'),
         url('../../common/fonts/iconfont.woff') format('woff'),
         url('../../common/fonts/iconfont.ttf') format('truetype'),
         url('../../common/fonts/iconfont.svg#iconfont') format('svg');
}
.iconfont {
    font-family: 'iconfont' !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.ph__wrap {
    width: 100%;
    max-width: var(--layout-container-max, 1200px);
    margin: 0 auto;
    padding: 0 var(--layout-gutter, 24px);
}

/* ── 区块骨架：左对齐区块头 + 一条**看得见**的线 + 标题装饰条 ──
   2026-10-09 用户口径"页面样式太素，需要引入装饰"，按**分场景**落地：
   展示型页面（首页 / 门户位）加装饰，阅读型页面（列表 / 内容页）保持克制 —— 下面这三条是**两处共用**的
   骨架级装饰（它们解决的是"该看见的没看见"，不是"加花样"，所以阅读页也照用）：
     · 区块头的线：原来用 `--c-divider`(#eff3f9)，而门户页底是 #f6f8fb —— **它比底色还亮**，
       屏幕上等于没有这条线（实测过）。改成 `--c-text` 12% 透明，跟随主题、且真的看得见。
     · 标题前的**主色短条**：零 HTML 改动就能给每个区块头一个"视觉起点"（纯 `::before`）。
     · `.ph-sec--tint`：给区块一块**浅底**（展示型页面用来做"隔一块白"的分层节奏）。 */
.ph-sec { padding: var(--sp-6, 32px) 0 0; }
.ph-sec__head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-4, 16px);
    padding-bottom: var(--sp-3, 12px);
    border-bottom: 1px solid color-mix(in srgb, var(--c-text) 12%, transparent);
}
.ph-sec__head h2 {
    font-size: var(--fs-lg, 16px);
    font-weight: var(--fw-semibold, 600);
    line-height: 1.4;
}
/* 标题装饰条：4px × 1em 的主色圆角短条，与标题同一基线（`inline-block` + `vertical-align`
   让它不影响 `h2` 在 flex 容器里的既有布局）。 */
.ph-sec__head h2::before {
    content: '';
    display: inline-block;
    width: 4px;
    height: 1em;
    margin-right: var(--sp-2, 8px);
    border-radius: var(--radius-pill, 999px);
    background-color: var(--c-primary);
    vertical-align: -0.1em;
}
/* 区块浅底（可选）：通栏一块白，用来在展示型页面里做"隔一块白"的分层。
   ⚠ 自带上下的内边距 —— 否则白块的上下边缘会贴着内容（`.ph-sec` 原来只有上留白）。 */
.ph-sec--tint {
    background-color: var(--c-surface);
    padding-top: var(--sp-6, 32px);
    padding-bottom: var(--sp-6, 32px);
}
.ph-sec__more {
    margin-left: auto;
    font-size: var(--fs-xs, 12px);
    color: var(--c-text-tertiary);
}
.ph-sec__more:hover { color: var(--c-primary-text); }
.ph-sec__body { padding-top: var(--sp-4, 16px); }

/* 空态（区块开关打开但没数据时不留白洞） */
.ph-empty { padding: var(--sp-5, 24px) 0; font-size: var(--fs-sm, 14px); color: var(--c-text-tertiary); }

/* ── 空态（`ui-empty` 系列的**门户版尺寸**）──
   ⚠ 为什么放在**本文件**，而不是 `common/ui/components.css` 或 `portal/list.css`：
     · `components.css` 是**教师 / 学生端**的设计系统，**门户页根本不加载它**（实测 `/course.html`
       的样式清单里没有）⇒ 在那儿写门户的尺寸等于没写；
     · `list.css` 只有**列表页**加载 ⇒ 详情页 / 内容页的空态图标只好沿用 `.ui-ico` 默认的 **16px**
       （这就是"空态只有一个小方块"的来源）。本文件是门户**各页都会加载**的骨架
       （由件自带注册）⇒ 只有放这里才全局生效。
   ⚠ 两类插画各有一套笔画粗细，别混：
     · `.ui-empty__icon` 引的是 **24 网格**通用图标（`#i-empty` / `#i-search`）⇒ 放到 64px 要放大
       2.67 倍，笔画必须收细到 `1.2`，否则糊成粗线；
     · `.ui-empty__art` 引的是 **48 网格**插画（`#i-art-empty` / `#i-art-search`，2026-10-09 用户口径
       "给空态换插画"）⇒ 只放大 1.33 倍，用 `1.5` 才有约 2px 的视觉笔画（用 1.2 会发灰）。 */
.ph .ui-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2, 8px);
    padding: var(--sp-6, 32px) var(--sp-4, 16px);
    text-align: center;
    color: var(--c-text-tertiary);
}
.ph .ui-empty__icon,
.ph .ui-empty__art {
    width: 64px;
    height: 64px;
    margin-bottom: var(--sp-1, 4px);
    color: var(--c-border-strong);
    fill: none;
}
.ph .ui-empty__icon { stroke-width: 1.2; }
.ph .ui-empty__art { stroke-width: 1.5; }
.ph .ui-empty__title { font-size: var(--fs-base, 14px); color: var(--c-text-secondary); }
.ph .ui-empty__desc { font-size: var(--fs-sm, 14px); }
/* 紧凑变体：卡脚 / 表格内嵌等空间受限处 */
.ph .ui-empty--sm { gap: var(--sp-1, 4px); padding: var(--sp-4, 16px) var(--sp-3, 12px); }
.ph .ui-empty--sm .ui-empty__icon,
.ph .ui-empty--sm .ui-empty__art { width: 44px; height: 44px; margin-bottom: 0; stroke-width: 1.6; }
.ph .ui-empty--sm .ui-empty__title { font-size: var(--fs-sm, 14px); }

/* ── 封面图「占位底衬」：图片还没到 / 永远到不了时透出来，避免留一块空白 ──
   为什么是 CSS 背景而不是 JS 超时替换：按秒数判死会**误杀慢图**（外链封面首屏常 > 3.5s，
   被换掉 = "明明有图却贴了默认图"）；底衬是纯被动的——图片一到位就自然盖住，零误判，
   而 `background-size: cover` 保证占位图**完整铺满**整块封面（不会出现半张小图）。
   ⚠ 选择器必须是**直接子级**：封面框上压着徽标这类元素（里面可能带小图）。

   ⚠⚠ 这里是**门户封面框的完整清单**（2026-10-07 统一，此前课程卡缺这一条）——
   与本文件同层的"运行时兜底"还有两层（缺一不可，口径见 `Vars::coverFallbackAttrs()`）：
     ① 值层：取数时封面为空 ⇒ 直接回落占位图（`ListBlocks::offerings()` / `LabCenterServices::centerListItems()`）；
     ② 属性层：`data-fallback` + 内联 `onerror` ⇒ **404 / DNS / 拒绝连接**立刻换图；
     ③ 底衬（本段）：图片**卡住不返回**时 `onerror` 永不触发，靠这块被动背景铺底。
   ⇒ **新增任何封面框，必须往下面这个选择器清单里加一条**，否则它就少了第 ③ 层。 */
.ph-hot__cover > img,
.ph-course__cover > img,
.ph-art__cover > img,
.ph-lab__cover > img,
.ph-labhero__slide > img,
.ph-labhero__slide-link > img,
.ph-hero__slide > img,
.ph-hero__link > img {
    background: url(/static/images/course_cover.jpg) center / cover no-repeat;
}

@media (prefers-reduced-motion: reduce) {
    .ph *, .ph *::before, .ph *::after { transition: none !important; animation: none !important; }
}
