:root { --brand: #5b5ce2; --sider-top: #20224a; --sider-bottom: #15162e; --content-bg: #f5f6fb; --text-secondary: #6f7080; --border-soft: #ececf5; /* 中性面:与 theme.ts 的 palette 一一对应 */ --surface: #ffffff; --surface-2: #fafaff; --surface-hover: #f6f6fd; --tab-rail: #f2f3fa; --text-strong: #1f2033; --text-muted: #b9bacb; --header-bg: rgba(255, 255, 255, 0.88); --scrollbar: #c9cae6; --track: #f1f2f6; --track-raised: #ffffff; --brand-soft: rgba(91, 92, 226, 0.08); --success-soft: #f0fdf4; --success-soft-border: #bbf7d0; --danger-soft: #fef2f2; --danger-soft-border: #fecaca; --warning-soft: #fffbeb; /* 内容页布局尺度:顶栏高度、内容列左右留白、内容列最大宽度 */ --layout-header-h: 56px; --content-pad: 14px; /* 底部留白单独一个变量:.app-content 的下边距比四周略大一点, 阅读器高度等「满屏高度」计算时统一引用它,避免出现几像素的竖直滚动条。 */ --content-pad-end: calc(var(--content-pad) + 4px); --content-max: 1680px; } /* 深色模式:只换中性色,品牌色与语义色保持不变 */ :root[data-theme="dark"] { --content-bg: #12141f; --text-secondary: #9b9db4; --border-soft: #2a2c40; --surface: #1a1c2a; --surface-2: #1f2132; --surface-hover: #22243a; --tab-rail: #16182a; --text-strong: #e9eaf3; --text-muted: #5d5f78; --header-bg: rgba(26, 28, 42, 0.88); --scrollbar: #3a3c55; --track: #24263c; --track-raised: #3a3e5c; --brand-soft: rgba(91, 92, 226, 0.22); --success-soft: rgba(22, 163, 74, 0.14); --success-soft-border: rgba(22, 163, 74, 0.4); --danger-soft: rgba(220, 38, 38, 0.14); --danger-soft-border: rgba(220, 38, 38, 0.4); --warning-soft: rgba(212, 136, 6, 0.14); } body { margin: 0; background: var(--content-bg); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; -webkit-font-smoothing: antialiased; } #root { min-height: 100vh; } ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 8px; } ::-webkit-scrollbar-track { background: transparent; } /* ---------------- 侧边栏外壳 ---------------- */ .app-sider { transition: all 0.2s ease; } .sider { display: flex; flex-direction: column; height: 100%; background: linear-gradient(180deg, var(--sider-top) 0%, var(--sider-bottom) 100%); } .sider-brand { position: relative; display: flex; align-items: center; gap: 8px; height: 56px; padding: 0 10px 0 12px; flex-shrink: 0; overflow: hidden; white-space: nowrap; color: #fff; border-bottom: 1px solid rgba(255, 255, 255, 0.08); transition: padding 0.2s ease; } /* 收拢时只留 logo,并且要保证 logo 居中 */ .sider--collapsed .sider-brand { justify-content: center; padding: 0; } .sider-brand-mark { display: grid; place-items: center; width: 30px; height: 30px; flex-shrink: 0; border-radius: 9px; background: var(--brand); color: #fff; font-size: 17px; font-weight: 800; box-shadow: 0 4px 12px rgba(91, 92, 226, 0.45); transition: transform 0.18s ease, opacity 0.16s ease; } .sider-brand-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 14.5px; font-weight: 700; } /* 菜单头部的收拢按钮:与平台名同一行,靠右 */ .sider-brand-collapse { margin-inline-start: auto; flex-shrink: 0; width: 30px; height: 30px; padding: 0; color: rgba(255, 255, 255, 0.66); } /* 收拢态:logo 与展开按钮叠在同一位置,hover / 聚焦时原地换人 */ .sider-brand-logo { position: relative; display: grid; place-items: center; width: 30px; height: 30px; } .sider-brand-toggle { display: grid; place-items: center; width: 30px; height: 30px; padding: 0; flex-shrink: 0; } .sider-brand-logo .sider-brand-toggle { position: absolute; inset: 0; opacity: 0; visibility: hidden; } .sider-brand-logo:hover .sider-brand-mark, .sider-brand-logo:focus-within .sider-brand-mark { opacity: 0; visibility: hidden; } .sider-brand-logo:hover .sider-brand-toggle, .sider-brand-logo:focus-within .sider-brand-toggle { opacity: 1; visibility: visible; } .sider-brand .sider-brand-toggle:not(:disabled):hover { color: #fff; background: rgba(255, 255, 255, 0.14); } .sider-scroll { flex: 1; min-height: 0; overflow-x: hidden; overflow-y: auto; padding: 10px 0 12px; } .sider-scroll::-webkit-scrollbar { width: 6px; } .sider-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.16); border-radius: 6px; } .sider-menu.ant-menu-dark .ant-menu-item-group-title, .sider-scroll .ant-menu-dark .ant-menu-item-group-title { padding-inline: 22px; letter-spacing: 0.6px; } /* 收拢态下的分组分隔线与弹出子菜单 */ .sider-scroll .ant-menu-dark .ant-menu-item-divider { margin-inline: 16px; border-color: rgba(255, 255, 255, 0.12); } .sider-footer { flex-shrink: 0; padding: 10px; border-top: 1px solid rgba(255, 255, 255, 0.08); } .sider-user { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 10px; cursor: pointer; background: rgba(255, 255, 255, 0.07); transition: background 0.2s; } .sider-user:hover { background: rgba(255, 255, 255, 0.14); } .sider-user--collapsed { justify-content: center; padding: 6px 0; } .sider-user-name { color: #fff; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sider-user-role { color: rgba(255, 255, 255, 0.5); font-size: 11px; line-height: 1.4; } /* 移动端抽屉中的侧栏:去掉 antd 默认留白 */ .app-sider-drawer .ant-drawer-body { background: linear-gradient(180deg, var(--sider-top) 0%, var(--sider-bottom) 100%); } /* ---------------- 顶栏(移动端在此唤出菜单抽屉) ---------------- */ .app-header { display: flex; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 20; /* 与 .app-content-inner 同一条基线:内容列被 max-width 收窄时, 顶栏控件同步内收(推导:内容列左偏移 = pad + (100% - 2*pad - 上限)/2 = (100% - 上限)/2,未被夹住时就是 pad,故取两者较大值)。 */ padding-inline: max( var(--content-pad), calc((100% - var(--content-max)) / 2) ) !important; background: var(--header-bg); border-bottom: 1px solid var(--border-soft); backdrop-filter: saturate(180%) blur(8px); } /* 移动端的菜单入口:带描边的小方块,避免被当成正文里的返回按钮 */ .header-toggle { flex-shrink: 0; display: grid; place-items: center; width: 38px; height: 32px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--surface-2); color: var(--text-secondary); } .header-toggle:hover { color: var(--brand); border-color: rgba(91, 92, 226, 0.35); background: var(--surface-hover); } /* 状态切换时图标轻微横向位移,强化「推走 / 拉回」的方向感 */ .header-toggle-icon { display: inline-grid; place-items: center; animation: header-toggle-in 0.2s ease; } .header-toggle-glyph { display: block; } @keyframes header-toggle-in { from { transform: translateX(-3px); opacity: 0.35; } to { transform: none; opacity: 1; } } @media (prefers-reduced-motion: reduce) { .header-toggle-icon { animation: none; } } /* 平台名只在侧栏文字被收拢掉时出现,避免与侧栏品牌行重复 */ .app-header-brand { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 14px; font-weight: 700; color: var(--text-strong); } .header-divider { flex-shrink: 0; width: 1px; height: 22px; margin-inline: -3px; background: var(--border-soft); } /* 功能页面 header:与下方模块面板同款面板(同底色、同描边、同圆角), 标题 + 描述在左,该功能的主操作按钮在右 */ .page-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; min-height: 54px; margin-bottom: 16px; padding: 10px 20px; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 12px; } .page-header-heading { min-width: 0; flex: 1; } .page-header .page-header-title { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .page-header .page-header-desc { display: block; margin-top: 1px; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .page-header-dot { color: var(--text-muted); } /* 功能页头右侧的主操作:由 HeaderActions portal 进来,空的时候不占位 */ .page-header-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .page-header-actions:empty { display: none; } .header-actions { display: flex; align-items: center; gap: 12px; margin-inline-start: auto; flex-shrink: 0; } .header-control { display: flex; align-items: center; justify-content: center; gap: 6px; min-width: 38px; height: 38px; padding-inline: 8px; border-radius: 12px; font-size: 14px; font-weight: 600; color: var(--text-secondary); } /* 明暗模式:圆角方块 + 轨道底色,图标本身表示当前可执行的动作 */ .mode-toggle { width: 38px; font-size: 18px; color: var(--text-strong); background: var(--track); } .mode-toggle:hover { color: var(--brand); background: var(--surface-hover); } /* 语言切换:分段控件,选中项抬起成同圆角的小方块(与明暗按钮同高) */ .header-actions .lang-switch.ant-segmented { padding: 3px; border-radius: 12px; background: var(--track); } .header-actions .lang-switch .ant-segmented-item { border-radius: 9px; color: var(--text-secondary); transition: color 0.18s ease; } .header-actions .lang-switch .ant-segmented-item-label { min-width: 36px; height: 32px; padding-inline: 10px; font-size: 14px; font-weight: 600; line-height: 32px; } .header-actions .lang-switch .ant-segmented-item:hover:not(.ant-segmented-item-selected) { color: var(--text-strong); } .header-actions .lang-switch .ant-segmented-item-selected, .header-actions .lang-switch .ant-segmented-thumb { background: var(--track-raised); box-shadow: 0 1px 2px rgba(15, 17, 45, 0.14); } .header-actions .lang-switch .ant-segmented-item-selected { color: var(--text-strong); } /* 内容页边距:留白随视口变宽略微加大,但宽度优先给内容, 避免高分辨屏上「中间一条窄柱、两侧大片空白」。 */ @media (min-width: 900px) { :root { --content-pad: 20px; } } @media (min-width: 1600px) { :root { --content-pad: 24px; } } @media (min-width: 2200px) { :root { --content-pad: 28px; } } .app-content { padding: var(--content-pad); padding-block-end: var(--content-pad-end); } .app-content-inner { max-width: min(100%, var(--content-max)); margin: 0 auto; } /* 页面切换淡入 */ .view-fade { animation: view-fade 0.24s ease both; } @keyframes view-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } } /* ---------------- 登录页 ---------------- */ .login-bg { min-height: 100vh; display: grid; place-items: center; padding: 16px; background: linear-gradient(135deg, #5b5ce2 0%, #312e81 60%, #1e1b4b 100%); } /* 登录页右上角的语言 / 明暗切换:渐变背景上用浅色控件 */ .login-bg > .header-actions { position: fixed; inset-block-start: 18px; inset-inline-end: 20px; z-index: 2; } .login-bg .mode-toggle, .login-bg .lang-switch.ant-segmented { --track: rgba(255, 255, 255, 0.18); --track-raised: #ffffff; color: rgba(255, 255, 255, 0.9); } .login-bg .mode-toggle { color: #ffffff; } .login-bg .mode-toggle:hover { --track: rgba(255, 255, 255, 0.3); color: #ffffff; } .login-bg .lang-switch .ant-segmented-item { color: rgba(255, 255, 255, 0.72); } .login-bg .lang-switch .ant-segmented-item:hover:not(.ant-segmented-item-selected) { color: #ffffff; } .login-bg .lang-switch .ant-segmented-item-selected, .login-bg .lang-switch .ant-segmented-thumb { background: #ffffff; color: #312e81; } .login-card { width: 400px; max-width: 100%; border-radius: 16px; box-shadow: 0 24px 64px rgba(15, 16, 46, 0.35); } .login-brand-mark { display: inline-grid; width: 52px; height: 52px; border-radius: 15px; font-size: 27px; } /* ---------------- 通用页面块 ---------------- */ .page-stack { display: flex; flex-direction: column; gap: 16px; } .panel-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 16px; } .section-title { display: flex; align-items: center; gap: 6px; margin: 0 0 8px; font-size: 14px; font-weight: 600; color: var(--text-strong); } /* 指标卡:可选图标 + 数值 */ .metric-card .ant-statistic-title { margin-bottom: 6px; } .metric-icon { display: grid; place-items: center; width: 42px; height: 42px; flex-shrink: 0; border-radius: 12px; background: rgba(91, 92, 226, 0.1); color: var(--brand); font-size: 19px; } .metric-icon--success { background: rgba(22, 163, 74, 0.1); color: #16a34a; } .metric-icon--warning { background: rgba(212, 136, 6, 0.12); color: #d48806; } /* 掌握度概览:一条分布条看完四档,段宽按知识点数量占比;图例可点进知识地图 */ .mastery-distribution { flex: 1; min-width: 240px; } .mastery-band { display: flex; height: 10px; overflow: hidden; border-radius: 999px; background: var(--surface-2); } /* 轻量列表:抽屉章节 / 结果回看 / 推荐步骤统一节奏 */ .data-rows { display: flex; flex-direction: column; } .data-row { padding: 12px 2px; border-bottom: 1px solid var(--border-soft); } .data-row:last-child { border-bottom: none; padding-bottom: 2px; } .data-row--clickable { cursor: pointer; transition: background 0.2s; } .data-row--clickable:hover { background: var(--surface-2); } /* 加载态:整页 / 局部两种高度 */ .async-state { padding: 48px 0; text-align: center; } .async-state--compact { padding: 24px 0; } .async-skeleton { padding: 8px 2px 12px; } /* 表格里的纯文本次要信息 */ .cell-sub { font-size: 12px; color: var(--text-secondary); } /* 次要说明常是整句话,限制一行,否则整列会被撑得比屏幕还宽 */ .ant-table-cell .cell-sub { max-width: 360px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } /* 选项字母前缀,错题本 / 练习记录 / 答题共用 */ .option-letter { display: inline-block; width: 26px; color: var(--text-secondary); } /* 答题选项行 */ .option-row { height: auto !important; min-height: 44px; padding: 10px 16px !important; text-align: left !important; justify-content: flex-start !important; white-space: normal !important; } .option-row-letter { display: inline-block; width: 24px; color: inherit; opacity: 0.7; } /* 答题题干:练习流程统一排版 */ .question-stem { font-size: 17px; font-weight: 600; line-height: 1.7; margin: 20px 0 14px; } /* 回看选项行(错题本 / 练习记录 / 题库预览),与答题行同一套排版语义 */ .option-review { display: flex; align-items: flex-start; gap: 6px; padding: 8px 12px; border: 1px solid var(--border-soft); border-radius: 8px; background: var(--surface); line-height: 1.7; transition: background 0.2s, border-color 0.2s; } .option-review--correct { background: var(--success-soft); border-color: var(--success-soft-border); } .option-review--wrong { background: var(--danger-soft); border-color: var(--danger-soft-border); } .option-review-icon { margin-left: auto; flex-shrink: 0; font-size: 15px; line-height: 1.7; } /* 知识图谱管理:左侧结构树 + 右侧详情 */ .graph-main { flex: 1 1 620px; min-width: min(520px, 100%); } .graph-detail { width: 380px; max-width: 100%; position: sticky; top: 76px; } .tree-box { max-height: 620px; overflow: auto; padding: 12px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--surface); } /* ---------------- 教材 / 课程:竖向 Tab + 等高卡片 + 分页 ---------------- */ /* * Tab 与内容必须读起来是一块东西:外壳是一张卡,导航条是嵌在卡内的分段面板, * 选中项抬成与内容区同底色的白色小块 —— 看到高亮就知道右边显示的是它的内容。 */ .resource-tabs.ant-tabs-left, .resource-tabs.ant-tabs-top { overflow: hidden; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 16px; } .resource-tabs .ant-tabs-content { padding: 0; } /* 竖向:只有 2 个标签,不需要 antd 的滚动裁剪 */ .resource-tabs.ant-tabs-left > .ant-tabs-nav, .resource-tabs.ant-tabs-left .ant-tabs-nav-wrap { overflow: visible; } /* 导航条浮在卡片内侧:四边留白,不再和内容区抢那条分隔线 */ .resource-tabs.ant-tabs-left > .ant-tabs-nav { flex: 0 0 186px; width: 186px; align-self: stretch; position: static; margin: 10px 0 10px 10px; padding: 8px; border-radius: 12px; background: var(--tab-rail); } .resource-tabs.ant-tabs-left > .ant-tabs-body-holder { flex: 1; min-width: 0; padding: 18px 20px 20px 22px; } /* antd 给左侧形态的内容区留了 24px,改由 body-holder 统一控制 */ .resource-tabs.ant-tabs-left > .ant-tabs-body-holder > .ant-tabs-content { padding: 0; } /* 窄屏:同一条分段面板改卧在卡片顶部 */ .resource-tabs.ant-tabs-top > .ant-tabs-nav { margin: 10px 10px 0; padding: 6px; border-radius: 12px; background: var(--tab-rail); } .resource-tabs.ant-tabs-top > .ant-tabs-body-holder { padding: 16px 18px 18px; } .resource-tabs .ant-tabs-nav-list { width: 100%; } /* antd 自带的导航分隔线由卡片描边代替,留着会再多切一刀 */ .resource-tabs .ant-tabs-nav::before { display: none; } .resource-tabs .ant-tabs-tab { justify-content: flex-start; align-self: stretch; height: 40px; margin: 0 0 2px !important; padding: 0 12px !important; border-radius: 9px; /* 标签只有名称,禁止折行 */ white-space: nowrap; color: var(--text-secondary); transition: background 0.18s ease, box-shadow 0.18s ease, color 0.18s ease; } .resource-tabs .ant-tabs-tab:last-child { margin-bottom: 0 !important; } .resource-tabs .ant-tabs-tab:hover { color: var(--text-strong); background: var(--surface-hover); } .resource-tabs .ant-tabs-tab .ant-tabs-tab-btn { width: 100%; color: inherit; } /* 选中项:白底小块浮在面板上,底色与右侧内容一致 */ .resource-tabs .ant-tabs-tab-active, .resource-tabs .ant-tabs-tab-active:hover { background: var(--surface); box-shadow: 0 1px 3px rgba(15, 17, 45, 0.14); } .resource-tabs .ant-tabs-tab-active .ant-tabs-tab-btn, .resource-tabs .ant-tabs-tab-active .ant-tabs-tab-btn .anticon { color: var(--brand); font-weight: 600; } /* 顶部形态:两项均分宽度 */ .resource-tabs.ant-tabs-top .ant-tabs-tab { flex: 1 1 0; margin-inline-end: 0 !important; } .resource-tabs .ant-tabs-ink-bar { display: none; } .resource-tab-label { display: flex; align-items: center; gap: 8px; white-space: nowrap; } /* 内容区是实底卡片,内层卡片靠描边和淡投影保持层次 */ .resource-tabs .equal-card { box-shadow: 0 1px 3px rgba(15, 17, 45, 0.05); } /* 卡片等高:栅格列与卡片一起撑满,内容多少不再影响高度 */ .card-grid { --card-h: 352px; align-items: stretch; } .card-grid > .ant-col { display: flex; } .card-grid .equal-card { width: 100%; height: var(--card-h); display: flex; flex-direction: column; } .card-grid .equal-card .ant-card-body { flex: 1; min-height: 0; display: flex; flex-direction: column; } /* 断点与 Col 的 xl 对齐:单列时没有对齐压力,固定高度只会撑出一片空白 */ @media (max-width: 1199px) { .card-grid .equal-card { height: auto; min-height: 260px; } } /* 弹性留白:把页脚和操作区顶到卡片底部,不同内容量的卡片同一条基线 */ .card-fill { flex: 1; min-height: 0; } /* 页脚不参与拉伸,章节目录单行显示,剩下的并入 +N */ .card-foot { flex: none; } .card-tags { display: flex; gap: 6px; } .card-tags .ant-tag { max-width: 150px; margin-inline-end: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .card-pin { padding-top: 12px; } .card-clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; /* flex-basis 取的是未裁剪的整段文字高度,允许压缩时会把第二行切半,这里锁定两行高 */ flex: none; } .card-pager { margin-top: 16px; } /* 数学公式 */ .math-inline { font-size: 1em; } .math-block { overflow-x: auto; overflow-y: hidden; padding: 4px 2px; } .katex-display { margin: 0.25em 0; } /* ---------------- 电子书阅读器 ---------------- */ .ebook-reader { display: flex; flex-direction: column; /* 顶栏 + 内容区上下留白之外的全部空间,保证页面本身不产生竖直滚动 */ height: calc( 100vh - var(--layout-header-h) - var(--content-pad) - var(--content-pad-end) ); min-height: 480px; overflow: hidden; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 12px; } .ebook-bar { display: flex; align-items: center; gap: 12px; flex-shrink: 0; min-height: 52px; padding: 8px 16px; border-bottom: 1px solid var(--border-soft); } .ebook-bar-title { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; } .ebook-name { flex: 1; min-width: 0; font-weight: 600; } .ebook-bar-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; } .ebook-body { position: relative; display: flex; flex: 1; min-height: 0; } /* PDF:虚拟滚动容器,页面绝对定位在占位轨道上 */ .ebook-pdf { flex: 1; overflow: auto; padding: 24px 0; } .ebook-pdf-strip { position: relative; margin: 0 auto; } .ebook-pdf-page { position: absolute; background: #ffffff; border-radius: 2px; box-shadow: 0 1px 6px rgba(15, 17, 45, 0.12); } .ebook-pdf-canvas { display: block; width: 100%; height: 100%; } /* EPUB:epub.js 往这里塞 iframe,尺寸交给它自己算 */ .ebook-epub { flex: 1; min-width: 0; } .ebook-epub iframe { display: block; width: 100%; height: 100%; border: 0; } .ebook-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: color-mix(in srgb, var(--surface) 82%, transparent); } .ebook-overlay-inner { display: flex; flex-direction: column; align-items: center; gap: 12px; } .ebook-overlay-text { color: var(--text-secondary); font-size: 13px; } .ebook-foot { display: flex; align-items: center; gap: 12px; flex-shrink: 0; padding: 8px 16px; border-top: 1px solid var(--border-soft); } .ebook-caption { color: var(--text-secondary); font-size: 12px; white-space: nowrap; } .ebook-progress { flex: 1; margin: 0; } .ebook-keys-hint { opacity: 0.7; } .ebook-counter { min-width: 92px; text-align: center; font-size: 12px; color: var(--text-secondary); } .ebook-font-btn { font-weight: 600; } .ebook-toc-list { display: flex; flex-direction: column; } .ebook-toc-item { width: 100%; text-align: start; overflow: hidden; } @media (max-width: 768px) { :root { --content-pad-end: calc(var(--content-pad) + 2px); } .app-content { padding: var(--content-pad); padding-block-end: var(--content-pad-end); } .ebook-reader { min-height: 420px; } .ebook-counter { min-width: 0; } .ebook-keys-hint { display: none; } .app-header { gap: 8px; padding-inline: 12px !important; } /* 窄屏放不下按钮文字:主操作只留图标,文案保留给读屏与无障碍名称 */ .page-header { margin-bottom: 12px; padding: 10px 14px; } .page-header-actions .ant-btn > span:not(.anticon):not(.ant-btn-icon) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } .page-header-actions .ant-btn { min-width: 34px; padding-inline: 0; } } /* ---------------- 今日任务:自评卡片与结算区 ---------------- */ /* 掌握度自评三档:图标 + 标签 + 说明,选中态给品牌色描边与浅底 */ .daily-rates { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; } .daily-rate { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; text-align: start; background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 12px; cursor: pointer; transition: background 0.2s, border-color 0.2s; } .daily-rate:hover:not(:disabled) { background: var(--surface-hover); border-color: var(--brand); } .daily-rate:disabled { opacity: 0.65; cursor: default; } .daily-rate--active { background: var(--brand-soft); border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); } .daily-rate-icon { color: var(--brand); font-size: 18px; } .daily-rate-text { display: flex; flex: 1; flex-direction: column; gap: 2px; } .daily-rate-label { color: var(--text-strong); font-weight: 600; } .daily-rate-desc { color: var(--text-secondary); font-size: 12px; line-height: 1.5; } .daily-rate-check { color: var(--brand); font-size: 15px; } /* 完成态结算块:章节、自评、完成时刻、连续天数一次看完 */ .daily-done { display: flex; gap: 14px; padding: 14px 16px; background: var(--success-soft); border: 1px solid var(--success-soft-border); border-radius: 14px; } .daily-done-icon { color: #16a34a; font-size: 26px; } /* 结算区:主按钮独占一行,提示语跟在按钮下面 */ .daily-foot { display: flex; flex-direction: column; gap: 8px; } /* 确认框里的章节名可能很长:限宽换行,避免气泡顶出内容区 */ .daily-confirm-desc { max-width: 260px; } /* 重点按钮:今日任务的唯一主操作,尺寸要压过页面其余按钮 */ .daily-submit.ant-btn { min-height: 52px; border-radius: 12px; box-shadow: 0 10px 22px rgba(91, 92, 226, 0.26); font-size: 16px; font-weight: 600; } .daily-submit.ant-btn:disabled { box-shadow: none; } /* ---------------- 分屏工作台(题库 / 记录 / 错题 / 答题) ---------------- */ .split-view { display: flex; align-items: stretch; overflow: hidden; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 14px; box-shadow: 0 1px 2px rgba(31, 32, 51, 0.04); } .split-aside { flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--surface-2); } .split-view--left .split-aside { border-inline-end: 1px solid var(--border-soft); } .split-view--right .split-aside { border-inline-start: 1px solid var(--border-soft); } .split-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; overflow: hidden; } /* 窄屏:左右分屏退回上下堆叠,清单只占一小段高度 */ .split-view--stack { flex-direction: column; height: auto !important; } .split-view--stack .split-aside { border-inline-end: 0; border-inline-start: 0; border-bottom: 1px solid var(--border-soft); width: 100% !important; max-height: 40vh; } .split-view--stack .split-main { min-height: 60vh; } .split-resizer { flex: 0 0 7px; cursor: col-resize; position: relative; background: transparent; touch-action: none; } .split-resizer::after { content: ""; position: absolute; inset: 0 3px; border-radius: 3px; background: var(--border-soft); transition: background 0.16s ease; } .split-resizer:hover::after, .split-resizer--active::after { background: var(--brand); } body.split-dragging { cursor: col-resize; user-select: none; } /* 分屏里的一栏 */ .pane { display: flex; flex-direction: column; height: 100%; min-height: 0; } .pane-head { flex: 0 0 auto; padding: 12px 14px; border-bottom: 1px solid var(--border-soft); background: var(--surface); } .split-aside > .pane > .pane-head { background: var(--surface-2); } .pane-head-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; } .pane-title { font-size: 14px; font-weight: 600; color: var(--text-strong); min-width: 0; } .pane-extra { flex-shrink: 0; } .pane-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; } .pane-toolbar:empty { display: none; } /* 题库侧栏的三个筛选下拉尽量等分一行;栏太窄时整体换行, 而不是把「难度不限」压成「难度…」; 菜单宽度靠 popupMatchSelectWidth={false} 单独放开,长选项不会被裁。 */ .bank-filter-select { flex: 1 1 92px; min-width: 92px; } .pane-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 10px 12px 18px; } .pane--flat .pane-body { padding: 0; overflow: hidden; display: flex; } .pane-foot { flex: 0 0 auto; padding: 10px 14px; border-top: 1px solid var(--border-soft); background: var(--surface); } /* 清单条目 */ .master-item { display: block; width: 100%; text-align: start; padding: 10px 12px; margin-bottom: 6px; border: 1px solid transparent; border-radius: 10px; background: transparent; color: inherit; cursor: pointer; transition: background 0.16s ease, border-color 0.16s ease; } .master-item:hover { background: var(--surface-hover); } .master-item--active { background: var(--brand-soft); border-color: rgba(91, 92, 226, 0.35); } .master-item-title { display: flex; align-items: center; gap: 6px; font-weight: 600; color: var(--text-strong); line-height: 1.5; } .master-item-sub { margin-top: 3px; font-size: 12px; color: var(--text-secondary); line-height: 1.6; } .master-group { margin: 6px 0 4px; padding: 0 4px; font-size: 12px; font-weight: 600; color: var(--text-muted); } /* 得分环 / 计数的数字都用等宽数字,纵向对比才整齐 */ .tabular { font-variant-numeric: tabular-nums; } /* ---------------- 试卷排版 ---------------- */ .paper { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; min-width: 0; } .paper-head { flex: 0 0 auto; padding: 14px 20px 10px; border-bottom: 1px solid var(--border-soft); background: var(--surface); } .paper-head-main { min-width: 0; } .paper-title { font-size: 16px; font-weight: 650; color: var(--text-strong); line-height: 1.5; } .paper-meta { margin-top: 2px; font-size: 12.5px; color: var(--text-secondary); line-height: 1.7; } .paper-head-side { flex-shrink: 0; } .paper-score { display: flex; flex-direction: column; align-items: flex-end; padding: 0 12px; border-inline-start: 1px solid var(--border-soft); } .paper-score-value { font-size: 22px; font-weight: 700; line-height: 1.1; color: var(--brand); font-variant-numeric: tabular-nums; } .paper-score-total { font-size: 13px; font-weight: 500; color: var(--text-secondary); } .paper-score-label { font-size: 11.5px; color: var(--text-secondary); } .paper-head-tools { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-top: 12px; } .paper-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 18px 24px; } /* 一道题 */ .paper-question { display: flex; gap: 12px; padding: 14px 10px 16px; border-radius: 12px; transition: background 0.16s ease, box-shadow 0.16s ease; } .paper-question + .paper-question { border-top: 1px dashed var(--border-soft); border-radius: 12px 12px 0 0; } .paper-question--active { background: var(--surface-2); box-shadow: inset 3px 0 0 var(--brand); } .paper-question-rail { flex: 0 0 auto; padding-top: 1px; } .paper-question-no { display: inline-grid; place-items: center; min-width: 28px; height: 28px; padding: 0 6px; border-radius: 50%; background: var(--track); color: var(--text-strong); font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; } .paper-question--correct .paper-question-no { background: var(--success-soft); color: var(--success-soft-border); color: #16a34a; } .paper-question--wrong .paper-question-no { background: var(--danger-soft); color: #dc2626; } .paper-question-main { flex: 1 1 auto; min-width: 0; } .paper-question-head { min-height: 24px; margin-bottom: 2px; } .paper-question-actions { margin-inline-start: auto; } .paper-stem { font-size: 15.5px; font-weight: 600; line-height: 1.85; color: var(--text-strong); margin: 6px 0 12px; } .paper-options { max-width: 760px; } .paper-answer { margin-top: 12px; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border-soft); max-width: 760px; } .paper-explain-body { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border-soft); line-height: 1.85; color: var(--text-strong); } .paper-explain-toggle { border: 0; background: transparent; padding: 0; cursor: pointer; color: var(--brand); font-size: 13px; } /* 答题卡 */ .answer-sheet { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } .answer-sheet-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .answer-chip { position: relative; display: inline-flex; align-items: center; gap: 3px; min-width: 32px; height: 30px; padding: 0 8px; border: 1px solid var(--border-soft); border-radius: 9px; background: var(--surface); color: var(--text-strong); font-size: 13px; font-variant-numeric: tabular-nums; cursor: pointer; transition: border-color 0.16s ease, background 0.16s ease, transform 0.16s ease; } .answer-chip:hover { transform: translateY(-1px); border-color: var(--brand); } .answer-chip--active { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-soft); } .answer-chip-icon { font-size: 11px; } .answer-chip--correct { background: var(--success-soft); border-color: var(--success-soft-border); color: #16a34a; } .answer-chip--wrong { background: var(--danger-soft); border-color: var(--danger-soft-border); color: #dc2626; } .answer-chip--done { border-color: rgba(91, 92, 226, 0.45); color: var(--brand); } .answer-chip--pending { border-style: dashed; color: var(--text-muted); } .answer-sheet-legend { display: flex; align-items: center; gap: 10px; font-size: 12px; color: var(--text-secondary); } .answer-sheet-legend-toggle { border: 0; background: transparent; padding: 0; cursor: pointer; color: var(--text-secondary); font-size: 12px; text-decoration: underline dotted; } .answer-sheet-legend-items { display: flex; } .answer-sheet-legend-items span { display: inline-flex; align-items: center; gap: 4px; } .answer-dot { width: 9px; height: 9px; border-radius: 3px; display: inline-block; } .answer-dot--correct { background: var(--success-soft); border: 1px solid #16a34a; } .answer-dot--wrong { background: var(--danger-soft); border: 1px solid #dc2626; } .answer-dot--done { background: var(--brand-soft); border: 1px solid var(--brand); } .answer-dot--pending { background: transparent; border: 1px dashed var(--text-muted); } .answer-sheet-summary { margin-inline-start: auto; display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--text-secondary); } /* 答题中的提交条 */ .paper-submit { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; } /* 题库卡片里的章节导航 */ .chapter-nav-count { font-variant-numeric: tabular-nums; color: var(--text-secondary); font-size: 12px; } /* 试卷头部:标题与视图切换并排 */ .paper-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; } /* 题干下方的主体(选项 / 作答控件) */ .paper-body-slot { min-width: 0; } /* 可折叠解析 */ .paper-explain { margin-top: 12px; max-width: 760px; } .paper-explain-caret { margin-inline-start: 6px; font-size: 10px; color: var(--text-muted); } /* 我的作答 / 正确答案 对照 */ .answer-compare { align-items: center; row-gap: 4px; } .answer-chip-no { font-variant-numeric: tabular-nums; } /* 清单里的可点分组(教材名)与更紧凑的子项(章节) */ .master-group-button { display: flex; align-items: center; gap: 6px; width: 100%; padding: 5px 8px; border: 0; border-radius: 8px; background: transparent; color: var(--text-strong); font: inherit; text-align: start; cursor: pointer; transition: background 0.16s ease, color 0.16s ease; } .master-group-button:hover { background: var(--surface-hover); } .master-group-button--active { color: var(--brand); } .master-item--tight { padding: 7px 10px; margin-bottom: 2px; border-radius: 8px; } .master-item--tight .master-item-title { font-weight: 500; font-size: 13px; } /* 侧栏底部的小字提示 */ .aside-hint { margin-top: 14px; padding: 10px 4px 0; border-top: 1px dashed var(--border-soft); line-height: 1.7; } /* 生成任务进度条(挂在分屏上方,高度变化由 ResizeObserver 收敛) */ .bank-task { margin-bottom: 12px; padding: 12px 16px 4px; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 12px; } /* 成绩单摘要 */ .result-score { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; } .result-score-value { font-size: 30px; font-weight: 700; line-height: 1.1; color: var(--brand); font-variant-numeric: tabular-nums; } .result-score-total { font-size: 15px; font-weight: 500; color: var(--text-secondary); } .result-score-label { font-size: 12px; color: var(--text-secondary); } .result-knowledge { margin-top: 14px; padding-top: 4px; border-top: 1px dashed var(--border-soft); } .result-knowledge-row { gap: 8px; padding: 4px 0; font-size: 13px; } .result-knowledge-name { flex: 1 1 auto; min-width: 0; color: var(--text-strong); } /* 章节测试:组卷条件收成上方一条窄栏,高度留给答题工作台 */ .test-launcher { padding: 12px 14px; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 14px; box-shadow: 0 1px 2px rgba(31, 32, 51, 0.04); } .test-launcher-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .test-launcher-select { width: 260px; max-width: 100%; } .test-launcher-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border-soft); } .test-launcher-tags { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px; } .test-launcher-note { flex: 1 1 240px; min-width: 0; font-size: 12.5px; } @media (max-width: 1200px) { .paper-head { padding: 12px 14px 8px; } .paper-body { padding: 14px 12px 26px; } .paper-question { padding: 16px 6px 18px; } }