Files
gaokao-volunteer-system/admin/static/portal-ui.css
Hermes Agent 3acda15527
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
fix(frontend): 视觉验收发现的问题逐条修复
P0 致命修复:
- 首页表单中段灰色不可见文字: hero-note(#e8edf7) 改为显式 #475569 可读色
- 首页上传区域空白虚线框: 补图标+说明+格式支持+CTA文案
- 结账页顶部裸 HTML class="wrap">: 缺少 <main 标签导致

P0 CTA层级:
- 首页双CTA: "直接做完整规划"从 btn-primary 改为 btn-secondary 形成层级

P1 信任感:
- 结账页补退款政策+支付方式+支付安全三栏
- 结账页删除 3 张冗余 trust-strip 卡片(原 6 张→2 张 form-proof)
- 结账页补"考试省份"必填星号

P1 定价页统一:
- CTA 文案统一: "选择付费审核"/"支付并启动方案生成"/"选择深度辅导"
- 价格单位统一: /次 /单 → 全部 /份

P1 导航对比度:
- global-nav-link 从 #b8c8e4 提亮到 #d8e4f8 (WCAG AA 4.5:1)

验证: pytest 1303 passed, ruff All checks passed
2026-06-27 23:16:26 +08:00

371 lines
7.3 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:root {
--portal-bg: #f3f7fb;
--portal-surface: #ffffff;
--portal-surface-soft: #f7fbff;
--portal-border: #d7e3f1;
--portal-text: #142235;
--portal-muted: #5b6b88;
--portal-primary: #1f6feb;
--portal-primary-dark: #194fb6;
--portal-primary-soft: rgba(31, 111, 235, 0.12);
--portal-success: #0f766e;
--portal-success-soft: #dff7f1;
--portal-warning: #8a5a00;
--portal-warning-soft: #fff7e6;
--portal-shadow: 0 18px 42px rgba(20, 34, 53, 0.08);
--portal-radius-xl: 24px;
--portal-radius-lg: 18px;
--portal-radius-md: 14px;
}
* {
box-sizing: border-box;
}
body {
color: var(--portal-text);
}
a {
color: var(--portal-primary);
}
a:hover {
color: var(--portal-primary-dark);
}
.portal-panel {
background: var(--portal-surface);
border: 1px solid var(--portal-border);
border-radius: var(--portal-radius-xl);
box-shadow: var(--portal-shadow);
}
.portal-eyebrow {
display: inline-flex;
padding: 6px 10px;
border-radius: 999px;
background: var(--portal-success-soft);
color: var(--portal-success);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.portal-muted {
color: var(--portal-muted);
}
.portal-button,
.portal-button-secondary {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 46px;
padding: 0 18px;
border-radius: var(--portal-radius-md);
text-decoration: none;
font-weight: 700;
border: none;
cursor: pointer;
}
.portal-button {
background: var(--portal-primary);
color: #fff;
}
.portal-button:hover {
background: var(--portal-primary-dark);
color: #fff;
}
.portal-button-secondary {
background: #edf3ff;
color: var(--portal-primary-dark);
}
.portal-button-secondary:hover {
background: #dfeaff;
color: var(--portal-primary-dark);
}
.portal-field input,
.portal-field textarea,
.portal-field select {
width: 100%;
padding: 12px;
border-radius: 12px;
border: 1px solid #cfd7e6;
font-size: 14px;
background: #fff;
color: var(--portal-text);
}
.portal-field input:focus,
.portal-field textarea:focus,
.portal-field select:focus {
outline: none;
border-color: var(--portal-primary);
box-shadow: 0 0 0 4px var(--portal-primary-soft);
}
.portal-helper {
color: var(--portal-muted);
font-size: 12px;
line-height: 1.6;
}
.portal-notice {
padding: 16px 18px;
border-radius: 16px;
background: var(--portal-warning-soft);
border: 1px solid #f4d39b;
color: var(--portal-warning);
line-height: 1.7;
}
.portal-status-grid {
display: grid;
gap: 12px;
}
.portal-status-item {
padding: 14px 16px;
border-radius: 16px;
background: var(--portal-surface-soft);
border: 1px solid var(--portal-border);
}
.global-nav {
position: sticky;
top: 0;
z-index: 100;
background: rgba(14,26,43,.92);
backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(255,255,255,.08);
padding: 12px 20px;
}
.global-nav-inner {
max-width: 1180px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
}
.global-nav-brand {
font-size: 18px;
font-weight: 700;
color: #fff;
text-decoration: none;
}
.global-nav-links {
display: flex;
gap: 20px;
align-items: center;
}
.global-nav-link {
color: #d8e4f8;
text-decoration: none;
font-size: 14px;
font-weight: 500;
}
.global-nav-link:hover {
color: #fff;
}
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
outline: 2px solid var(--portal-primary);
outline-offset: 2px;
}
@media (max-width: 768px) {
.global-nav {
padding: 10px 14px;
}
.global-nav-brand {
font-size: 16px;
}
.global-nav-links {
gap: 12px;
}
.global-nav-link {
font-size: 13px;
}
}
/* ============================================================
通用状态组件库2026-06-26 第一阶段 P1-2
覆盖loading / skeleton / empty / error / toast / spinner
所有用户端页面可直接 <div class="state-..."> 引用。
============================================================ */
/* —— Loading 容器 —— */
.state-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
padding: 36px 18px;
text-align: center;
color: #5b6b88;
background: #f8fbff;
border: 1px solid #d7e3f1;
border-radius: 16px;
}
.state-loading__spinner {
width: 28px;
height: 28px;
border: 3px solid #dbe7f5;
border-top-color: #1f6feb;
border-radius: 50%;
animation: state-spin 0.9s linear infinite;
}
.state-loading__text {
font-size: 14px;
line-height: 1.6;
margin: 0;
}
@keyframes state-spin {
to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.state-loading__spinner {
animation-duration: 2.5s;
}
}
/* —— Skeleton 占位(首屏数据未到时用)—— */
.state-skeleton {
display: block;
padding: 18px;
background: #f4f7fb;
border: 1px solid #e1e8f3;
border-radius: 14px;
}
.state-skeleton__line {
display: block;
height: 14px;
margin: 10px 0;
border-radius: 7px;
background: linear-gradient(90deg, #e6ecf5 0%, #f3f6fb 50%, #e6ecf5 100%);
background-size: 200% 100%;
animation: state-shimmer 1.4s ease-in-out infinite;
}
.state-skeleton__line--short { width: 38%; }
.state-skeleton__line--mid { width: 64%; }
.state-skeleton__line--long { width: 90%; }
@keyframes state-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
.state-skeleton__line {
animation: none;
background: #e6ecf5;
}
}
/* —— Empty 空状态 —— */
.state-empty {
padding: 28px 20px;
border-radius: 16px;
background: #f8fbff;
border: 1px solid #d7e3f1;
color: #5b6b88;
text-align: center;
}
.state-empty__title {
margin: 0 0 6px;
font-size: 16px;
font-weight: 700;
color: #2c3e5b;
}
.state-empty__hint {
margin: 0;
font-size: 13px;
line-height: 1.7;
}
/* —— Error 错误状态 —— */
.state-error {
padding: 20px 18px;
border-radius: 14px;
background: #fff5f5;
border: 1px solid #f5c2c7;
color: #b42318;
}
.state-error__title {
margin: 0 0 6px;
font-size: 15px;
font-weight: 700;
}
.state-error__hint {
margin: 0;
font-size: 13px;
line-height: 1.7;
color: #8a1f15;
}
.state-error a {
color: #b42318;
text-decoration: underline;
}
/* —— Toast全局aria-live=polite—— */
.state-toast-stack {
position: fixed;
left: 50%;
bottom: 24px;
transform: translateX(-50%);
display: flex;
flex-direction: column;
gap: 8px;
z-index: 9999;
pointer-events: none;
}
.state-toast {
pointer-events: auto;
min-width: 220px;
max-width: 90vw;
padding: 10px 14px;
border-radius: 10px;
background: rgba(20, 34, 53, .92);
color: #fff;
font-size: 13px;
line-height: 1.5;
box-shadow: 0 12px 30px rgba(20, 34, 53, .18);
opacity: 0;
transform: translateY(8px);
transition: opacity .2s ease, transform .2s ease;
}
.state-toast--visible {
opacity: 1;
transform: translateY(0);
}
.state-toast--success { background: #1f7a4d; }
.state-toast--error { background: #b42318; }
.state-toast--info { background: #1f6feb; }
/* —— 工具类sr-only可访问性配套—— */
.state-sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}