diff --git a/frontend/src/styles.css b/frontend/src/styles.css index ff14f56..6866a25 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1,51 +1,127 @@ -/* Fully self-contained: no remote font dependency. */ +/* ========================================================================== + Codex Helper - Knolling Pastel Flat Lay Design System + Source: design.md + - Style: Organized, Flat Lay, Clean 90° Alignment, Pastel Restraint, Matte Stock + - Palette: Primary #F6D0D6 (Pastel Pink), Secondary #2D2D2D (Charcoal), + Tertiary #CBE4F0 (Pastel Blue), Neutral #D0F0C0 (Soft Mint), + Surface #E6E6FA (Lavender), Border #00000020 + - Typography: Lato, JetBrains Mono, 12px Base Corner Radius + ========================================================================== */ + :root { - font-family: Inter, "PingFang SC", sans-serif; + font-family: + Lato, + Inter, + -apple-system, + BlinkMacSystemFont, + "PingFang SC", + "Hiragino Sans GB", + "Microsoft YaHei", + sans-serif; color-scheme: light; scrollbar-gutter: stable; - --bg: #f4f7fa; - --panel: #fff; - --text: #101820; - --muted: #71808d; - --border: #dfe7ec; - --accent: #25bfd5; - --accent2: #596ef3; - --track: #e8eff2; - --grid: #e5ecef; - --danger: #e84e61; - --green: #25b978; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + /* Knolling Pastel Palette */ + --pastel-pink: #f6d0d6; + --pastel-blue: #cbe4f0; + --pastel-mint: #d0f0c0; + --pastel-lavender: #e6e6fa; + --charcoal: #2d2d2d; + + --bg: #f7d9df; + --bg-gradient: linear-gradient( + 135deg, + #f6d0d6 0%, + #f8dfe3 40%, + #ebe6f7 75%, + #dbebf5 100% + ); + --panel: #ffffff; + --panel-secondary: #faf7fa; + --text: #2d2d2d; + --muted: #6e6978; + --border: rgba(45, 45, 45, 0.12); + --border-strong: rgba(45, 45, 45, 0.22); + --accent: #357a9f; + --accent-btn: #cbe4f0; + --accent-btn-hover: #b4dced; + --accent-btn-text: #2d2d2d; + --track: #eee5ea; + --grid: rgba(45, 45, 45, 0.08); + --danger: #d93d54; + --danger-bg: #fde8ec; + --danger-border: #f8abb6; + --green: #218c57; + --green-bg: #e6f7e2; + --green-border: #b8e6b0; + + /* Elevation: Soft Natural Flat Lay Drop Shadows */ + --shadow-sm: + 0 1px 3px rgba(45, 45, 45, 0.06), 0 1px 2px rgba(45, 45, 45, 0.04); + --shadow-md: + 0 3px 12px rgba(45, 45, 45, 0.06), 0 1px 3px rgba(45, 45, 45, 0.04); + --shadow-lg: + 0 8px 24px rgba(45, 45, 45, 0.08), 0 2px 6px rgba(45, 45, 45, 0.04); + + --radius-xs: 6px; + --radius-sm: 10px; + --radius-md: 14px; + --radius-lg: 20px; } + html[data-theme="dark"] { color-scheme: dark; - --bg: #071015; - --panel: #0d181f; - --text: #edfafd; - --muted: #7f98a4; - --border: #1b3039; - --track: #263740; - --grid: #183039; - --green: #38d996; + + /* Knolling Dark Charcoal & Pastel Tone */ + --bg: #1c1822; + --bg-gradient: linear-gradient(135deg, #1c1822 0%, #25202e 50%, #1e222a 100%); + --panel: #272230; + --panel-secondary: #2f2a3a; + --text: #f5f2f8; + --muted: #a19ba9; + --border: rgba(255, 255, 255, 0.12); + --border-strong: rgba(255, 255, 255, 0.22); + --accent: #6db6dd; + --accent-btn: #354e63; + --accent-btn-hover: #405c75; + --accent-btn-text: #f5f2f8; + --track: #352f42; + --grid: rgba(255, 255, 255, 0.08); + --danger: #f2687c; + --danger-bg: rgba(242, 104, 124, 0.16); + --danger-border: rgba(242, 104, 124, 0.35); + --green: #40d492; + --green-bg: rgba(64, 212, 146, 0.16); + --green-border: rgba(64, 212, 146, 0.35); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.5); } + * { box-sizing: border-box; } + body { margin: 0; min-width: 320px; - background: - radial-gradient( - circle at 85% 5%, - color-mix(in srgb, var(--accent) 9%, transparent), - transparent 32% - ), - var(--bg); + background: var(--bg-gradient); + background-attachment: fixed; color: var(--text); + line-height: 1.6; } + button, input, select { font: inherit; + letter-spacing: inherit; } + .center { min-height: 100vh; min-height: 100dvh; @@ -53,44 +129,66 @@ select { place-content: center; gap: 24px; } + +/* Spinner Animation */ .spinner { width: 34px; height: 34px; border: 3px solid var(--track); border-top-color: var(--accent); border-radius: 50%; - animation: spin 0.8s linear infinite; + animation: spin 0.75s cubic-bezier(0.4, 0, 0.2, 1) infinite; margin: auto; } + @keyframes spin { to { transform: rotate(360deg); } } + +/* Brand & Logo - Clean 90° Alignment */ .logo { display: flex; align-items: center; gap: 10px; font-weight: 700; - letter-spacing: -0.03em; + letter-spacing: -0.02em; white-space: nowrap; + user-select: none; } + .logo svg { color: var(--accent); width: 22px; height: 22px; } + +.brand-name { + color: var(--text); + font-weight: 750; + letter-spacing: -0.02em; +} + .version-badge { - padding: 2px 6px; + padding: 2px 8px; border: 1px solid var(--border); border-radius: 999px; color: var(--muted); font-size: 11px; font-weight: 600; - letter-spacing: 0; + letter-spacing: 0.02em; line-height: 1.2; white-space: nowrap; + background: var(--pastel-lavender); + box-shadow: var(--shadow-sm); } + +html[data-theme="dark"] .version-badge { + background: var(--panel-secondary); +} + +/* Setup Page - Knolling Hero & Flat Lay Form */ .setup { min-height: 100vh; min-height: 100dvh; @@ -100,111 +198,227 @@ select { gap: 8vw; padding: 7vw; } + .setup-mobile-brand { display: none; } + .hero h1 { - font-size: clamp(42px, 5vw, 76px); - line-height: 1.05; - letter-spacing: -0.055em; + font-size: clamp(38px, 4.5vw, 68px); + line-height: 1.12; + letter-spacing: -0.04em; + font-weight: 800; + margin: 20px 0 16px; + color: var(--text); } + .hero h1 span { color: var(--accent); } + .hero p { color: var(--muted); font-size: 18px; + max-width: 480px; + line-height: 1.6; } + +/* Panels & Cards - Matte Paper Surfaces */ .panel { - background: color-mix(in srgb, var(--panel) 94%, transparent); + background: var(--panel); border: 1px solid var(--border); - border-radius: 18px; - box-shadow: 0 16px 50px rgba(0, 0, 0, 0.05); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + transition: + border-color 0.2s ease, + box-shadow 0.2s ease; } + +/* Forms */ .form { - padding: 32px; + padding: 34px; display: flex; flex-direction: column; gap: 18px; } + .form h2 { margin: 0; - font-size: 26px; + font-size: 24px; + font-weight: 750; + letter-spacing: -0.02em; } + .form small, .hint, .form p { color: var(--muted); } + +.hint { + font-size: 13px; + line-height: 1.5; +} + label { display: flex; flex-direction: column; gap: 8px; font-size: 13px; + font-weight: 550; color: var(--muted); } + input, select { border: 1px solid var(--border); - background: var(--bg); + background: var(--panel-secondary); color: var(--text); - border-radius: 10px; - padding: 12px; + border-radius: var(--radius-sm); + padding: 11px 14px; outline: none; + font-size: 14px; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease, + background-color 0.2s ease; } + +input:hover, +select:hover { + border-color: var(--border-strong); +} + input:focus, select:focus { border-color: var(--accent); - box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent); + box-shadow: 0 0 0 2px var(--accent-btn); + background: var(--panel); } + +/* Buttons - Knolling Flat Lay Style (Moderately rounded 12px, Accent fill, No outer glows) */ button { - border: 0; - border-radius: 10px; - padding: 11px 16px; - background: linear-gradient(120deg, var(--accent), var(--accent2)); - color: #fff; + border: 1px solid var(--border-strong); + border-radius: var(--radius-md); + padding: 11px 18px; + background: var(--accent-btn); + color: var(--accent-btn-text); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-weight: 600; + font-size: 14px; + box-shadow: var(--shadow-sm); + transition: + transform 0.15s ease, + background-color 0.2s ease, + box-shadow 0.2s ease, + opacity 0.2s ease, + border-color 0.2s ease; } + +button:hover:not(:disabled) { + background: var(--accent-btn-hover); + transform: translateY(-1px); + box-shadow: var(--shadow-md); +} + +button:active:not(:disabled) { + transform: translateY(0) scale(0.99); +} + button:disabled { - opacity: 0.65; + opacity: 0.5; cursor: not-allowed; + transform: none !important; + box-shadow: none; } + button svg { width: 17px; + height: 17px; } + +/* Secondary Button - Outline Variant with muted border */ +.secondary { + background: var(--panel); + border: 1.5px solid var(--border); + color: var(--text); + box-shadow: var(--shadow-sm); +} + +.secondary:hover:not(:disabled) { + background: var(--pastel-lavender); + border-color: var(--border-strong); + color: var(--text); + box-shadow: var(--shadow-md); +} + +html[data-theme="dark"] .secondary:hover:not(:disabled) { + background: var(--panel-secondary); +} + +/* Danger Button */ +.danger { + background: var(--danger-bg); + border: 1px solid var(--danger-border); + color: var(--danger); + box-shadow: var(--shadow-sm); +} + +.danger:hover:not(:disabled) { + background: color-mix(in srgb, var(--danger-bg) 80%, var(--danger)); + border-color: var(--danger); + color: var(--danger); + box-shadow: var(--shadow-md); +} + +.icon { + padding: 10px; +} + +/* Login Page */ .login { width: min(420px, 90vw); position: relative; + box-shadow: var(--shadow-lg); } + .github-link { - border-radius: 10px; - padding: 11px 16px; + border-radius: var(--radius-sm); + padding: 10px 16px; color: var(--muted); display: inline-flex; align-items: center; justify-content: flex-start; gap: 8px; font-weight: 600; + font-size: 14px; text-decoration: none; + transition: + background-color 0.2s ease, + color 0.2s ease; } + .github-link:hover { background: var(--track); color: var(--text); } + .github-link svg { width: 17px; + height: 17px; } + .login-github { position: absolute; - top: 16px; - right: 16px; + top: 18px; + right: 18px; padding: 9px; } + .login-github span { position: absolute; width: 1px; @@ -212,19 +426,24 @@ button svg { overflow: hidden; clip: rect(0 0 0 0); } + .error { color: var(--danger) !important; } + +/* App Shell Layout */ .app { display: grid; - grid-template-columns: 230px 1fr; + grid-template-columns: 236px 1fr; min-height: 100vh; min-height: 100dvh; } + .public-app { min-height: 100vh; min-height: 100dvh; } + .public-header { display: flex; flex-direction: row; @@ -232,28 +451,37 @@ button svg { justify-content: space-between; gap: 20px; width: 100%; - max-width: 1500px; + max-width: 1400px; margin: 0 auto 0; - padding: 24px 42px; + padding: 22px 40px; border-bottom: 1px solid var(--border); + background: color-mix(in srgb, var(--panel) 90%, var(--bg)); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); } + .public-header button { white-space: nowrap; } + .public-content { width: 100%; - max-width: 1500px; + max-width: 1400px; margin: 0 auto; - padding: 42px; + padding: 38px 40px; } + .public-login-link { margin: -4px 0 0; text-align: center; } + .mobile-topbar, .mobile-bottom-nav { display: none; } + +/* Sidebar Navigation */ aside { border-right: 1px solid var(--border); padding: 28px 18px; @@ -262,125 +490,187 @@ aside { position: sticky; top: 0; height: 100vh; - background: color-mix(in srgb, var(--bg) 88%, transparent); - backdrop-filter: blur(15px); + background: color-mix(in srgb, var(--panel) 88%, var(--bg)); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + z-index: 10; } + aside .logo { padding: 0 10px 28px; } + aside .logo svg { width: 30px; height: 30px; flex-shrink: 0; } + nav { display: flex; flex-direction: column; gap: 6px; } + aside button, .tabs button { justify-content: flex-start; background: transparent; color: var(--muted); + border: 1px solid transparent; + box-shadow: none; + font-weight: 550; + padding: 10px 14px; + border-radius: var(--radius-md); } + aside button:hover, .aside-bottom a:hover, +.tabs button:hover { + background: color-mix(in srgb, var(--track) 70%, transparent); + color: var(--text); + transform: none; + box-shadow: none; +} + aside nav button.active, -.tabs button:hover, .tabs button.active { - background: var(--track); + background: var(--accent-btn); + color: var(--accent-btn-text); + border: 1px solid var(--border-strong); + font-weight: 650; + transform: none; + box-shadow: var(--shadow-sm); +} + +aside nav button.active svg, +.tabs button.active svg { color: var(--text); } + .aside-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 5px; + padding-top: 18px; + border-top: 1px solid var(--border); } + +/* Content Area */ .content { - padding: 42px; - max-width: 1500px; + padding: 38px 40px; + max-width: 1400px; width: 100%; margin: auto; } + header { display: flex; align-items: center; justify-content: space-between; - margin-bottom: 28px; + margin-bottom: 26px; } + header h1 { margin: 0; - font-size: 30px; - letter-spacing: -0.04em; + font-size: 28px; + font-weight: 800; + letter-spacing: -0.035em; } + header p { - margin: 8px 0; + margin: 8px 0 0; color: var(--muted); + font-size: 14px; } + .header-actions { display: flex; gap: 10px; } -.secondary { - background: var(--panel); - border: 1px solid var(--border); - color: var(--text); -} + +/* Account Overview Cards - Knolling Flat Lay Composition */ .account-overview-list { display: flex; flex-direction: column; gap: 16px; } + .account-overview { overflow: hidden; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease; } + +.account-overview:hover { + border-color: var(--border-strong); + box-shadow: var(--shadow-lg); +} + .account-summary-toggle { width: 100%; display: grid; grid-template-columns: auto minmax(180px, 1fr) auto minmax(280px, 1.5fr) auto; align-items: center; - gap: 14px; - padding: 20px 24px; - border-radius: 17px; + gap: 16px; + padding: 18px 24px; + border-radius: var(--radius-lg); background: transparent; color: var(--text); text-align: left; + border: 0; + box-shadow: none; + cursor: pointer; + transition: background-color 0.15s ease; } -.account-summary-toggle:hover, -.account-summary-toggle:focus-visible { - background: color-mix(in srgb, var(--track) 62%, transparent); + +.account-summary-toggle:hover { + background: color-mix(in srgb, var(--track) 60%, transparent); + transform: none; + box-shadow: none; } + .account-summary-toggle:focus-visible { outline: 2px solid var(--accent); - outline-offset: -3px; + outline-offset: -2px; + background: color-mix(in srgb, var(--track) 60%, transparent); } + .account-summary-identity { display: flex; flex-direction: column; - gap: 5px; + gap: 4px; min-width: 0; } + .account-summary-identity strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + font-size: 16px; + font-weight: 700; + letter-spacing: -0.01em; } + .account-summary-identity span, .account-summary-metrics { color: var(--muted); font-size: 13px; } + .account-summary-identity span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .account-summary-plan { justify-self: start; white-space: nowrap; } + .account-summary-metrics { display: flex; justify-content: flex-end; @@ -388,63 +678,107 @@ header p { gap: 6px 14px; min-width: 0; } + .account-summary-metrics span { white-space: nowrap; } + .account-summary-limits { display: grid; justify-content: end; gap: 8px; width: 100%; } + .account-summary-limits.single { justify-content: center; } + .account-summary-limit { display: grid; grid-template-columns: minmax(76px, auto) 42px 28px minmax(92px, auto); align-items: baseline; gap: 6px; + padding: 4px 10px; + border-radius: var(--radius-sm); + background: var(--panel-secondary); + border: 1px solid var(--border); } + .account-summary-limit-name { color: var(--text); font-weight: 650; + font-size: 13px; } + .account-summary-limit strong { - font-size: 16px; + font-size: 15px; text-align: right; + font-variant-numeric: tabular-nums; + font-weight: 750; } + .account-summary-limit-remaining { font-size: 12px; + color: var(--muted); } + .account-summary-limit-reset { padding-left: 10px; border-left: 1px solid var(--border); text-align: left; + font-size: 12px; + color: var(--muted); } + .account-chevron { flex: none; width: 20px; + height: 20px; color: var(--muted); - transition: transform 0.2s ease; + transition: + transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), + color 0.2s ease; } + +.account-summary-toggle:hover .account-chevron { + color: var(--text); +} + .account-overview.expanded .account-chevron { transform: rotate(180deg); + color: var(--accent); } + +/* Account Detail Section */ .account-detail { display: flex; flex-direction: column; gap: 20px; padding: 0 24px 24px; border-top: 1px solid var(--border); + animation: accountDetailExpand 0.25s cubic-bezier(0.16, 1, 0.3, 1); } + +@keyframes accountDetailExpand { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + .account-detail-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; - padding-top: 22px; + padding-top: 20px; } + .account-detail-title, .account-detail-actions, .limit-heading, @@ -452,139 +786,190 @@ header p { display: flex; align-items: center; } + .account-detail-title { gap: 12px; } + .account-detail-title > svg { width: 24px; height: 24px; color: var(--accent); } + .account-detail-title small, .account-info-item small { color: var(--muted); + font-size: 12px; + font-weight: 550; + text-transform: uppercase; + letter-spacing: 0.04em; } + .account-detail-title h2 { - margin: 4px 0 0; + margin: 2px 0 0; font-size: 22px; + font-weight: 750; + letter-spacing: -0.02em; } + .account-detail-actions { justify-content: flex-end; gap: 12px; } + .account-detail-actions .fresh { margin-left: 0; } + .account-detail-alert { - padding: 12px 14px; - border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--border)); - border-radius: 10px; - background: color-mix(in srgb, var(--danger) 8%, var(--panel)); + padding: 12px 16px; + border: 1px solid var(--danger-border); + border-radius: var(--radius-md); + background: var(--danger-bg); + color: var(--danger); + font-size: 14px; } + .cycle-note { display: flex; align-items: flex-start; - gap: 8px; - padding: 12px 14px; - border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border)); - border-radius: 10px; - background: color-mix(in srgb, var(--accent) 7%, var(--panel)); - color: var(--muted); + gap: 10px; + padding: 12px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-md); + background: var(--pastel-blue); + color: var(--text); font-size: 13px; line-height: 1.5; } + +html[data-theme="dark"] .cycle-note { + background: var(--panel-secondary); +} + .cycle-note svg { flex: none; - width: 16px; + width: 17px; + height: 17px; margin-top: 2px; color: var(--accent); } + .account-info-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 10px; + gap: 12px; } + .account-info-item { display: flex; align-items: center; - gap: 10px; + gap: 12px; min-width: 0; - padding: 13px 14px; - border-radius: 12px; - background: var(--track); + padding: 12px 14px; + border-radius: var(--radius-md); + background: var(--panel-secondary); + border: 1px solid var(--border); } + .account-info-item > svg { flex: none; width: 18px; + height: 18px; color: var(--accent); } + .account-info-item div { display: flex; flex-direction: column; - gap: 4px; + gap: 2px; min-width: 0; } + .account-info-item b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; + font-weight: 650; } + +/* Reset Credits - Knolling Lavender Banner */ .reset-credits { display: flex; align-items: center; - gap: 12px; - margin-top: 14px; - padding: 12px 14px; - border: 1px solid color-mix(in srgb, var(--accent2) 30%, var(--border)); - border-radius: 12px; - background: color-mix(in srgb, var(--accent2) 7%, var(--panel)); + gap: 14px; + margin-top: 4px; + padding: 13px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-md); + background: var(--pastel-lavender); + box-shadow: var(--shadow-sm); + color: var(--text); } + +html[data-theme="dark"] .reset-credits { + background: var(--panel-secondary); +} + .reset-credits > svg { flex: none; width: 20px; - color: var(--accent2); + height: 20px; + color: var(--accent); } + .reset-credits-main, .reset-credits-expiry { display: flex; min-width: 0; flex-direction: column; - gap: 4px; + gap: 2px; } + .reset-credits-main small, .reset-credits-expiry small { color: var(--muted); font-size: 12px; + font-weight: 550; } + .reset-credits-main b, .reset-credits-expiry b { font-size: 13px; + font-weight: 700; } + .reset-credits-expiry { margin-left: auto; text-align: right; } + .reset-credits-expiry b { overflow-wrap: anywhere; } + .account-detail-state { display: flex; min-height: 170px; align-items: center; justify-content: center; flex-direction: column; - gap: 10px; + gap: 12px; color: var(--muted); text-align: center; } + .account-detail-state .spinner { width: 28px; height: 28px; } + .account-detail-state p { margin: 0; } + .account { padding: 20px 24px; display: flex; @@ -592,43 +977,63 @@ header p { align-items: center; margin-bottom: 20px; } + .account div { display: flex; flex-direction: column; } + .account small, .limit small, .stat small, .chart small { color: var(--muted); } + +/* Status Indicator Dot */ .dot { flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--danger); - box-shadow: 0 0 10px currentColor; + box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 25%, transparent); + transition: all 0.2s ease; } + .dot.ok { background: var(--green); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 25%, transparent); } + .badge { - background: var(--track); - padding: 6px 10px; - border-radius: 99px; + background: var(--pastel-mint); + border: 1px solid var(--border); + padding: 4px 10px; + border-radius: 999px; font-size: 12px; + font-weight: 600; + letter-spacing: 0.01em; + color: var(--text); } + +html[data-theme="dark"] .badge { + background: var(--green-bg); +} + .fresh { margin-left: auto; color: var(--muted); font-size: 12px; } + +/* Limit Cards - Flat Lay Objects */ .limits { display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); - gap: 18px; + gap: 16px; } + .limit { padding: 20px; display: grid; @@ -636,104 +1041,148 @@ header p { gap: 12px; align-items: start; } + .limit > small { grid-column: 1/-1; } + .limit-heading { grid-column: 1/-1; gap: 7px; + font-weight: 650; } + .limit-heading svg, .stat-label svg { - width: 16px; + width: 17px; + height: 17px; color: var(--accent); } + .stat-label { gap: 7px; + font-weight: 600; } + .remaining strong { display: block; - font-size: 50px; + font-size: 46px; line-height: 1; font-variant-numeric: tabular-nums; + font-weight: 850; + letter-spacing: -0.04em; color: var(--green); } + .remaining strong i { font-size: 20px; font-style: normal; + font-weight: 650; + margin-left: 2px; } + .remaining span, .reset span { display: block; color: var(--muted); font-size: 12px; - margin-top: 7px; + margin-top: 6px; } + .reset { text-align: right; } + .reset b { display: block; - font-size: 18px; - margin-top: 7px; + font-size: 16px; + font-weight: 700; + margin-top: 6px; } + +/* Limit Bar */ .bar { grid-column: 1/-1; display: flex; - height: 14px; - border-radius: 99px; + height: 12px; + border-radius: 999px; overflow: hidden; background: var(--track); } + .bar i { - background: #9aa6ad; + background: color-mix(in srgb, var(--muted) 35%, var(--track)); + transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1); } + .bar em { background: var(--green); + transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1); } + .green { color: var(--green); } + +/* Statistics Grid */ .stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; - margin: 20px 0; + margin: 10px 0; } + .stat { - padding: 20px; + padding: 18px 20px; } + .stat b { display: block; font-size: 24px; - margin-top: 10px; + font-weight: 800; + letter-spacing: -0.025em; + font-variant-numeric: tabular-nums; + margin-top: 8px; } + .chart { padding: 24px; min-width: 0; } + .chart h3 { - margin: 0 0 5px; + margin: 0 0 8px; + font-size: 17px; + font-weight: 750; + letter-spacing: -0.02em; } + .banner { - padding: 14px 18px; - border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--border)); - background: color-mix(in srgb, var(--danger) 8%, var(--panel)); - border-radius: 12px; + padding: 13px 16px; + border: 1px solid var(--danger-border); + background: var(--danger-bg); + border-radius: var(--radius-md); margin-bottom: 18px; color: var(--danger); + font-weight: 550; + font-size: 14px; } + .empty { - padding: 32px; + padding: 34px; text-align: center; color: var(--muted); + font-size: 14px; } + +/* Settings Layout */ .settings { display: grid; - grid-template-columns: 190px minmax(0, 1fr); + grid-template-columns: 196px minmax(0, 1fr); gap: 20px; align-items: start; } + .settings-content { display: grid; width: 100%; @@ -741,44 +1190,57 @@ header p { min-width: 0; min-height: 640px; } + .settings-panel { grid-area: 1 / 1; min-width: 0; visibility: hidden; pointer-events: none; } + .settings-panel.active { visibility: visible; pointer-events: auto; } + .tabs { display: flex; flex-direction: column; gap: 5px; } + .wide { width: 100%; max-width: 960px; min-height: 480px; } + .settings-loading { display: grid; place-content: center; } + .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } + .checks { display: flex; flex-direction: row; align-items: center; gap: 10px; + cursor: pointer; + user-select: none; } + .checks input { width: auto; + accent-color: var(--accent); + cursor: pointer; } + .fixed-setting { display: flex; flex-direction: column; @@ -787,62 +1249,80 @@ header p { font-size: 13px; color: var(--muted); } + .fixed-setting b { border: 1px solid var(--border); - background: var(--bg); + background: var(--panel-secondary); color: var(--text); - border-radius: 10px; - padding: 12px; - font-weight: 500; + border-radius: var(--radius-sm); + padding: 11px 14px; + font-weight: 550; + font-size: 14px; } + .actions { display: flex; gap: 10px; } -.danger { - background: transparent; - border: 1px solid var(--danger); - color: var(--danger); -} -.icon { - padding: 10px; -} + +/* Device Code Box - Knolling Monospace Frame */ .codebox { grid-column: 1 / -1; - padding: 16px 18px; - border: 1px dashed var(--accent); - border-radius: 12px; + padding: 16px 20px; + border: 1.5px dashed var(--accent); + border-radius: var(--radius-md); display: flex; justify-content: space-between; align-items: center; gap: 18px; - background: color-mix(in srgb, var(--accent) 6%, var(--panel)); + background: var(--pastel-blue); overflow-wrap: anywhere; + box-shadow: var(--shadow-sm); } + +html[data-theme="dark"] .codebox { + background: var(--panel-secondary); +} + .codebox strong { - font-family: monospace; + font-family: + "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + monospace; font-size: 24px; - letter-spacing: 0.08em; - color: var(--accent); + letter-spacing: 0.1em; + color: var(--text); white-space: nowrap; + font-weight: 750; + background: var(--panel); + padding: 4px 12px; + border-radius: var(--radius-sm); + border: 1px solid var(--border); } + .codex-settings { display: flex; flex-direction: column; gap: 18px; } + .codex-heading h2, .add-account-card h3 { margin: 0; } + .codex-heading h2 { - font-size: 26px; + font-size: 24px; + font-weight: 750; + letter-spacing: -0.02em; } + .codex-heading p, .add-account-card p { color: var(--muted); margin: 7px 0 0; + font-size: 14px; } + .add-account-card { padding: 22px 24px; display: flex; @@ -850,38 +1330,52 @@ header p { justify-content: space-between; gap: 24px; } + +.add-account-card h3 { + font-size: 17px; + font-weight: 700; + letter-spacing: -0.015em; +} + .add-account-controls { display: flex; align-items: end; gap: 10px; } + .add-account-controls label { min-width: 250px; } + .add-account-controls button { min-height: 43px; white-space: nowrap; } + .account-list { display: flex; flex-direction: column; gap: 14px; } + .account-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 20px 28px; padding: 22px 24px; } + .account-card-main { display: flex; align-items: flex-start; gap: 14px; min-width: 0; } + .account-card-main .dot { - margin-top: 15px; + margin-top: 14px; } + .account-details { display: flex; flex-direction: column; @@ -889,13 +1383,15 @@ header p { min-width: 0; flex: 1; } + .account-details input { width: 100%; max-width: 360px; - padding: 9px 11px; + padding: 9px 12px; font-weight: 700; font-size: 16px; } + .account-meta { display: flex; flex-wrap: wrap; @@ -903,15 +1399,18 @@ header p { color: var(--muted); font-size: 13px; } + .account-meta span + span { position: relative; } + .account-meta span + span::before { content: "·"; position: absolute; left: -10px; color: var(--border); } + .account-card-actions { display: flex; flex-direction: column; @@ -919,19 +1418,31 @@ header p { gap: 10px; min-width: 285px; } + .account-buttons { display: flex; gap: 8px; } + .account-buttons .secondary:first-child { flex: 1; } + .account-empty { padding: 44px 24px; } + a { color: var(--accent); + text-decoration: none; + transition: color 0.15s ease; } + +a:hover { + text-decoration: underline; +} + +/* Responsive & Mobile Layout */ @media (max-width: 800px) { :root { scrollbar-gutter: auto; @@ -950,6 +1461,7 @@ a { } .setup-mobile-brand { display: block; + margin-bottom: 4px; } .app { display: block; @@ -968,8 +1480,9 @@ a { min-height: calc(58px + env(safe-area-inset-top)); padding: env(safe-area-inset-top) 12px 0 16px; border-bottom: 1px solid var(--border); - background: color-mix(in srgb, var(--bg) 92%, transparent); - backdrop-filter: blur(15px); + background: color-mix(in srgb, var(--panel) 92%, var(--bg)); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); } .mobile-topbar .logo { min-width: 0; @@ -990,16 +1503,29 @@ a { .mobile-menu-popover { position: absolute; z-index: 30; - top: calc(100% + 7px); + top: calc(100% + 8px); right: 0; display: flex; flex-direction: column; width: min(230px, calc(100vw - 24px)); padding: 8px; border: 1px solid var(--border); - border-radius: 14px; + border-radius: var(--radius-md); background: var(--panel); - box-shadow: 0 18px 50px rgba(0, 0, 0, 0.18); + box-shadow: var(--shadow-lg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + animation: popoverFade 0.2s cubic-bezier(0.16, 1, 0.3, 1); + } + @keyframes popoverFade { + from { + opacity: 0; + transform: scale(0.96) translateY(-4px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } } .mobile-menu-popover button, .mobile-menu-popover .github-link { @@ -1019,8 +1545,10 @@ a { padding: 6px max(12px, env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left)); border-top: 1px solid var(--border); - background: color-mix(in srgb, var(--bg) 94%, transparent); - backdrop-filter: blur(15px); + background: color-mix(in srgb, var(--panel) 94%, var(--bg)); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 -2px 12px rgba(45, 45, 45, 0.05); } .mobile-bottom-nav button { min-height: 52px; @@ -1030,9 +1558,14 @@ a { background: transparent; color: var(--muted); font-size: 12px; + border-radius: var(--radius-sm); + box-shadow: none; + border: 1px solid transparent; } .mobile-bottom-nav button.active { - color: var(--accent); + color: var(--text); + background: var(--accent-btn); + border-color: var(--border-strong); } .mobile-bottom-nav svg { height: 21px; @@ -1252,6 +1785,7 @@ a { grid-column: 1; } } + @media (max-width: 359px) { .brand-name { font-size: 14px; @@ -1281,6 +1815,7 @@ a { flex: 0 0 44px; } } + @media (max-width: 800px) and (orientation: landscape) and (max-height: 500px) { .center, .setup { @@ -1292,9 +1827,14 @@ a { margin: 16px 0; } } + @media (prefers-reduced-motion: reduce) { - * { - animation: none !important; - transition: none !important; + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } } diff --git a/frontend/src/usage-chart.tsx b/frontend/src/usage-chart.tsx index ac79cab..4dc49ba 100644 --- a/frontend/src/usage-chart.tsx +++ b/frontend/src/usage-chart.tsx @@ -48,14 +48,21 @@ export default function UsageChart({ > - - + + + - + date.slice(5) : undefined } @@ -66,6 +73,8 @@ export default function UsageChart({ tickCount={compact ? 4 : 5} tickFormatter={compactAxis} stroke="var(--muted)" + tickLine={false} + axisLine={false} /> [ @@ -75,15 +84,33 @@ export default function UsageChart({ contentStyle={{ background: "var(--panel)", border: "1px solid var(--border)", - borderRadius: 12, + borderRadius: 8, + boxShadow: "var(--shadow-md)", + padding: "8px 12px", + color: "var(--text)", + }} + labelStyle={{ + fontWeight: 600, + color: "var(--muted)", + marginBottom: 4, + }} + itemStyle={{ + color: "var(--accent)", + fontWeight: 650, }} />