/* ==========================================================================
   前台门户 chrome（页头 / 导航 / 页尾 / 主题与语言入口）
   --------------------------------------------------------------------------
   落点：web/static/portal/chrome.css（门户专用，与 teacher 的 common/ui 同源 token）

   为什么单独一份：
   `views/common/school/{header,footer}.php` 被**教师端 / 学员端 / 用户中心 / 前台门户共用**
   （文件内注释明写），改它会同时改四个端 ⇒ 门户的 chrome 单独做一份，旧那份不动。

   颜色 / 圆角 / 阴影 / 间距一律引用 common/ui/tokens.css 的语义 token，不出现裸色值
   ⇒ 主题（blue / orange / green / youth）一换，页头页尾跟着变（全站通）。

   设计取向（品牌手册「克制、清楚、可信赖」+ 桌面高信息密度）：
   · 页头：品牌 ｜ 五个实验域导航 ｜ 工具区。当前域用**贴条下划线**（结构即信息），
     不做胶囊、不做色块、不加图标 —— 桌面靠文字扫读最快。
   · 滚动后加一条底阴影：告诉用户「已经滚动了」（有信息量的变化，不是装饰）。
   · 页尾：品牌落款 ｜ 站点 ｜ 友情链接 三栏 + 细线之上的版权行；白底 + 细线上边，不铺灰块。
   ========================================================================== */

/* ── 门户基础层（P5 旧共享 CSS 摘除后的全局兜底，2026-10-12）
   ------------------------------------------------------------------
   布局原先最先引 `common/css/{clear,common-style}.css` 垫全局底（reset / 字体 / body 底色 /
   a 基础色 / iconfont）。那四条引用已从 `views/layouts/school.php` 摘除 ⇒ 门户设计系统自己
   补一层**轻量**基础（只做全局兜底，不做激进 reset，避免冲击未件化页）：
   · 取值全走 token（--font-sans / --c-bg / --c-text / --fs-base），四套主题换肤自然生效；
   · `.iconfont` 与 `widgets/css/portal_base.css` 同值兜底（门户件走件注册、页尾等非件区
     不依赖件 ⇒ 这里保证任何门户页都有字形）；字体二进制仍在 `common/fonts/`（P5 收口迁移）。 */
