diff --git a/CHANGELOG.md b/CHANGELOG.md index 439ee836..f2650e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # 印度占星 Skill 更新日志 +## 2026-09-04 — 产品界面收束到三档字重、两档圆角和共用按钮 + +聊天正文改为 16px;产品界面字重只保留 400 / 500 / 600。控件圆角 8px、卡片 12px。会员购买、兑换和支付重试改走共用 `Button`。生时校正候选卡间距落到 4px 网格。登录与引导页仍用原来的按钮类名。Skill 版本未变。 + ## 2026-09-04 — 个人报告中心与阅读页接入产品阅读室视觉 报告页不再用第二套报纸纸色和无衬线加粗标题。中心与阅读页改走产品画布、发丝线、衬线标题(字重 400),terracotta 只留给生成和打印;星盘 SVG 跟主题走,深色模式可读。打印仍钉回浅色纸。Skill 版本未变。 diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index ab28ef5d..eb92d2f9 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -155,7 +155,7 @@ is read through an external store so a change in one tab reaches the others. | `--type-caption` | `13px` | 500 | 1.4 | 0 | Labels and metadata | | `--type-overline` | `12px` | 500 | 1.4 | `1.5px` | Eyebrows and badges | -Display headings use the serif stack at weight 400. Body copy never drops below 14px; 12–13px is reserved for short labels and metadata. CJK text uses `text-wrap: pretty`; display text uses `text-wrap: balance`. +Display headings use the serif stack at weight 400. Body copy never drops below 14px; 12–13px is reserved for short labels and metadata. No product UI text is smaller than `--type-overline` (12px). Product UI uses three font weights: 400 (display and body), 500 (UI titles, labels, buttons), and 600 (emphasis only). CJK text uses `text-wrap: pretty`; display text uses `text-wrap: balance`. One documented exception: the thinking text inside a timeline step (`.consultation-run-timeline__thinking`) and the fallback thinking trace (`.message-thinking-body`) render at 13px. They are working notes shown on request inside a collapsed row, not reading copy; the answer itself never inherits that size. @@ -163,6 +163,8 @@ One documented exception: the thinking text inside a timeline step (`.consultati The base unit is 4px. Tokens are `--space-1: 4px`, `--space-2: 8px`, `--space-3: 12px`, `--space-4: 16px`, `--space-5: 20px`, `--space-6: 24px`, `--space-8: 32px`, `--space-10: 40px`, `--space-12: 48px`, `--space-16: 64px`, and `--space-24: 96px`. +Radii have two visual steps. Controls use 8px (`--radius-md`; `--radius-xs` and `--radius-sm` alias that value). Cards and sheets use 12px (`--radius-lg`; `--radius-xl` aliases it). Circles stay `50%`; pills stay `999px`. + - Chat reading width: 760px for the welcome/composer and 900px for long answers. Both chat surfaces share the 900px transcript width; the rectification session no longer narrows it to 720px. - Admin content width: 1200px, centered. - Desktop shell: 288px sidebar plus flexible reading panel. @@ -181,6 +183,7 @@ The base unit is 4px. Tokens are `--space-1: 4px`, `--space-2: 8px`, `--space-3: ### Button +- **Implementation:** report surfaces and membership use `@/components/ui/button`. Login, onboarding, and birth-time dialogs still use `.button-primary` / `.button-secondary`, which share the same 44px height, 8px radius, and action tokens. Those CSS classes stay until those surfaces can move without growing `page.tsx`. - **Variants:** ink primary, cream secondary, text, circular icon, deep-brown emphasis. - **Spacing:** 44px minimum height; radii 8px for standard and full radius for icon-only. - **States:** default, hover, active, focus-visible, disabled, loading. @@ -308,7 +311,7 @@ The birth-time rectification session is the consultation transcript plus a house - **Variants:** assistant editorial text on canvas; user text on warm card surface; streaming; error. Streaming uses a timeline of completed steps plus the current step; the thinking body expands while streaming, collapses when answer text appears, and is stored with the assistant message. - **Identity:** every assistant message carries the 32px Jyotisha logo avatar; user messages stay visually lighter and avatar-free. -- **Typography:** assistant body 17px (16px below 768px) with serif subheadings; user body 14px. +- **Typography:** assistant body `--type-body-md` (16px) with serif subheadings; user body 14px. - **Tables:** three-column technique audit tables keep 状态 on one line. Below 768px they stack each row as title + status, then the note, instead of squeezing 已执行 into a vertical glyph column. - **Follow-up:** the latest settled consultation answer may offer two or three grounded next questions under that answer. Clicking one sends it in the current session. The composer never hosts suggestion chips. If the answer does not support a grounded continuation, nothing is shown. - **Motion:** a new row enters once, through the GSAP tween in `chat-message-row.tsx` at the 160ms Message duration; there is no CSS entrance keyframe beside it. The trailing assistant reply is one component (`LatestAssistantEntry`) from its first streamed token through settlement, so settling never remounts it and never replays the entrance. @@ -390,6 +393,11 @@ Text release is paced, not animated: the frame buffer commits at most once per a - **Width:** 420px desktop maximum. - **States:** open, submitting, success, and error. +### Membership + +- **Structure:** full-page archive on the page floor. Header chrome is back, orders, and redeem; the hero names the current plan; tabs switch membership vs credits; each plan/credit card carries one purchase action. +- **Actions:** header chrome stays hairline `--color-ink-secondary`. The one filled terracotta control is the recommended-plan purchase (`Button` default). Other plan and credit buys use `Button` outline. Redeem opens a dialog; it is not a second filled button on the same screen. + ### Logout dialog - **Structure:** confirmation title and explanation, cancel action, and destructive confirm action. diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 85e2f482..b9e6ed19 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -46,7 +46,7 @@ --color-dark-hover: var(--color-dark-hover); --color-dark-muted: var(--color-dark-muted); --color-dark-border: var(--color-dark-border); - --radius-sm: 6px; + --radius-sm: 8px; --radius-md: 8px; --radius-lg: 12px; } @@ -101,11 +101,11 @@ --type-body-sm: 14px; --type-caption: 13px; --type-overline: 12px; - --radius-xs: 4px; - --radius-sm: 6px; + --radius-xs: 8px; + --radius-sm: 8px; --radius-md: 8px; --radius-lg: 12px; - --radius-xl: 16px; + --radius-xl: 12px; --space-1: 4px; --space-2: 8px; --space-3: 12px; @@ -304,7 +304,7 @@ button:disabled { cursor: default; opacity: .45; } .app-loading-symbol { position: relative; width: 56px; height: 56px; display: grid; place-items: center; } .app-loading-mark { width: 30px; height: 30px; background: url("/jyotish-logo.png") center / contain no-repeat; } .app-loading-orbit::after { position: absolute; top: -3px; left: 50%; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: var(--color-action); box-shadow: 0 0 0 3px var(--color-canvas); content: ""; } -.app-loading-actions { display: flex; gap: 10px; margin-top: 12px; } +.app-loading-actions { display: flex; gap: var(--space-3); margin-top: var(--space-3); } .brand-mark, .welcome-mark, .auth-brand span { width: 28px; height: 28px; display: block; flex: 0 0 auto; background: url("/jyotish-logo.png") center / contain no-repeat; font-size: 0; } .session-nav { min-height: 0; flex: 0 0 auto; } .session-nav:last-of-type { min-height: 0; flex: 1 1 auto; display: flex; flex-direction: column; } @@ -314,7 +314,7 @@ button:disabled { cursor: default; opacity: .45; } .credit-button .credit-icon { width: 16px; height: 16px; flex: 0 0 auto; } .welcome-mark { margin-bottom: 20px; } .welcome h1, .auth-panel h1 { margin: 0; font-size: clamp(30px, 4vw, 42px); font-weight: 600; letter-spacing: -.035em; line-height: 1.1; } -.welcome-copy { max-width: 520px; margin: 13px 0 28px; color: var(--color-ink-secondary); font-size: 15px; line-height: 1.65; } +.welcome-copy { max-width: 520px; margin: var(--space-3) 0 28px; color: var(--color-ink-secondary); font-size: var(--type-body-md); line-height: 1.65; } .onboarding-card-reveal { min-width: 0; max-width: 100%; animation: onboarding-card-enter 180ms var(--ease-out) both; } .onboarding-card-reveal-inner { min-width: 0; max-width: 100%; min-height: 0; } .onboarding-card-heading { display: grid; gap: 4px; padding-bottom: 2px; } @@ -324,7 +324,7 @@ button:disabled { cursor: default; opacity: .45; } [data-sonner-toaster] [data-sonner-toast] { border: 1px solid var(--color-border) !important; border-radius: var(--radius-lg) !important; background: var(--color-canvas) !important; color: var(--color-ink) !important; box-shadow: var(--shadow-elevated) !important; } [data-sonner-toast] [data-title] { font-size: var(--type-body-sm); font-weight: 600; } [data-sonner-toast] [data-description] { color: var(--color-ink-secondary) !important; font-size: var(--type-caption); line-height: 1.5; } -.birth-time-transition-fields { min-width: 0; display: grid; gap: 14px; margin: 0; padding: 0; border: 0; } +.birth-time-transition-fields { min-width: 0; display: grid; gap: var(--space-4); margin: 0; padding: 0; border: 0; } .birth-time-assessment-overlay { position: absolute; z-index: 2; inset: 0; display: grid; place-items: center; padding: var(--space-6); border-radius: inherit; background: var(--color-canvas-soft); } .birth-time-assessment-progress { width: min(360px, 100%); display: grid; justify-items: center; gap: var(--space-2); color: var(--color-ink-secondary); text-align: center; } .birth-time-assessment-progress strong { margin-top: var(--space-2); color: var(--color-ink); font-family: var(--font-display); font-size: var(--type-title-md); font-weight: 400; } @@ -335,11 +335,11 @@ button:disabled { cursor: default; opacity: .45; } .message-user { justify-content: flex-end; } .message-user .message-content { display: flex; flex-direction: column; align-items: flex-end; } .message-assistant .message-content { width: auto; max-width: none; flex: 1; } -.message p { max-width: none; margin: 0; color: var(--color-ink); font-size: 17px; line-height: 1.65; white-space: pre-wrap; } -.message-markdown { color: var(--color-ink); font-size: 17px; line-height: 1.65; } +.message p { max-width: none; margin: 0; color: var(--color-ink); font-size: var(--type-body-md); line-height: 1.65; white-space: pre-wrap; } +.message-markdown { color: var(--color-ink); font-size: var(--type-body-md); line-height: 1.65; } .message-markdown > *:first-child { margin-top: 0; } .message-markdown > *:last-child { margin-bottom: 0; } -.claim-boundary-badge { width: fit-content; margin: 0 0 var(--space-2); padding: 4px 9px; border: 1px solid color-mix(in srgb, var(--color-action) 24%, transparent); border-radius: 999px; background: var(--color-action-soft); color: var(--color-action-hover); font-size: 12px; line-height: 1.45; } +.claim-boundary-badge { width: fit-content; margin: 0 0 var(--space-2); padding: var(--space-1) var(--space-2); border: 1px solid color-mix(in srgb, var(--color-action) 24%, transparent); border-radius: 999px; background: var(--color-action-soft); color: var(--color-action-hover); font-size: var(--type-overline); line-height: 1.45; } .evidence-audit-panel { margin: 0 0 var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: color-mix(in srgb, var(--color-canvas-soft) 68%, transparent); } .evidence-audit-panel summary { cursor: pointer; padding: var(--space-2) var(--space-3); color: var(--color-ink-secondary); font-size: 13px; } .evidence-audit-table { display: grid; gap: 1px; padding: 0 var(--space-3) var(--space-3); } @@ -348,7 +348,7 @@ button:disabled { cursor: default; opacity: .45; } .evidence-audit-row small { color: var(--color-ink-tertiary); line-height: 1.45; } .raw-evidence-receipt { margin: 0 var(--space-3) var(--space-3); border-top: 1px solid color-mix(in srgb, var(--color-border) 64%, transparent); padding-top: var(--space-2); } .raw-evidence-receipt summary { padding: var(--space-1) 0; color: var(--color-ink-tertiary); font-size: 12px; } -.raw-evidence-receipt pre { max-height: 180px; overflow: auto; margin: var(--space-2) 0 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink-secondary); font-size: 11px; line-height: 1.5; } +.raw-evidence-receipt pre { max-height: 180px; overflow: auto; margin: var(--space-2) 0 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink-secondary); font-size: var(--type-overline); line-height: 1.5; } .message-markdown p { margin: 0 0 14px; } .message-markdown ul, .message-markdown ol { margin: 8px 0 18px; padding-inline-start: 1.15em; } .message-markdown li { margin: 0; padding-block: 4px; padding-inline-start: 4px; } @@ -379,7 +379,7 @@ button:disabled { cursor: default; opacity: .45; } } .markdown-table th, .markdown-table td { - padding: 8px 10px 8px 0; + padding: 8px var(--space-3) 8px 0; border-bottom: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent); vertical-align: top; text-align: start; @@ -389,11 +389,11 @@ button:disabled { cursor: default; opacity: .45; } .markdown-table thead th { color: var(--color-ink-secondary); font-size: var(--type-overline); - font-weight: 650; + font-weight: 600; letter-spacing: .02em; } .markdown-table tbody th { - font-weight: 550; + font-weight: 500; } .markdown-table table:has(thead th:nth-child(3):last-child) td:nth-child(2) { width: 4.5em; @@ -495,19 +495,19 @@ button:disabled { cursor: default; opacity: .45; } .dialog-close svg { width: 19px; height: 19px; } .redeem-form { display: grid; gap: 8px; padding-top: 12px; } .redeem-form > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; } -.redeem-form label, .profile-form label > span, .code-form label > span, .stack-form label { color: var(--color-ink-secondary); font-size: 11px; font-weight: 600; } -.profile-form { display: grid; gap: 14px; margin-top: 16px; } -.profile-form label { display: grid; gap: 7px; } -.profile-form em, .code-form em { color: var(--color-ink-tertiary); font-size: 10px; font-style: normal; font-weight: 400; } +.redeem-form label, .profile-form label > span, .code-form label > span, .stack-form label { color: var(--color-ink-secondary); font-size: var(--type-overline); font-weight: 600; } +.profile-form { display: grid; gap: var(--space-4); margin-top: var(--space-4); } +.profile-form label { display: grid; gap: var(--space-2); } +.profile-form em, .code-form em { color: var(--color-ink-tertiary); font-size: var(--type-overline); font-style: normal; font-weight: 400; } .profile-grid, .location-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .location-fieldset { margin: 0; padding: 0; border: 0; } -.location-fieldset legend { margin-bottom: 10px; color: var(--color-ink-secondary); font-size: 11px; font-weight: 600; } +.location-fieldset legend { margin-bottom: var(--space-3); color: var(--color-ink-secondary); font-size: var(--type-overline); font-weight: 600; } .birth-place-picker { display: grid; gap: 8px; } -.birth-place-levels { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; } -.birth-place-levels > label { min-width: 0; display: grid; gap: 7px; } -.birth-place-levels > label > span { color: var(--color-ink-secondary); font-size: 11px; font-weight: 600; } -.birth-place-note { margin: 0; color: var(--color-ink-tertiary); font-size: 11px; line-height: 1.5; text-wrap: pretty; word-break: auto-phrase; } -.birth-place-status { min-height: 20px; display: flex; align-items: flex-start; gap: 6px; margin: 0; color: var(--color-ink-tertiary); font-size: 11px; line-height: 1.5; } +.birth-place-levels { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--space-3); } +.birth-place-levels > label { min-width: 0; display: grid; gap: var(--space-2); } +.birth-place-levels > label > span { color: var(--color-ink-secondary); font-size: var(--type-overline); font-weight: 600; } +.birth-place-note { margin: 0; color: var(--color-ink-tertiary); font-size: var(--type-overline); line-height: 1.5; text-wrap: pretty; word-break: auto-phrase; } +.birth-place-status { min-height: 20px; display: flex; align-items: flex-start; gap: var(--space-2); margin: 0; color: var(--color-ink-tertiary); font-size: var(--type-overline); line-height: 1.5; } .birth-place-status.is-ready { color: var(--color-success); } .birth-place-status.is-error { color: var(--color-danger); } .birth-place-status > svg, @@ -523,10 +523,10 @@ button:disabled { cursor: default; opacity: .45; } .auth-brand strong { font-weight: 600; } .auth-step { transition: opacity 180ms ease-out, transform 180ms var(--ease-out); } @starting-style { .auth-step { opacity: 0; transform: translateY(6px); } } -.inline-actions { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px; } -.section-title { display: flex; align-items: center; justify-content: space-between; gap: 18px; } -.code-form { display: grid; grid-template-columns: 120px 120px 200px minmax(180px, 1fr) auto; align-items: end; gap: 12px; margin-top: 18px; } -.code-form label { display: grid; gap: 7px; } +.inline-actions { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-3); } +.section-title { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); } +.code-form { display: grid; grid-template-columns: 120px 120px 200px minmax(180px, 1fr) auto; align-items: end; gap: var(--space-3); margin-top: var(--space-5); } +.code-form label { display: grid; gap: var(--space-2); } .generated-list { display: grid; gap: 8px; margin-top: 16px; } .generated-list code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .status-已过期, .status-已兑换 { color: var(--color-ink-secondary); } @@ -566,7 +566,6 @@ button:disabled { cursor: default; opacity: .45; } .starter-list > button { min-height: 64px; } .starter-content span { font-size: 13px; } .message-assistant .message-content { max-width: 100%; } - .message p, .message-markdown { font-size: 16px; } .message-user p { font-size: 14px; } .composer { min-height: 56px; } .composer-footer > p { display: none; } @@ -781,7 +780,7 @@ button:disabled { cursor: default; opacity: .45; } .session-actions .session-action-danger, .session-actions .session-action-danger > svg { color: var(--color-danger); } .session-actions .session-action-danger[data-highlighted] { background: var(--color-danger-muted); } .sidebar-footer { position: relative; margin-top: 0; padding-top: 10px; border-top: 1px solid var(--sidebar-border); } -.profile-trigger { width: 100%; display: grid; grid-template-columns: 34px minmax(0, 1fr) 18px; align-items: center; gap: 9px; padding: 5px 7px; border: 0; background: transparent; color: var(--sidebar-foreground); cursor: pointer; text-align: left; transition: background-color 120ms ease-out, transform 120ms ease-out; min-height: 56px; border-radius: var(--radius-md); } +.profile-trigger { width: 100%; display: grid; grid-template-columns: 34px minmax(0, 1fr) 18px; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2); border: 0; background: transparent; color: var(--sidebar-foreground); cursor: pointer; text-align: left; transition: background-color 120ms ease-out, transform 120ms ease-out; min-height: 56px; border-radius: var(--radius-md); } .user-avatar { display: inline-grid; flex: 0 0 auto; overflow: hidden; place-items: center; border-radius: 50%; background: var(--color-action-soft); } .user-avatar > svg { width: 100%; height: 100%; display: block; } .profile-avatar { width: 32px; height: 32px; } @@ -820,7 +819,7 @@ button:disabled { cursor: default; opacity: .45; } .chat-header-subtitle { max-width: min(560px, 62vw); overflow: hidden; color: var(--color-muted-foreground); font-size: var(--type-caption); line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; } .chat-header-actions { min-width: max-content; display: flex; flex: 0 0 auto; align-items: center; gap: var(--space-2); white-space: nowrap; } .chat-header-actions > * { flex: 0 0 auto; } -.credit-button { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 0 11px; cursor: pointer; font-size: 13px; font-variant-numeric: tabular-nums; transition: background-color 120ms ease-out, transform 120ms ease-out; min-width: 64px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas-soft); color: var(--color-ink-secondary); font-weight: 500; } +.credit-button { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: 0 var(--space-3); cursor: pointer; font-size: var(--type-caption); font-variant-numeric: tabular-nums; transition: background-color 120ms ease-out, transform 120ms ease-out; min-width: 64px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas-soft); color: var(--color-ink-secondary); font-weight: 500; } .conversation { min-width: 0; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding-bottom: var(--composer-reserve); background: var(--color-canvas); } .conversation.is-empty { display: grid; place-items: center; padding: var(--space-8); } @@ -835,7 +834,7 @@ button:disabled { cursor: default; opacity: .45; } line-height: 1.28; text-wrap: balance; } -.onboarding-message { padding: 0 0 10px; padding-bottom: var(--space-3); } +.onboarding-message { padding: 0 0 var(--space-3); } .onboarding-message .message-markdown p { word-break: auto-phrase; text-wrap: pretty; } .onboarding-message.is-phrase-safe .message-markdown p { overflow-wrap: break-word; } .onboarding-stream .message-markdown p:last-child::after { width: 2px; height: 1em; display: inline-block; margin-left: 3px; background: var(--color-action); vertical-align: -.12em; animation: onboarding-caret 700ms steps(1, end) infinite; content: ""; } @@ -1022,7 +1021,7 @@ button:disabled { cursor: default; opacity: .45; } .product-entrypoint-action { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: flex-end; gap: var(--space-1); color: var(--color-action); font-size: var(--type-caption); font-weight: 600; white-space: nowrap; } .product-entrypoint-action .starter-arrow { width: 15px; height: 15px; color: currentColor; } .rectification-entry-error { grid-column: 1 / -1; margin: 0; } -.starter-note { margin: 10px 0 0; color: var(--color-ink-secondary); line-height: 1.5; grid-column: 1 / -1; font-size: 13px; } +.starter-note { margin: var(--space-3) 0 0; color: var(--color-ink-secondary); line-height: 1.5; grid-column: 1 / -1; font-size: var(--type-caption); } .message-list { --assistant-content-inset: calc(32px + var(--space-3)); margin: 0 auto; @@ -1171,7 +1170,7 @@ button:disabled { cursor: default; opacity: .45; } .consultation-run-timeline__sources { display: flex; flex-wrap: wrap; - gap: 6px; + gap: var(--space-2); } .consultation-run-timeline__source { border-radius: 999px; @@ -1234,13 +1233,13 @@ button:disabled { cursor: default; opacity: .45; } .conversation-follow-up { max-width: 100%; min-height: 44px; - padding: 0 14px; + padding: 0 var(--space-4); border: 1px solid var(--color-border); border-radius: 999px; background: var(--color-canvas); color: var(--color-ink); cursor: pointer; - font-size: 13px; + font-size: var(--type-caption); line-height: 1.4; text-align: left; } @@ -1331,7 +1330,7 @@ button:disabled { cursor: default; opacity: .45; } .rectification-analysis-content section { display: grid; gap: var(--space-2); } .rectification-analysis-content h4 { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-caption); font-weight: 600; } .rectification-analysis-content ol, -.rectification-analysis-content ul { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; } +.rectification-analysis-content ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; } .rectification-analysis-content li { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); } .rectification-analysis-content li span { min-width: 0; color: var(--color-ink-secondary); } .rectification-analysis-content li small { flex: 0 0 auto; color: var(--color-ink-muted); } @@ -1351,7 +1350,7 @@ button:disabled { cursor: default; opacity: .45; } and the chip styling is reset. */ .markdown-code { margin: 0 0 14px; overflow: hidden; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas-muted); } .markdown-code-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 36px; padding: 0 var(--space-2) 0 var(--space-4); border-bottom: 1px solid var(--color-border); } -.markdown-code-language { color: var(--color-ink-tertiary); font-family: var(--font-mono); font-size: 11px; letter-spacing: .04em; } +.markdown-code-language { color: var(--color-ink-tertiary); font-family: var(--font-mono); font-size: var(--type-overline); letter-spacing: .04em; } .markdown-code-copy { display: inline-flex; align-items: center; gap: var(--space-1); min-height: 28px; padding: 0 var(--space-2); border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--color-ink-secondary); cursor: pointer; font-size: var(--type-caption); transition: background-color 120ms ease-out, color 120ms ease-out; } .markdown-code-copy svg { width: 13px; height: 13px; } .markdown-code pre { margin: 0; padding: 0; overflow: hidden; background: none; } @@ -1414,7 +1413,7 @@ button:disabled { cursor: default; opacity: .45; } } .technique-audit-panel th, .technique-audit-panel td { - padding: 7px 10px 7px 0; + padding: var(--space-2) var(--space-3) var(--space-2) 0; border-bottom: 1px solid color-mix(in srgb, var(--color-border) 64%, transparent); vertical-align: top; text-align: start; @@ -1423,14 +1422,14 @@ button:disabled { cursor: default; opacity: .45; } } .technique-audit-panel thead th { color: var(--color-ink-tertiary); - font-size: 11px; - font-weight: 650; + font-size: var(--type-overline); + font-weight: 600; letter-spacing: .04em; } .technique-audit-panel tbody th { width: 28%; color: var(--color-ink); - font-weight: 550; + font-weight: 500; } .technique-audit-panel td[data-status] { width: 4.5em; @@ -1475,7 +1474,7 @@ button:disabled { cursor: default; opacity: .45; } grid-column: 1; grid-row: 1; color: var(--color-ink); - font-weight: 550; + font-weight: 500; } .markdown-table table:has(thead th:nth-child(3):last-child) tbody td:nth-child(2), @@ -1501,7 +1500,7 @@ button:disabled { cursor: default; opacity: .45; } border-bottom: 0; } } -.error-message { margin: 12px 0 0; padding: 12px 14px; border-left: 3px solid var(--color-danger); background: var(--color-danger-muted); color: var(--color-danger); font-size: 13px; line-height: 1.6; border-color: var(--color-danger); border-radius: 0 var(--radius-md) var(--radius-md) 0; } +.error-message { margin: var(--space-3) 0 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--color-danger); background: var(--color-danger-muted); color: var(--color-danger); font-size: var(--type-caption); line-height: 1.6; border-color: var(--color-danger); border-radius: 0 var(--radius-md) var(--radius-md) 0; } .composer-wrap { position: sticky; bottom: 0; z-index: 2; min-width: 0; border-top: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent); padding: var(--space-3) var(--space-6) var(--space-4); background: var(--color-frosted); backdrop-filter: saturate(130%) blur(20px); } /* Jump to latest: shared by both chat surfaces. Hangs off the composer wrap's top @@ -1522,7 +1521,7 @@ button:disabled { cursor: default; opacity: .45; } min-width: 44px; display: inline-flex; align-items: center; - gap: 6px; + gap: var(--space-2); padding: 0 var(--space-4); border: 1px solid var(--color-border); border-radius: 999px; @@ -1540,9 +1539,9 @@ button:disabled { cursor: default; opacity: .45; } outline: 3px solid color-mix(in srgb, var(--color-focus) 56%, transparent); outline-offset: 3px; } -.composer { width: min(760px, 100%); display: flex; align-items: flex-end; gap: 10px; margin: 0 auto; border: 1px solid var(--color-border); transition: border-color 140ms ease-out; min-height: 60px; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); border-color: var(--color-border-strong); border-radius: var(--radius-lg); background: var(--color-canvas); box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-border) 42%, transparent); } +.composer { width: min(760px, 100%); display: flex; align-items: flex-end; gap: var(--space-3); margin: 0 auto; border: 1px solid var(--color-border-strong); transition: border-color 140ms ease-out; min-height: 60px; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); border-radius: var(--radius-lg); background: var(--color-canvas); } .composer:focus-within { border-color: var(--color-action); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-action) 15%, transparent); } -.composer textarea { min-width: 0; min-height: 44px; max-height: 128px; flex: 1; resize: none; padding: 11px 0 8px; border: 0; outline: 0; background: transparent; color: var(--color-ink); line-height: 1.5; font-size: 16px; } +.composer textarea { min-width: 0; min-height: 44px; max-height: 128px; flex: 1; resize: none; padding: var(--space-3) 0 var(--space-2); border: 0; outline: 0; background: transparent; color: var(--color-ink); line-height: 1.5; font-size: var(--type-body-md); } .composer button { width: 44px; height: 44px; display: grid; flex: 0 0 auto; place-items: center; border: 0; color: var(--color-on-dark); cursor: pointer; transition: background-color 120ms ease-out, transform 120ms ease-out; border-radius: 999px; background: var(--color-action); } .composer .composer-stop { background: var(--color-action); } .composer .composer-stop:not(:disabled):hover { background: var(--color-action-hover); } @@ -1695,17 +1694,17 @@ button:disabled { cursor: default; opacity: .45; } .chart-library-group { display: grid; gap: var(--space-3); } .chart-library-group-heading { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); } .chart-library-group-heading b, .chart-library-group-heading small { display: block; } -.chart-library-group-heading b { color: var(--color-ink); font-size: var(--type-caption); font-weight: 650; } +.chart-library-group-heading b { color: var(--color-ink); font-size: var(--type-caption); font-weight: 600; } .chart-library-group-heading small { margin-top: 3px; color: var(--color-ink-secondary); font-size: var(--type-caption); font-weight: 400; } -.chart-library-count { display: grid; min-width: 24px; height: 24px; place-items: center; border-radius: 999px; background: var(--color-canvas-muted); color: var(--color-ink-secondary); font-size: 11px; } +.chart-library-count { display: grid; min-width: 24px; height: 24px; place-items: center; border-radius: 999px; background: var(--color-canvas-muted); color: var(--color-ink-secondary); font-size: var(--type-overline); } .chart-library-item { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas); } .chart-library-item-main { min-width: 0; } .chart-library-item strong, .chart-library-item small { display: block; } .chart-library-item strong { color: var(--color-ink); font-size: var(--type-body-md); font-weight: 500; } .chart-library-item small, .chart-library-item > span, .empty-library-copy { color: var(--color-ink-secondary); font-size: var(--type-caption); } .chart-library-item small + small { margin-top: 3px; } -.chart-library-item-title { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 5px; } -.chart-role-badge, .chart-default-badge { display: inline-flex; align-items: center; min-height: 20px; padding: 0 7px; border-radius: 999px; background: var(--color-canvas-muted); color: var(--color-ink-secondary); font-size: 10px; font-weight: 650; } +.chart-library-item-title { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-1); } +.chart-role-badge, .chart-default-badge { display: inline-flex; align-items: center; min-height: 20px; padding: 0 var(--space-2); border-radius: 999px; background: var(--color-canvas-muted); color: var(--color-ink-secondary); font-size: var(--type-overline); font-weight: 600; } .chart-role-badge.is-self, .chart-default-badge { background: var(--color-action-soft); color: var(--color-action-hover); } .chart-library-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); } .chart-library-actions > * { max-width: 100%; } @@ -1720,12 +1719,12 @@ button:disabled { cursor: default; opacity: .45; } .synastry-history-item { display: grid; gap: 3px; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); text-align: left; } .synastry-history-item small { color: var(--color-ink-secondary); font-size: var(--type-caption); } -input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input), select:not([class^="ant-"]):not([class*=" ant-"]) { width: 100%; min-height: 44px; padding: 0 12px; border: 1px solid var(--color-border-strong); color: var(--color-ink); border-color: var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-canvas); font-size: 14px; } +input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input), select:not([class^="ant-"]):not([class*=" ant-"]) { width: 100%; min-height: 44px; padding: 0 var(--space-3); border: 1px solid var(--color-border-strong); color: var(--color-ink); border-color: var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-canvas); font-size: var(--type-body-sm); } input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class*=" ant-"]):not(.ant-picker input):disabled, select:not([class^="ant-"]):not([class*=" ant-"]):disabled { color: var(--color-ink-tertiary); background: var(--color-canvas-muted); } -.button-primary, .button-secondary { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; padding: 0 15px; border: 1px solid var(--color-action); cursor: pointer; text-decoration: none; transition: background-color 120ms ease-out, color 120ms ease-out, transform 120ms ease-out; border-radius: var(--radius-md); font-size: 14px; font-weight: 500; } +.button-primary, .button-secondary { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; padding: 0 var(--space-4); border: 1px solid var(--color-action); cursor: pointer; text-decoration: none; transition: background-color 120ms ease-out, color 120ms ease-out, transform 120ms ease-out; border-radius: var(--radius-md); font-size: var(--type-body-sm); font-weight: 500; } .button-primary { border-color: var(--color-action); background: var(--color-action); color: var(--color-on-dark); } .button-secondary { border-color: var(--color-border-strong); background: var(--color-canvas); color: var(--color-ink); } -.form-error, .form-success { margin: 10px 0 0; padding: 10px 12px; border-left: 3px solid currentColor; line-height: 1.5; border-radius: 0 var(--radius-md) var(--radius-md) 0; font-size: 13px; } +.form-error, .form-success { margin: var(--space-3) 0 0; padding: var(--space-3); border-left: 3px solid currentColor; line-height: 1.5; border-radius: 0 var(--radius-md) var(--radius-md) 0; font-size: var(--type-caption); } .danger-primary { border-color: var(--color-danger); background: var(--color-danger); } .auth-page { display: grid; place-items: center; padding: var(--space-8); background: var(--color-canvas-soft); } @@ -1737,10 +1736,10 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .auth-story > div > p { max-width: 480px; margin: 0; color: var(--color-ink-secondary); font-size: var(--type-body-md); line-height: 1.65; text-wrap: pretty; } .auth-footnote { margin: 0; color: var(--color-ink-tertiary); font-size: var(--type-caption); } .auth-panel { width: 100%; min-width: 0; display: flex; flex-direction: column; justify-content: center; padding: var(--space-12); border: 0; border-radius: 0; background: var(--color-canvas); } -.auth-brand { align-items: center; gap: 10px; font-size: 17px; display: none; margin-bottom: var(--space-10); } +.auth-brand { align-items: center; gap: var(--space-3); font-size: var(--type-title-lg); display: none; margin-bottom: var(--space-10); } .auth-panel h1 { font-size: var(--type-display-md); } .page-intro { line-height: 1.6; margin: var(--space-3) 0 var(--space-8); color: var(--color-ink-secondary); font-size: var(--type-body-md); } -.auth-test-channel { margin: 0 0 var(--space-6); padding: 10px 12px; border: 1px dashed color-mix(in srgb, var(--color-action) 40%, var(--color-border)); border-radius: var(--radius-md); background: var(--color-action-soft); color: var(--color-ink-secondary); line-height: 1.5; font-size: var(--type-caption); } +.auth-test-channel { margin: 0 0 var(--space-6); padding: var(--space-3); border: 1px dashed color-mix(in srgb, var(--color-action) 40%, var(--color-border)); border-radius: var(--radius-md); background: var(--color-action-soft); color: var(--color-ink-secondary); line-height: 1.5; font-size: var(--type-caption); } .auth-test-channel strong { color: var(--color-action); font-family: var(--font-mono); font-size: 15px; font-variant-numeric: tabular-nums; letter-spacing: .12em; } .stack-form { display: grid; gap: var(--space-3); } .stack-form label { font-size: 13px; } @@ -1769,7 +1768,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .generated-list > div { min-height: 48px; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 12px; padding: 0 12px; border: 0; border-radius: var(--radius-md); background: var(--color-canvas-muted); } .generated-list code { font-family: var(--font-mono); } .generated-list button { min-width: 44px; min-height: 44px; border: 0; background: transparent; cursor: pointer; color: var(--color-action); } -.code-status { display: inline-flex; min-height: 28px; align-items: center; padding: 0 9px; border-radius: var(--radius-md); background: var(--color-canvas-muted); color: var(--color-ink-secondary); } +.code-status { display: inline-flex; min-height: 28px; align-items: center; padding: 0 var(--space-2); border-radius: var(--radius-md); background: var(--color-canvas-muted); color: var(--color-ink-secondary); } .status-可用 { background: var(--color-success-muted); color: var(--color-success); } .status-已过期, .status-已兑换, .empty-cell { color: var(--color-ink-tertiary); } @@ -1806,7 +1805,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class [data-sidebar="rail"] { display: none; } .chat-panel { grid-template-rows: calc(64px + env(safe-area-inset-top)) minmax(0, 1fr) auto; } .chat-panel.is-rectification { grid-template-rows: calc(64px + env(safe-area-inset-top)) minmax(0, 1fr); } - .chat-header { gap: 10px; padding: max(0px, env(safe-area-inset-top)) var(--space-3) 0; } + .chat-header { gap: var(--space-3); padding: max(0px, env(safe-area-inset-top)) var(--space-3) 0; } .conversation.is-empty { display: block; place-items: initial; @@ -2528,7 +2527,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class padding: 0; color: var(--color-ink); font-size: var(--type-title-sm); - font-weight: 700; + font-weight: 600; } .birth-time-source-intro { margin: 0 0 var(--space-3); color: var(--color-ink-secondary); font-size: var(--type-caption); line-height: 1.55; } .birth-time-source-list { grid-template-columns: 1fr; gap: var(--space-2); } @@ -2552,8 +2551,8 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class } .birth-time-window-details .birth-time-skip-button { grid-column: 1 / -1; justify-self: start; min-height: 44px; padding-inline: 13px; border-color: transparent; background: transparent; color: var(--color-action); font-size: var(--type-caption); } .birth-time-window-details .birth-time-skip-button:hover { background: color-mix(in srgb, var(--color-action-soft) 72%, transparent); } -.birth-time-detail-grid > label { gap: 7px; } -.birth-time-detail-grid > label > span { color: var(--color-ink-secondary); font-size: var(--type-caption); font-weight: 700; } +.birth-time-detail-grid > label { gap: var(--space-2); } +.birth-time-detail-grid > label > span { color: var(--color-ink-secondary); font-size: var(--type-caption); font-weight: 600; } .birth-time-detail-grid textarea { width: 100%; min-width: 0; @@ -2595,7 +2594,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class } /* shadcn-style select used in onboarding; the native controls remain untouched elsewhere. */ -.select-trigger { width: 100%; min-height: 44px; display: inline-flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: 0 13px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); font: inherit; text-align: left; transition: border-color 160ms ease-out, box-shadow 160ms ease-out, background-color 160ms ease-out; } +.select-trigger { width: 100%; min-height: 44px; display: inline-flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: 0 var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); font: inherit; text-align: left; transition: border-color 160ms ease-out, box-shadow 160ms ease-out, background-color 160ms ease-out; } .select-trigger:hover { border-color: color-mix(in srgb, var(--color-action) 42%, var(--color-border)); background: var(--color-canvas-soft); } .select-trigger:focus-visible { border-color: var(--color-action); outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-action) 18%, transparent); } .select-trigger[data-popup-open] { border-color: var(--color-action); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-action) 14%, transparent); } @@ -2607,9 +2606,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .select-content { width: var(--anchor-width); min-width: 190px; max-width: min(360px, calc(100vw - 32px)); height: auto !important; max-height: min(360px, calc(100vh - 32px)); overflow: hidden; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); padding: 5px; box-shadow: var(--shadow-elevated); transform-origin: var(--transform-origin); animation: select-content-in 140ms var(--ease-out) both; } .select-list { display: grid; gap: 2px; max-height: min(320px, 50vh) !important; overflow-y: auto !important; outline: none; scrollbar-width: none; -ms-overflow-style: none; } .select-list::-webkit-scrollbar { width: 0; height: 0; display: none; } -.select-item { min-height: 44px; position: relative; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: 9px 10px; border-radius: var(--radius-sm); color: var(--color-ink); font-size: var(--type-body-sm); line-height: 1.35; cursor: pointer; outline: none; user-select: none; } +.select-item { min-height: 44px; position: relative; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); color: var(--color-ink); font-size: var(--type-body-sm); line-height: 1.35; cursor: pointer; outline: none; user-select: none; } .select-item:hover, .select-item[data-highlighted] { background: var(--color-action-soft); color: var(--color-action-hover); } -.select-item[data-selected] { color: var(--color-action-hover); font-weight: 650; } +.select-item[data-selected] { color: var(--color-action-hover); font-weight: 600; } .select-item[data-disabled] { cursor: not-allowed; opacity: .45; } .select-item-indicator { display: inline-flex; flex: 0 0 auto; color: var(--color-action); } @keyframes select-content-in { from { opacity: 0; transform: translateY(-3px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } } @@ -2622,7 +2621,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class /* onboarding controls */ .birth-time-clock-selects { width: min(100%, 250px); display: grid !important; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; } -.birth-time-clock-separator { color: var(--color-ink-secondary); font-size: var(--type-title-sm); font-weight: 700; } +.birth-time-clock-separator { color: var(--color-ink-secondary); font-size: var(--type-title-sm); font-weight: 600; } .birth-time-clock-selects .select-trigger { min-width: 0; } .birth-time-clock-menu.select-content { width: 108px; min-width: 108px; } @@ -2843,7 +2842,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class display: flex; flex-wrap: wrap; align-items: baseline; - gap: 6px 10px; + gap: var(--space-2) var(--space-3); } .rectification-board__minute time { font-variant-numeric: tabular-nums; @@ -2856,7 +2855,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .rectification-board__chips { display: flex; flex-wrap: wrap; - gap: 6px; + gap: var(--space-2); flex: 1 1 100%; margin: 0; padding: 0; @@ -2989,9 +2988,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class } .rectification-candidates { display: grid; - gap: 14px; + gap: var(--space-4); margin: 0; - padding: 18px; + padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas-soft); @@ -3005,7 +3004,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class display: grid; gap: var(--space-3); margin: 0; - padding: 18px; + padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas-soft); @@ -3053,7 +3052,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class font-size: var(--type-caption); line-height: 1.5; } -.rectification-candidates-heading { display: grid; gap: 5px; } +.rectification-candidates-heading { display: grid; gap: var(--space-1); } .rectification-candidates-heading strong { font-size: var(--type-title-sm); font-family: var(--font-display); font-weight: 600; letter-spacing: -.2px; } .rectification-candidates-heading span, .rectification-candidate-support { color: var(--color-ink-secondary); font-size: var(--type-caption); line-height: 1.5; } @@ -3062,14 +3061,14 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class width: 100%; min-width: 0; grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 10px; + gap: var(--space-3); } .rectification-candidate { display: grid; - gap: 10px; + gap: var(--space-3); min-width: 0; min-height: 132px; - padding: 14px; + padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-lg); color: var(--color-ink); @@ -3092,14 +3091,14 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .rectification-candidate-time { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .rectification-candidate-time strong { font-size: var(--type-title-md); font-family: var(--font-display); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.2px; } .rectification-candidate-badge { - padding: 2px 7px; + padding: var(--space-1) var(--space-2); border-radius: 999px; color: var(--color-action) !important; background: color-mix(in srgb, var(--color-action) 10%, transparent); - font-size: 11px !important; - font-weight: 650; + font-size: var(--type-overline) !important; + font-weight: 600; } -.rectification-candidate-action { align-self: end; color: var(--color-action); font-size: 13px; font-weight: 650; } +.rectification-candidate-action { align-self: end; color: var(--color-action); font-size: 13px; font-weight: 600; } .rectification-saved { width: calc(100% - var(--assistant-content-inset)); margin: 8px 0 16px; @@ -3125,7 +3124,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class width: calc(100% - var(--assistant-content-inset)); margin: 8px 0 16px; margin-inline-start: var(--assistant-content-inset); - padding: 18px; + padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas-soft); @@ -3177,7 +3176,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class background: transparent; color: var(--color-action); font: inherit; - font-weight: 650; + font-weight: 600; cursor: pointer; } .rectification-adopt-status__link:focus-visible { @@ -3193,12 +3192,12 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class display: grid; gap: var(--space-3); margin: 0; - padding: 18px; + padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas-soft); } -.rectification-house-table__heading { display: grid; gap: 5px; } +.rectification-house-table__heading { display: grid; gap: var(--space-1); } .rectification-house-table__heading strong { font-size: var(--type-title-sm); font-family: var(--font-display); @@ -3213,7 +3212,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .rectification-house-table .markdown-table { margin: 0; } @media (max-width: 640px) { .rectification-house-table, - .rectification-candidates { padding: 14px; } + .rectification-candidates { padding: var(--space-4); } .rectification-candidate-list { grid-template-columns: none; grid-auto-flow: column; @@ -3362,8 +3361,8 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class width: fit-content; display: inline-flex; align-items: center; - gap: 6px; - padding: 2px 10px; + gap: var(--space-2); + padding: var(--space-1) var(--space-3); border-radius: 999px; background: var(--color-canvas-muted); color: var(--color-ink-secondary); @@ -3534,7 +3533,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class max-width: 440px; display: inline-flex; align-items: center; - gap: 6px; + gap: var(--space-2); color: var(--color-warning); font-size: var(--type-caption); line-height: 1.45; @@ -3765,7 +3764,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class flex: 0 0 auto; display: inline-flex; align-items: center; - padding: 2px 10px; + padding: var(--space-1) var(--space-3); border-radius: 999px; background: var(--color-canvas); color: var(--color-ink-secondary); @@ -3818,7 +3817,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .personal-report-evidence-links { display: flex; flex-wrap: wrap; - gap: 7px 16px; + gap: var(--space-2) var(--space-4); margin: var(--space-4) 0 0; padding: 0; list-style: none; @@ -3901,13 +3900,13 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class @media (max-width: 760px) { .personal-report-reader-body { padding: 0 var(--space-4) var(--space-12); } - .personal-report-actions > div { min-height: 50px; padding: 6px var(--space-4); } + .personal-report-actions > div { min-height: 50px; padding: var(--space-2) var(--space-4); } .personal-report-action-end > span { display: none; } .personal-report-document { margin-top: var(--space-5); padding: var(--space-6) var(--space-4) var(--space-5); } .personal-report-section { margin-bottom: var(--space-10); } .personal-report-cover-grid { grid-template-columns: 1fr; gap: var(--space-6); } .personal-report-cover h1 { font-size: var(--type-display-md); letter-spacing: -.5px; } - .personal-report-metadata { gap: 7px; } + .personal-report-metadata { gap: var(--space-2); } .personal-report-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } .personal-report-facts > div { padding: var(--space-4) var(--space-2); } .personal-report-facts > div + div { border-left: 0; } @@ -4008,35 +4007,34 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .membership-header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); } .membership-header-left, .membership-header-actions { min-width: 0; display: flex; align-items: center; gap: var(--space-3); } .membership-header-actions { gap: var(--space-2); } -.membership-back, .membership-orders-entry, .membership-redeem-entry { min-height: 44px; display: inline-flex; align-items: center; gap: var(--space-2); padding: 0 12px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-canvas); color: var(--color-ink-secondary); cursor: pointer; font-size: 14px; text-decoration: none; } -.membership-redeem-entry { color: var(--color-action); } +.membership-back, .membership-orders-entry, .membership-redeem-entry { min-height: 44px; display: inline-flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-canvas); color: var(--color-ink-secondary); cursor: pointer; font-size: var(--type-body-sm); text-decoration: none; } .membership-back:hover, .membership-orders-entry:hover, .membership-redeem-entry:hover { border-color: var(--color-border-strong); color: var(--color-ink); } .membership-back svg, .membership-redeem-entry svg { width: 16px; height: 16px; } -.membership-title { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-lg); font-weight: 650; letter-spacing: -.02em; } +.membership-title { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-lg); font-weight: 600; letter-spacing: -.02em; } .membership-hero { min-height: 0; display: block; padding: var(--space-8); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-canvas-soft); } .membership-hero-copy { max-width: 760px; } .membership-greeting { margin: 0 0 var(--space-3); color: var(--color-ink-secondary); font-size: var(--type-body-sm); } -.membership-hero h2 { max-width: 680px; margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: clamp(28px, 4vw, 40px); font-weight: 650; letter-spacing: -.03em; line-height: 1.12; text-wrap: balance; } +.membership-hero h2 { max-width: 680px; margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: clamp(28px, 4vw, 40px); font-weight: 600; letter-spacing: -.03em; line-height: 1.12; text-wrap: balance; } .membership-summary { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; margin-top: var(--space-6); border-top: 1px solid var(--color-border); } .membership-summary-card { min-width: 0; display: grid; gap: var(--space-1); padding: var(--space-4) 0 0; border: 0; border-radius: 0; background: transparent; } .membership-summary-card + .membership-summary-card { padding-left: var(--space-5); border-left: 1px solid var(--color-border); } .membership-summary-card span { color: var(--color-ink-secondary); font-size: var(--type-caption); } -.membership-summary-card strong { color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 650; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; } +.membership-summary-card strong { color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; } .membership-summary-card small { color: var(--color-ink-tertiary); font-size: var(--type-caption); line-height: 1.5; } .membership-section-heading { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); } .membership-section-heading > div { display: grid; gap: var(--space-1); } -.membership-section-heading h2 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 650; letter-spacing: -.01em; } +.membership-section-heading h2 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 600; letter-spacing: -.01em; } .membership-section-heading p { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-body-sm); line-height: 1.55; } -.membership-orders-refresh { flex: 0 0 auto; padding: 6px 10px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-canvas); color: var(--color-ink-secondary); cursor: pointer; font-size: var(--type-caption); } +.membership-orders-refresh { flex: 0 0 auto; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-canvas); color: var(--color-ink-secondary); cursor: pointer; font-size: var(--type-caption); } .membership-order-list { display: grid; gap: 0; margin: 0; padding: 0; border-top: 1px solid var(--color-border); list-style: none; } .membership-order-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: var(--space-4); padding: var(--space-4) 0; border-bottom: 1px solid var(--color-border); background: transparent; } .membership-order-row > div { min-width: 0; display: grid; gap: 2px; } .membership-order-row strong { overflow: hidden; color: var(--color-ink); font-size: var(--type-body-sm); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; } .membership-order-row small { color: var(--color-ink-tertiary); font-size: var(--type-caption); font-variant-numeric: tabular-nums; } .membership-order-row b { color: var(--color-ink); font-size: var(--type-body-sm); font-weight: 600; font-variant-numeric: tabular-nums; } -.membership-order-status { padding: 0; border-radius: 0; background: transparent; font-size: var(--type-caption); font-weight: 650; } +.membership-order-status { padding: 0; border-radius: 0; background: transparent; font-size: var(--type-caption); font-weight: 600; } .membership-order-status.status-paid { color: var(--color-success); } .membership-order-status.status-pending { color: var(--color-action-hover); } .membership-order-status.status-failed { color: var(--color-danger); } @@ -4047,11 +4045,11 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .membership-plan-card--recommended { border-color: var(--color-border-strong); background: var(--color-canvas); } .membership-plan-card--current { border-color: var(--color-action); } .membership-card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); } -.membership-card-header h3, .membership-credit-copy h3 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 650; letter-spacing: -.01em; } +.membership-card-header h3, .membership-credit-copy h3 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 600; letter-spacing: -.01em; } .membership-card-meta { margin: 4px 0 0; color: var(--color-ink-tertiary); font-size: var(--type-caption); } -.membership-status { color: var(--color-action); font-size: var(--type-caption); font-weight: 650; white-space: nowrap; } +.membership-status { color: var(--color-action); font-size: var(--type-caption); font-weight: 600; white-space: nowrap; } .membership-status.is-current { color: var(--color-success); } -.membership-card-price { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-display-sm); font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.02em; } +.membership-card-price { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-display-sm); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.02em; } .membership-card-price small { color: var(--color-ink-secondary); font-family: var(--font-body); font-size: var(--type-caption); font-weight: 400; letter-spacing: 0; } .membership-card-audience { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-body-sm); line-height: 1.6; } .membership-card-entitlements { display: grid; gap: var(--space-2); margin: 0; padding: 0 0 0 18px; } @@ -4067,7 +4065,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .membership-payment-icon { display: grid; place-items: center; color: var(--color-action); } .membership-payment-icon svg { width: 24px; height: 24px; } .membership-payment-copy { min-width: 0; display: grid; gap: var(--space-1); } -.membership-payment-copy h3 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 650; } +.membership-payment-copy h3 { margin: 0; color: var(--color-ink); font-family: var(--font-body); font-size: var(--type-title-md); font-weight: 600; } .membership-payment-copy p { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-body-sm); line-height: 1.55; font-variant-numeric: tabular-nums; } .membership-payment-panel .dialog-actions { margin: 0; } .membership-redeem { width: min(100%, 480px); } diff --git a/frontend/src/app/membership/page.tsx b/frontend/src/app/membership/page.tsx index b1265585..cbda3608 100644 --- a/frontend/src/app/membership/page.tsx +++ b/frontend/src/app/membership/page.tsx @@ -6,6 +6,7 @@ import type { FormEvent } from "react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { ArrowLeft, CheckCircle2, Gift, Sparkles, X } from "lucide-react"; +import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { keepFocusWithin } from "@/lib/focus-trap"; import { @@ -348,14 +349,14 @@ function MembershipContent() {