*,
*::before,
*::after { box-sizing: border-box; }
html {
    font-family: var(--font-sans, "Microsoft YaHei", sans-serif);
    -webkit-text-size-adjust: 100%;
}
body {
    margin: 0;
    font-size: var(--fs-base, 14px);
    color: var(--c-text, #333);
    background-color: var(--c-bg, #f6f8fb);
}
a { color: inherit; text-decoration: none; }
a:hover { color: var(--c-primary-text, #f89b38); }
img { border-style: none; vertical-align: middle; }
h1, h2, h3, h4, h5, h6, p, ul, ol, dl, dd, figure, blockquote, form, fieldset, pre, hr { margin: 0; padding: 0; }
ul, ol { list-style: none; }
table { border-collapse: collapse; border-spacing: 0; }
input::placeholder, textarea::placeholder { color: #ccc; font-style: normal; }
/* 细滚动条（旧 clear.css 全局观感，门户横滑区依赖） */
body *::-webkit-scrollbar { width: 6px; height: 6px; background-color: #eee; }
body *::-webkit-scrollbar-thumb { background-color: #ccc; }
@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;
}

/* ── 共享图标（sprite + `.ui-ico`）
   ------------------------------------------------------------------
   布局在 `<body>` 起始处内联了 `views/common/icons.php` 的 sprite；它的隐藏规则在
   `common/ui/components.css` 里，而**门户壳不加载那个文件** ⇒ 不补这一段，
   那个 `<svg class="ui-ico-sprite">` 会以默认尺寸顶在页面最上方，页头因此多出一大片空白。
   取值与 components.css 一致（不用 display:none：个别 WebKit 会连带拒绝 `<use>` 引用）。 */
.ui-ico-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}
/* ⚠ 必须与 `common/ui/components.css` 的 `.ui-ico` **逐条同值**：sprite 里的符号都是
   **描边路径**（没有填充），漏掉 `fill:none; stroke:currentColor` 就会被浏览器按默认
   `fill:#000` 填成实心黑块 —— 语言下拉的选中勾、页头搜索等图标都会失真（2026-10-03 实测）。 */
.ui-ico {
    width: 16px;
    height: 16px;
    flex: none;
    vertical-align: -0.125em; /* 与相邻文字视觉居中，而不是压基线 */
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* 小尺寸档：笔画同步加粗到 2.2，否则 14px 下会糊（与 teacher 同值） */
.ui-ico--sm { width: 14px; height: 14px; stroke-width: 2.2; }

/* ── 页头 / 页尾 / 正文：同一条竖线 ──
   三者共用同一套容器参数（`--layout-container-max` 1200 + `--layout-gutter` 24），
   ⇒ 页头品牌、正文首块、页尾品牌左边缘对齐；页头工具、正文右缘、页尾右栏右边缘对齐。
   条（背景 / 描边）本身仍通栏铺底。 */

/* ── 页头 ── */
.portal-head {
    position: sticky;
    top: 0;
    z-index: var(--z-header, 100);
    background-color: var(--c-surface);
    border-bottom: 1px solid var(--c-border);
    /* ⚠ 旧门户 CSS 有一条**裸 header 元素选择器** `school-common.css:2 header,.header_app{min-width:1100px}`
       （同处第 206 行还给了 `header{background-color:#333}` —— 旧页头是黑底就是它）。
       我们的门户页头是 <header class="portal-head"> ⇒ 会继承那个 min-width，移动端收不下来
       （实测 375 设备上 .portal-head 被撑到 1100）。这里中和掉。 */
    min-width: 0;
    max-width: none;
    transition: box-shadow var(--dur-base, .24s) var(--ease-out, ease);
}
.portal-head.is-scrolled { box-shadow: var(--shadow-sm); }

.portal-head__bar {
    /* 页头**内容区与正文列同宽**（条本身仍通栏铺底 / 描边）：
       `max-width:1200 + 居中 + padding-inline:24` 与 `.ph__wrap` / `.exp-det__wrap` 完全同参
       ⇒ 品牌左边缘 == 正文首块的左边缘（1440 下都是 x=144、1024 下都是 x=24、375 下都是 x=24）。
       页尾不走这条（按用户要求保持通栏两端对齐），见 .portal-foot__in。 */
    width: 100%;
    max-width: var(--layout-container-max, 1200px);
    margin: 0 auto;
    padding-inline: var(--layout-gutter, 24px);
    min-height: var(--topbar-h, 56px);
    display: flex;
    align-items: stretch;
    gap: var(--sp-5, 24px);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .portal-head { background-color: transparent; }
    .portal-head::before {
        content: "";
        position: absolute;
        inset: 0;
        z-index: -1;
        background-color: color-mix(in srgb, var(--c-surface) 82%, transparent);
        -webkit-backdrop-filter: saturate(120%) blur(16px);
        backdrop-filter: saturate(120%) blur(16px);
    }
}

/* 品牌 */
.portal-head__brand { display: flex; align-items: center; flex: 0 0 auto; }
.portal-head__brand img { max-height: 30px; width: auto; }
.portal-head__word { font-size: var(--fs-lg, 16px); font-weight: var(--fw-semibold, 600); letter-spacing: .06em; }

/* 导航：当前域用贴条下划线（结构即信息），不换底色 */
.portal-nav { flex: 1 1 auto; min-width: 0; display: flex; align-items: stretch; }
.portal-nav__list { display: flex; align-items: stretch; list-style: none; margin: 0; padding: 0; }
.portal-nav__list li { display: flex; align-items: center; }
.portal-nav__list a {
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0 12px;
    font-size: var(--fs-base, 14px);
    color: var(--c-text-secondary);
    /* 窄屏时导航整行横向滚动 ⇒ 项内文字禁止换行，否则"实训课程"会被拆成两行 */
    white-space: nowrap;
    transition: color var(--dur-fast, .14s) var(--ease-out, ease),
                box-shadow var(--dur-base, .24s) var(--ease-out, ease);
}
.portal-nav__list a:hover { color: var(--c-text); }
.portal-nav__list li.is-on a { color: var(--c-primary-text); font-weight: var(--fw-medium, 500); }
/* 贴条：贴在 56px 条的下沿，比"文字变蓝"更容易定位当前域 */
.portal-nav__list li.is-on { box-shadow: inset 0 -2px 0 var(--c-primary); }

/* 工具区：静音图标 + 一个主行动（登录） */
.portal-head__tools { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2, 8px); flex: 0 0 auto; }
.portal-head__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px; height: 36px;
    border-radius: var(--radius-sm, 6px);
    color: var(--c-text-tertiary);
    transition: color var(--dur-fast, .14s) var(--ease-out, ease),
                background-color var(--dur-fast, .14s) var(--ease-out, ease);
}
.portal-head__icon:hover { color: var(--c-primary-text); background-color: var(--c-primary-softer); }
.portal-head__icon svg { width: 18px; height: 18px; }

/* ── 头部下拉件（语言入口 / 用户菜单**共用一套**）──
   ------------------------------------------------------------------
   两处都用 `<details class="ui-dropdown">`（与 teacher 端同一套结构与取值），
   而门户壳只加载 tokens.css（没有 common/ui 的 components.css / layout.css / ui.js）
   ⇒ 这里按 teacher 的 `components.css` **同值**落一份基础件，作用域限定在 `.portal-head`；
   **触发区外观各自设**（与 teacher 一样：语言 = 圆形字标位，用户 = 头像+昵称胶囊）。
   交互靠原生 `<details>`：不加载 ui.js 也能开合。 */
.portal-head .ui-dropdown { position: relative; }
.portal-head .ui-dropdown__trigger {
    display: flex;
    align-items: center;
    gap: var(--sp-2, 8px);
    cursor: pointer;
    list-style: none;                 /* 去掉 summary 默认三角（Firefox / Safari） */
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: color var(--dur-fast, .14s) var(--ease-out, ease),
                background-color var(--dur-fast, .14s) var(--ease-out, ease);
}
.portal-head .ui-dropdown__trigger::-webkit-details-marker { display: none; }
.portal-head .ui-dropdown__trigger::marker { content: ""; }
.portal-head .ui-dropdown__trigger:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--c-primary-soft, var(--c-primary-softer));
}
/* 箭头：mask 只取形状（形状变量在 tokens.css，门户有加载），颜色随触发区前景 */
.portal-head .ui-dropdown__caret {
    width: 12px;
    height: 12px;
    flex: none;
    background-color: currentColor;
    -webkit-mask: var(--icon-chevron-down) center / 12px 12px no-repeat;
    mask: var(--icon-chevron-down) center / 12px 12px no-repeat;
    transition: transform var(--dur-base, .24s) var(--ease-out, ease);
}
.portal-head .ui-dropdown[open] .ui-dropdown__caret { transform: rotate(180deg); }
.portal-head .ui-dropdown__menu {
    position: absolute;
    top: calc(100% + var(--sp-2, 8px));
    right: 0;
    z-index: var(--z-dropdown, 200);
    min-width: 132px;
    max-width: 280px;
    padding: var(--sp-1, 4px);
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md, 12px);
    background-color: var(--c-surface);
    box-shadow: var(--shadow-md);
}
.portal-head .ui-dropdown__item {
    display: flex;
    align-items: center;
    gap: var(--sp-2, 8px);
    width: 100%;
    padding: var(--sp-2, 8px) var(--sp-3, 12px);
    border: 0;
    border-radius: var(--radius-sm, 6px);
    font-size: var(--fs-sm, 14px);
    color: var(--c-text-secondary);
    line-height: 1.4;
    text-align: left;
}
.portal-head .ui-dropdown__item:hover,
.portal-head .ui-dropdown__item:focus-visible {
    color: var(--c-text);
    background-color: var(--c-surface-2);
    outline: none;
}
.portal-head .ui-dropdown__sep {
    height: 1px;
    margin: var(--sp-1, 4px) var(--sp-2, 8px);
    background-color: var(--c-divider);
}
.portal-head .ui-dropdown__item--danger { color: var(--c-danger, #d92d20); }
.portal-head .ui-dropdown__item--danger:hover,
.portal-head .ui-dropdown__item--danger:focus-visible { color: var(--c-danger, #d92d20); }

/* ── 语言入口：触发区 = 只有当前语言的字标（圆形图标位） ── */
.portal-head__lang {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}
.portal-head__lang .ui-dropdown__trigger {
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border-radius: var(--radius-pill, 999px);
    color: var(--c-text-secondary);
}
.portal-head__lang .ui-dropdown__trigger:hover,
.portal-head__lang[open] .ui-dropdown__trigger {
    color: var(--c-primary-text);
    background-color: var(--c-primary-softer);
}
/* 字标：20×20 圆角小方块 + 1–2 字语言记号（触发区与菜单项共用） */
.portal-head__lang .ui-lang__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 20px;
    height: 20px;
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius-sm, 6px);
    font-size: var(--fs-xs, 12px);
    font-weight: var(--fw-medium, 500);
    line-height: 1;
}
/* 菜单项里的语言名撑开剩余宽度，把「当前项」的勾选顶到最右；nowrap 防中文被挤成两行 */
.portal-head__lang .ui-lang__name { flex: 1; white-space: nowrap; }
/* 选中项的勾：与 teacher 的 `.ui-lang__check` 同值（尺寸/笔画由 `.ui-ico--sm` 给，不再另写死宽高） */
.portal-head__lang .ui-lang__check { margin-left: auto; color: var(--c-primary); }
.portal-head__lang .ui-lang__item.is-active { color: var(--c-primary-text); }

/* 消息（铃铛）：共享 sprite 线性图标（20px，与 teacher 的 `.ui-console__alert` 同值）。
   未读数角标**压在图标右上角**（不是排在图标右边）—— 取值照 teacher 的 `.ui-console__alert-badge`：
   绝对定位到右上、外圈一圈底色，免得与铃铛笔画糊在一起；未读数为 0 时视图里根本不输出这枚角标。 */
.portal-head__alert { display: flex; align-items: center; }
.portal-head__alert a {
    position: relative;              /* 角标的定位基准 = 图标本身 */
    display: inline-flex;
    align-items: center;
    color: var(--c-text-tertiary);
}
.portal-head__alert a:hover { color: var(--c-primary-text); }
.portal-head__alert .ui-ico { width: 20px; height: 20px; }
.portal-head__alert .head_alert_number {
    position: absolute;
    top: -4px;
    right: -6px;
    min-width: 14px;
    height: 14px;
    padding: 0 4px;
    border-radius: var(--radius-pill, 999px);
    background-color: var(--c-danger, #e0445a);
    color: #fff;
    font-size: 10px;
    line-height: 14px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--c-surface);   /* 描一圈底色，与图标分开 */
}

/* ── 用户菜单：与 teacher 的 `.ui-console__user` **同值**的胶囊触发区
   （头像 + 昵称 + 箭头；菜单项用上面的 `.ui-dropdown__item` 基础件）。
   替换掉旧页头那套 `.hover_exit`（悬停展开的裸列表，与 teacher 不是一个东西）。 ── */
.portal-head__user {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    font-size: var(--fs-sm, 14px);
}
.portal-head__user .ui-dropdown__trigger {
    height: 36px;
    padding: var(--sp-1, 4px) var(--sp-3, 12px) var(--sp-1, 4px) var(--sp-1, 4px);
    border-radius: var(--radius-pill, 999px);
    color: var(--c-text-secondary);
}
.portal-head__user .ui-dropdown__trigger:hover,
.portal-head__user[open] .ui-dropdown__trigger {
    color: var(--c-text);
    background-color: var(--c-surface-2);
}
.portal-head__user-name {
    max-width: 8em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* 头像：32px 圆 + 描边；没有头像时用首字兜底（与 teacher 的 `.ui-avatar` 一致） */
.portal-head__avatar {
    width: 32px;
    height: 32px;
    flex: none;
    border-radius: 50%;
    overflow: hidden;
    object-fit: cover;
    border: 1px solid var(--c-border);
    background-color: var(--c-surface-2);
}
.portal-head__avatar--text {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background-color: var(--c-primary-solid);
    color: var(--c-on-primary);
    font-weight: var(--fw-semibold, 600);
}
/* 用户菜单不另加宽：条目都是 4 字，跟着基础件的最小宽走（与 teacher 同值） */
.portal-head__user .ui-dropdown__menu { min-width: 132px; }

/* ── 换肤入口（.ui-theme-dock）
   样式原本在 common/ui/components.css 里；门户壳本批**暂不加载 components.css**
   （它的 base.css reset 会冲击尚未改造的门户页），故在此按同一套 token 复刻一份。
   等门户页全部接入 .ui-* 后，删掉这一段、改由 components.css 提供。 ── */
.portal-head .ui-theme-dock { position: relative; display: inline-flex; align-items: center; }
.portal-head .ui-theme-dock__trigger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: var(--radius-sm, 6px);
    color: var(--c-text-tertiary); background: none; border: 0;
    transition: color var(--dur-fast, .14s) var(--ease-out, ease), background-color var(--dur-fast, .14s) var(--ease-out, ease);
}
.portal-head .ui-theme-dock__trigger:hover,
.portal-head .ui-theme-dock__trigger[aria-expanded="true"] {
    color: var(--c-primary-text); background-color: var(--c-primary-softer);
}
.portal-head .ui-theme-dock__panel {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
    min-width: 168px; padding: var(--sp-1, 4px);
    background-color: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md, 12px);
    box-shadow: var(--shadow-md);
}
.portal-head .ui-theme-dock__panel[hidden] { display: none; }
.portal-head .ui-theme-dock__title { padding: 6px 10px; font-size: var(--fs-xs, 12px); color: var(--c-text-tertiary); }
.portal-head .ui-theme-dock__item {
    display: flex; align-items: center; gap: var(--sp-2, 8px); width: 100%;
    padding: 7px 10px; border: 0; background: none;
    font-size: var(--fs-sm, 14px); color: var(--c-text-secondary);
    border-radius: var(--radius-sm, 6px);
}
.portal-head .ui-theme-dock__item:hover { background-color: var(--c-surface-2); color: var(--c-text); }
.portal-head .ui-theme-dock__item.is-active { color: var(--c-primary-text); font-weight: var(--fw-medium, 500); }
.portal-head .ui-theme-dock__swatch {
    width: 16px; height: 16px; border-radius: var(--radius-sm, 6px);
    border: 1px solid var(--c-border-strong); flex: 0 0 auto;
}
.portal-head .ui-theme-dock__name { flex: 1; text-align: left; }
.portal-head .ui-theme-dock__check { color: var(--c-primary); opacity: 0; }
.portal-head .ui-theme-dock__item.is-active .ui-theme-dock__check { opacity: 1; }

/* ── 页尾 ── */
.portal-foot {
    margin-top: var(--sp-6, 32px);
    border-top: 1px solid var(--c-border);
    color: var(--c-text-secondary);
    font-size: var(--fs-xs, 12px);
    min-width: 0;
    max-width: none;
    /* ⚠ 两条都得听旧 CSS 的账（`school-common.css:228` 是**裸 footer 元素选择器**）：
       `footer{ height:160px!important; background:#333; background:-webkit-repeating-linear-gradient(-45deg,#2d2d2d 3px,#222 7px) }`
       ① 高度：不覆盖 height 会被 `!important` 压成 160px，新页尾的三栏内容直接被切；
       ② 背景：只写 background-color 压不住那条**深色斜纹 background-image**（实测页尾呈深灰带纹理）。
       故这里用 background 简写一次性清掉 image，并显式放开高度。 */
    height: auto !important;
    background: var(--c-surface);
}
.portal-foot__in {
    /* 左对齐的竖排三段（品牌 / 站点 / 友情链接）：内容都从同一条左边缘起，
       不再「品牌贴左、链接贴右」——那样中间会空出一大片（用户 2026-10-03 反馈"别扭"）。 */
    display: flex;
    flex-direction: column;
    gap: var(--sp-4, 16px);
    /* 与正文 / 页头同参（页尾不再通栏） */
    width: 100%;
    max-width: var(--layout-container-max, 1200px);
    margin: 0 auto;
    padding: var(--sp-6, 32px) var(--layout-gutter, 24px);
}
.portal-foot__brand .word {
    display: block;
    font-size: var(--fs-lg, 16px);
    font-weight: var(--fw-semibold, 600);
    letter-spacing: .06em;
    color: var(--c-text);
}
.portal-foot__brand .slogan { margin: var(--sp-2, 8px) 0 0; color: var(--c-text-tertiary); }

/* ── 「标签 + 链接」行（站点 / 友情链接共用同一套，节奏一致）──
   标签留在行首，链接顺文字流铺开并在行末自然换行。
   ⚠ 刻意用**文字流**（inline-block）而不是 flex + wrap：flex 下 `ul` 的基准宽度是
     max-content，链接一多就把标题挤到自己一行、首行大片留白（实测 24 条时标题独占一行）。 */
.portal-foot__row { display: block; }
.portal-foot__row h6 {
    display: inline-block;
    margin: 0 var(--sp-4, 16px) var(--sp-2, 8px) 0;
    font-size: var(--fs-xs, 12px);
    font-weight: var(--fw-medium, 500);
    color: var(--c-text-tertiary);
}
.portal-foot__row ul {
    display: inline;
    list-style: none;
    margin: 0;
    padding: 0;
}
.portal-foot__row li {
    display: inline-block;
    margin: 0 var(--sp-5, 24px) var(--sp-2, 8px) 0;
}
.portal-foot__row li:last-child { margin-right: 0; }
.portal-foot__row a { color: var(--c-text-secondary); }
.portal-foot__row a:hover { color: var(--c-primary-text); }
.portal-foot__row li.none { color: var(--c-text-tertiary); }

/* 友情链接行：与上面的品牌块用一条细线分区（站点行属于品牌块，不加线） */
.portal-foot__row--rule {
    margin-top: var(--sp-2, 8px);
    padding-top: var(--sp-4, 16px);
    border-top: 1px solid var(--c-divider);
}

.portal-foot__cp { border-top: 1px solid var(--c-divider); }
.portal-foot__cpin {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2, 8px) var(--sp-5, 24px);
    width: 100%;
    max-width: var(--layout-container-max, 1200px);
    margin: 0 auto;
    padding: var(--sp-4, 16px) var(--layout-gutter, 24px);
    color: var(--c-text-tertiary);
}
.portal-foot__cpin a { color: var(--c-text-tertiary); }
.portal-foot__cpin a:hover { color: var(--c-primary-text); }
/* 站点链接（使用帮助 / 常见问题 / 联系我们）与版权同处一行：跟在版权/技术支持后面，
   同字号同色，读作一条「底部信息带」（用户口径：不要单独占一行）。 */
.portal-foot__util {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--sp-2, 8px) var(--sp-4, 16px);
    margin-left: var(--sp-2, 8px);
}
.portal-foot__util a { color: var(--c-text-tertiary); }
.portal-foot__util a:hover { color: var(--c-primary-text); }

/* ── 响应式 ── */
@media (max-width: 1024px) {
    .portal-nav__list a { padding: 0 9px; }
}
@media (max-width: 900px) {
    /* 旧版窄屏直接把导航 display:none —— 等于没有导航。
       这里改成「品牌 + 工具 / 导航」两行，导航本身横向滚动。 */
    .portal-head__bar { flex-wrap: wrap; align-items: center; gap: var(--sp-3, 12px); padding-block: 6px; }
    .portal-nav { order: 3; flex: 0 0 100%; overflow-x: auto; scrollbar-width: none; }
    .portal-nav::-webkit-scrollbar { display: none; }
    .portal-nav__list li { height: 40px; }
    .portal-nav__list li.is-on { box-shadow: inset 0 -2px 0 var(--c-primary); }
}
@media (max-width: 640px) {
    .portal-head__tools { gap: var(--sp-1, 4px); }
    .portal-head__icon, .portal-head .ui-theme-dock__trigger,
    .portal-head__lang .ui-dropdown__trigger { width: 32px; height: 32px; }
    /* 窄屏：链接间距收一档（仍是同一条左边缘、行末换行，只是每行少放几条） */
    .portal-foot__row li { margin-right: var(--sp-4, 16px); }
}
@media (prefers-reduced-motion: reduce) {
    .portal-head, .portal-nav__list a { transition: none !important; }
}

/* ==========================================================================
   页面高度：内容不足一屏时也要**至少占满视口**，把页脚顶到最底
   —— 否则空列表 / 短内容页的页脚会浮在屏幕中间（实测 1440×900 的空栏目页：
      内容只到 630px，页脚下面空着 270px 的灰底，看图像"页面断了"）。
   只动**布局壳**：`body` 变 flex 列、`#container` 吃掉剩余高度 ⇒ 页脚自然贴底；
   `#container` 内部的块级 / 浮动布局一概不变（旧页那些 float·clearfix 结构不受影响）。
   需要"空态垂直居中"的页面，再由页面级样式往下接（见 `portal/list.css` 列表页那段）。
   ⚠ `dvh` 兜移动端地址栏收放；不支持的浏览器落到前一条 `vh`。
   ⚠ 本文档由 `views/layouts/school.php` 引入（门户专用），不影响 teacher / 学员端。 */
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}
#container {
    flex: 1 0 auto;
    /* ⚠ 这里必须是 flex 容器，页面内容（`.ph` / `.contain`）才能用 `flex: 1 0 auto`
       接着往下撑（列表页的空态居中就是靠这条链）；只给 `flex: 1 0 auto` 不设 `display: flex`
       的话，`#container` 自己会变高、但内容仍在顶部，空态看着还是"缩在上半截"。 */
    display: flex;
    flex-direction: column;
}