{paymentError}

{selectedProductId && ( - + )}
)} @@ -406,14 +407,15 @@ function MembershipContent() {
  • 支付由合作渠道处理;如长时间未到账,请联系支持并出示订单号。
  • - + ); })} @@ -444,14 +446,15 @@ function MembershipContent() {
  • 点数充值支付成功后立即到账。
  • - + ))} @@ -491,16 +494,16 @@ function MembershipContent() {
    {paymentOrder.status === "failed" && ( - + )} - +
    )} @@ -544,15 +547,15 @@ function MembershipContent() { }} placeholder="输入完整兑换码" /> - + {redeemError &&

    {redeemError}

    } {redeemMessage &&

    {redeemMessage}

    } {redeemDone && (
    - +
    )} diff --git a/frontend/tests/membership-page.test.ts b/frontend/tests/membership-page.test.ts index e21fa622..81d83431 100644 --- a/frontend/tests/membership-page.test.ts +++ b/frontend/tests/membership-page.test.ts @@ -162,7 +162,12 @@ test("plan cards carry price, duration, audience, entitlements, purchase and rul assert.match(pageSource, /entitlementLabel\(entitlement\)/); assert.match(pageSource, /
    /); assert.match(pageSource, /详细规则<\/summary>/); - assert.match(pageSource, /className=\{recommended \? "button-primary membership-buy" : "button-secondary membership-buy"\}/); + // 原值: className={recommended ? "button-primary membership-buy" : "button-secondary membership-buy"} + // 新值: Button className="membership-buy" + variant default|outline + // 原因: 会员购买走共用 Button;登录/引导仍用 .button-primary 类(page.tsx 冻结与破坏确认合同) + assert.match(pageSource, /import \{ Button \} from "@\/components\/ui\/button"/); + assert.match(pageSource, /className="membership-buy"/); + assert.match(pageSource, /variant=\{recommended \? "default" : "outline"\}/); }); test("renewal semantics map the active subscription to the matching plan", () => { @@ -305,7 +310,10 @@ test("redeem modal reuses the existing account dialog classes", () => { assert.match(pageSource, /className="redeem-form"/); assert.match(pageSource, /className="form-error" role="alert"/); assert.match(pageSource, /className="form-success" role="status"/); - assert.match(pageSource, /className="button-primary"/); + // 原值: className="button-primary" + // 新值: