feat: implement account management and subscription payment center components

This commit is contained in:
2569718930@qq.com
2026-05-24 23:09:13 +08:00
parent 79a652e8a9
commit 45e9c28437
12 changed files with 480 additions and 333 deletions
@@ -1062,3 +1062,33 @@
@keyframes spin { to { transform: rotate(360deg); } }
/* ── Model Forecast Light Mode Overrides ── */
:global(html.light) .root :global(.model-group) {
background: #f8fafc;
border-left-color: var(--color-border-default);
}
:global(html.light) .root :global(.model-bar-track) {
background: var(--color-bg-input);
}
:global(html.light) .root :global(.model-bar-value) {
color: #ffffff;
text-shadow: 0 1px 2px rgba(15, 23, 42, 0.4);
}
:global(html.light) .root :global(.model-name strong) {
color: var(--color-text-primary);
}
:global(html.light) .root :global(.model-name span) {
color: var(--color-text-muted);
}
:global(html.light) .root :global(.model-stack-summary span) {
background: #ffffff;
border-color: var(--color-border-default);
color: var(--color-text-secondary);
}
@@ -714,6 +714,55 @@
background: var(--bg-card);
}
/* ── Segmented Control: Locale Switcher in Light Mode ── */
.root :global(.scan-terminal.light .scan-locale-switch) {
border-color: #cbd5e1 !important;
background: #e2e8f0 !important;
color: #64748b !important;
}
.root :global(.scan-terminal.light .scan-locale-switch span) {
color: #64748b !important;
}
.root :global(.scan-terminal.light .scan-locale-switch span.active) {
color: #0f172a !important;
background: #ffffff !important;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08) !important;
}
/* ── Status Chips and Manual Refresh button in Light Mode ── */
.root :global(.scan-terminal.light .scan-status-chip) {
border-color: #cbd5e1 !important;
background: #ffffff !important;
color: #475569 !important;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05) !important;
}
.root :global(.scan-terminal.light .scan-status-chip.live) {
border-color: rgba(16, 185, 129, 0.22) !important;
background: rgba(16, 185, 129, 0.12) !important;
color: #065f46 !important;
}
.root :global(.scan-terminal.light .scan-status-chip.stale) {
border-color: rgba(245, 158, 11, 0.24) !important;
background: rgba(245, 158, 11, 0.12) !important;
color: #92400e !important;
}
.root :global(.scan-terminal.light button.scan-status-chip.refresh) {
border-color: #cbd5e1 !important;
background: #ffffff !important;
color: #1e293b !important;
}
.root :global(.scan-terminal.light button.scan-status-chip.refresh:hover) {
background: #f8fafc !important;
border-color: #94a3b8 !important;
}
.root :global(.scan-terminal.light .scan-mode-tab.active) {
color: #1D4ED8;
background: #DBEAFE;
@@ -814,9 +863,7 @@
background: linear-gradient(180deg, rgba(224, 247, 255, 0.82), rgba(241, 248, 255, 0.92));
}
.root :global(.scan-terminal.light .scan-locale-switch),
.root :global(.scan-terminal.light .scan-ghost-button),
.root :global(.scan-terminal.light .scan-theme-button),
.root :global(.scan-terminal.light .scan-sort-pill),
.root :global(.scan-terminal.light .scan-icon-pill),
.root :global(.scan-terminal.light .scan-account-button),
@@ -1221,128 +1268,128 @@
/* ── Leaflet map light overrides (needs !important to beat Leaflet inline styles) ── */
.root :global(.map),
html.light .root :global(.scan-terminal.light .scan-map-shell .map),
html.light .root :global(.scan-terminal.light .scan-map-shell .leaflet-container),
html.light .root :global(.leaflet-container),
html.light .root :global(.leaflet-pane),
html.light .root :global(.leaflet-map-pane),
html.light .root :global(.leaflet-tile-pane) {
:global(html.light) .root :global(.scan-terminal.light .scan-map-shell .map),
:global(html.light) .root :global(.scan-terminal.light .scan-map-shell .leaflet-container),
:global(html.light) .root :global(.leaflet-container),
:global(html.light) .root :global(.leaflet-pane),
:global(html.light) .root :global(.leaflet-map-pane),
:global(html.light) .root :global(.leaflet-tile-pane) {
background: #eef7ff !important;
}
/* ── City detail rail light overrides ── */
html.light .root :global(.scan-city-detail-rail),
html.light .root :global(.scan-terminal.light > .detail-panel.scan-city-detail-rail) {
:global(html.light) .root :global(.scan-city-detail-rail),
:global(html.light) .root :global(.scan-terminal.light > .detail-panel.scan-city-detail-rail) {
background: linear-gradient(180deg, rgba(238, 247, 255, 0.98), rgba(255, 255, 255, 0.96));
border-color: rgba(37, 99, 235, 0.16);
color: var(--text-primary);
}
html.light .root :global(.scan-city-detail-rail .panel-header),
html.light .root :global(.scan-city-detail-rail .detail-structured-section),
html.light .root :global(.scan-city-detail-rail .detail-summary-shell),
html.light .root :global(.scan-city-detail-rail .detail-card) {
:global(html.light) .root :global(.scan-city-detail-rail .panel-header),
:global(html.light) .root :global(.scan-city-detail-rail .detail-structured-section),
:global(html.light) .root :global(.scan-city-detail-rail .detail-summary-shell),
:global(html.light) .root :global(.scan-city-detail-rail .detail-card) {
background: rgba(255, 255, 255, 0.74);
border-color: rgba(125, 171, 214, 0.28);
}
html.light .root :global(.scan-city-detail-rail h2),
html.light .root :global(.scan-city-detail-rail h3),
html.light .root :global(.scan-city-detail-rail strong),
html.light .root :global(.scan-city-detail-rail .detail-value),
html.light .root :global(.scan-city-detail-rail .detail-summary-temp),
html.light .root :global(.scan-city-detail-rail .detail-section-head h3),
html.light .root :global(.scan-city-detail-rail .panel-title-area h2) {
:global(html.light) .root :global(.scan-city-detail-rail h2),
:global(html.light) .root :global(.scan-city-detail-rail h3),
:global(html.light) .root :global(.scan-city-detail-rail strong),
:global(html.light) .root :global(.scan-city-detail-rail .detail-value),
:global(html.light) .root :global(.scan-city-detail-rail .detail-summary-temp),
:global(html.light) .root :global(.scan-city-detail-rail .detail-section-head h3),
:global(html.light) .root :global(.scan-city-detail-rail .panel-title-area h2) {
color: var(--text-primary);
}
html.light .root :global(.scan-city-detail-rail p),
html.light .root :global(.scan-city-detail-rail li),
html.light .root :global(.scan-city-detail-rail small),
html.light .root :global(.scan-city-detail-rail .panel-overline),
html.light .root :global(.scan-city-detail-rail .panel-loading-hint),
html.light .root :global(.scan-city-detail-rail .panel-meta-chip),
html.light .root :global(.scan-city-detail-rail .detail-section-kicker),
html.light .root :global(.scan-city-detail-rail .detail-label),
html.light .root :global(.scan-city-detail-rail .detail-value-muted),
html.light .root :global(.scan-city-detail-rail .detail-source-note),
html.light .root :global(.scan-city-detail-rail .detail-source-kind),
html.light .root :global(.scan-city-detail-rail .detail-mini-meta),
html.light .root :global(.scan-city-detail-rail .detail-summary-supporting),
html.light .root :global(.scan-city-detail-rail .scan-detail-city-sub),
html.light .root :global(.scan-city-detail-rail .scan-detail-volume-caption),
html.light .root :global(.scan-city-detail-rail .scan-detail-score-label),
html.light .root :global(.scan-city-detail-rail .scan-detail-empty) {
:global(html.light) .root :global(.scan-city-detail-rail p),
:global(html.light) .root :global(.scan-city-detail-rail li),
:global(html.light) .root :global(.scan-city-detail-rail small),
:global(html.light) .root :global(.scan-city-detail-rail .panel-overline),
:global(html.light) .root :global(.scan-city-detail-rail .panel-loading-hint),
:global(html.light) .root :global(.scan-city-detail-rail .panel-meta-chip),
:global(html.light) .root :global(.scan-city-detail-rail .detail-section-kicker),
:global(html.light) .root :global(.scan-city-detail-rail .detail-label),
:global(html.light) .root :global(.scan-city-detail-rail .detail-value-muted),
:global(html.light) .root :global(.scan-city-detail-rail .detail-source-note),
:global(html.light) .root :global(.scan-city-detail-rail .detail-source-kind),
:global(html.light) .root :global(.scan-city-detail-rail .detail-mini-meta),
:global(html.light) .root :global(.scan-city-detail-rail .detail-summary-supporting),
:global(html.light) .root :global(.scan-city-detail-rail .scan-detail-city-sub),
:global(html.light) .root :global(.scan-city-detail-rail .scan-detail-volume-caption),
:global(html.light) .root :global(.scan-city-detail-rail .scan-detail-score-label),
:global(html.light) .root :global(.scan-city-detail-rail .scan-detail-empty) {
color: var(--text-secondary);
}
html.light .root :global(.scan-city-detail-rail .panel-meta-chip),
html.light .root :global(.scan-city-detail-rail .panel-weather-chip),
html.light .root :global(.scan-city-detail-rail .detail-source-link),
html.light .root :global(.scan-city-detail-rail .panel-action-button-secondary),
html.light .root :global(.scan-city-detail-rail .panel-action-button-ghost) {
:global(html.light) .root :global(.scan-city-detail-rail .panel-meta-chip),
:global(html.light) .root :global(.scan-city-detail-rail .panel-weather-chip),
:global(html.light) .root :global(.scan-city-detail-rail .detail-source-link),
:global(html.light) .root :global(.scan-city-detail-rail .panel-action-button-secondary),
:global(html.light) .root :global(.scan-city-detail-rail .panel-action-button-ghost) {
background: #eef7ff;
border-color: rgba(37, 99, 235, 0.18);
color: #1f3654;
}
/* ── AI city card light overrides ── */
html.light .root :global(.scan-terminal.light .scan-ai-city-card),
html.light .root :global(.scan-terminal.light .scan-ai-city-section),
html.light .root :global(.scan-terminal.light .scan-ai-decision-band),
html.light .root :global(.scan-terminal.light .scan-ai-market-decision),
html.light .root :global(.scan-terminal.light .scan-ai-decision-metrics span),
html.light .root :global(.scan-terminal.light .scan-ai-city-pills span),
html.light .root :global(.scan-terminal.light .scan-ai-city-freshness span),
html.light .root :global(.scan-terminal.light .scan-ai-city-metrics > span),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-metrics span),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-reason) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-card),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-section),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-band),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-market-decision),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-metrics span),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-pills span),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-freshness span),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-metrics > span),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-metrics span),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-reason) {
background: #eef7ff;
border-color: rgba(37, 99, 235, 0.16);
}
html.light .root :global(.scan-terminal.light .scan-ai-city-metrics > span.primary) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-metrics > span.primary) {
background: #dbeafe;
border-color: rgba(59, 130, 246, 0.34);
}
html.light .root :global(.scan-terminal.light .scan-ai-city-metrics b) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-metrics b) {
color: var(--text-primary);
}
html.light .root :global(.scan-terminal.light .scan-ai-city-metrics > span.primary b) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-metrics > span.primary b) {
color: #1d4ed8;
}
html.light .root :global(.scan-terminal.light .scan-ai-city-metrics small) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-metrics small) {
color: #64748b;
}
html.light .root :global(.scan-terminal.light .scan-ai-city-card p),
html.light .root :global(.scan-terminal.light .scan-ai-city-card li),
html.light .root :global(.scan-terminal.light .scan-ai-city-card small),
html.light .root :global(.scan-terminal.light .scan-ai-city-card span:not(.scan-ai-city-kicker)) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-card p),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-card li),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-card small),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-card span:not(.scan-ai-city-kicker)) {
color: var(--text-secondary);
}
html.light .root :global(.scan-terminal.light .scan-ai-city-status-tag.green) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-status-tag.green) {
color: #047857;
}
html.light .root :global(.scan-terminal.light .scan-ai-city-status-tag.blue) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-status-tag.blue) {
color: #1d4ed8;
}
html.light .root :global(.scan-terminal.light .scan-ai-city-status-tag.amber) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-status-tag.amber) {
color: #b45309;
}
html.light .root :global(.scan-terminal.light .scan-ai-city-status-tag.red) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-status-tag.red) {
color: #b91c1c;
}
/* ── Upgrade announcement light overrides ── */
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement) {
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement) {
background:
radial-gradient(circle at top left, rgba(37, 99, 235, 0.12), transparent 36%),
var(--bg-card);
@@ -1350,188 +1397,188 @@ html.light .root :global(.scan-terminal.light .scan-upgrade-announcement) {
box-shadow: 0 16px 36px rgba(61, 100, 145, 0.12);
}
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement-copy strong),
html.light .root :global(.scan-terminal.light .scan-ai-city-mobile-priority b),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-metrics b),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-reason),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-head h3),
html.light .root :global(.scan-terminal.light .scan-ai-market-mobile-line b) {
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement-copy strong),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-mobile-priority b),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-metrics b),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-reason),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-head h3),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-market-mobile-line b) {
color: var(--text-primary);
}
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement-copy p),
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement li),
html.light .root :global(.scan-terminal.light .scan-ai-city-mobile-priority small),
html.light .root :global(.scan-terminal.light .scan-mobile-decision-metrics small),
html.light .root :global(.scan-terminal.light .scan-ai-market-mobile-line span) {
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement-copy p),
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement li),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-mobile-priority small),
:global(html.light) .root :global(.scan-terminal.light .scan-mobile-decision-metrics small),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-market-mobile-line span) {
color: var(--text-secondary);
}
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement-copy span) {
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement-copy span) {
color: #047857;
}
html.light .root :global(.scan-terminal.light .scan-upgrade-announcement li),
html.light .root :global(.scan-terminal.light .scan-ai-city-mobile-priority span),
html.light .root :global(.scan-terminal.light .scan-ai-decision-why),
html.light .root :global(.scan-terminal.light .scan-ai-market-mobile-line) {
:global(html.light) .root :global(.scan-terminal.light .scan-upgrade-announcement li),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-mobile-priority span),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-why),
:global(html.light) .root :global(.scan-terminal.light .scan-ai-market-mobile-line) {
background: #eef7ff;
border-color: rgba(37, 99, 235, 0.16);
}
html.light .root :global(.scan-terminal.light .scan-ai-decision-why) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-why) {
color: #1d4ed8;
}
/* ── Section titles ── */
html.light .root :global(.scan-terminal.light .scan-ai-city-section-title) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-section-title) {
color: #1d4ed8;
}
html.light .root :global(.scan-terminal.light .scan-ai-decision-band span) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-band span) {
color: #1d4ed8;
}
html.light .root :global(.scan-terminal.light .scan-ai-decision-band p) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-band p) {
color: var(--text-muted);
}
html.light .root :global(.scan-terminal.light .scan-ai-decision-band strong) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-decision-band strong) {
color: var(--text-primary);
}
/* ── Scrollbar light overrides ── */
html.light .root :global(.scan-terminal.light .scan-ai-city-body) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-city-body) {
scrollbar-color: rgba(37, 99, 235, 0.18) transparent;
}
html.light .root :global(.scan-ai-city-body::-webkit-scrollbar-thumb) {
:global(html.light) .root :global(.scan-ai-city-body::-webkit-scrollbar-thumb) {
background: rgba(37, 99, 235, 0.22);
}
/* ── AI prediction dual-card light mode ── */
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card) {
background: var(--bg-card);
border-color: var(--border-glass);
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card.ai) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card.ai) {
background: linear-gradient(180deg, rgba(219, 234, 254, 0.52), var(--bg-card));
border-color: rgba(14, 165, 233, 0.28);
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card.deb) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card.deb) {
background: var(--bg-card);
border-color: var(--border-glass);
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card small) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card small) {
color: #64748b;
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card strong) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card strong) {
color: var(--text-primary);
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card.ai strong) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card.ai strong) {
color: #0369a1;
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card em) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card em) {
color: #64748b;
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card.ai.pending) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card.ai.pending) {
background: rgba(219, 234, 254, 0.28);
border-color: rgba(14, 165, 233, 0.16);
}
html.light .root :global(.scan-terminal.light .scan-ai-prediction-card.ai.pending strong) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-prediction-card.ai.pending strong) {
color: #94a3b8;
}
html.light .root :global(.scan-terminal.light .scan-ai-confidence) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-confidence) {
background: rgba(59, 130, 246, 0.1);
color: #2563eb;
}
html.light .root :global(.scan-terminal.light .scan-ai-confidence.high) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-confidence.high) {
background: rgba(16, 185, 129, 0.12);
color: #047857;
}
html.light .root :global(.scan-terminal.light .scan-ai-confidence.medium) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-confidence.medium) {
background: rgba(245, 158, 11, 0.12);
color: #b45309;
}
html.light .root :global(.scan-terminal.light .scan-ai-confidence.low) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-confidence.low) {
background: rgba(148, 163, 184, 0.12);
color: #64748b;
}
html.light .root :global(.scan-terminal.light .scan-ai-confidence.neutral) {
:global(html.light) .root :global(.scan-terminal.light .scan-ai-confidence.neutral) {
background: rgba(148, 163, 184, 0.08);
color: #64748b;
}
/* ── Empty / Error / Retry light overrides ── */
html.light .root :global(.scan-terminal.light .scan-empty-title),
html.light .root :global(.scan-terminal.light .scan-error-title) {
:global(html.light) .root :global(.scan-terminal.light .scan-empty-title),
:global(html.light) .root :global(.scan-terminal.light .scan-error-title) {
color: var(--text-primary);
}
html.light .root :global(.scan-terminal.light .scan-empty-copy),
html.light .root :global(.scan-terminal.light .scan-error-copy) {
:global(html.light) .root :global(.scan-terminal.light .scan-empty-copy),
:global(html.light) .root :global(.scan-terminal.light .scan-error-copy) {
color: var(--text-muted);
}
html.light .root :global(.scan-terminal.light .scan-empty-icon) {
:global(html.light) .root :global(.scan-terminal.light .scan-empty-icon) {
background: rgba(37, 99, 235, 0.08);
border-color: rgba(37, 99, 235, 0.2);
color: #2563EB;
}
html.light .root :global(.scan-terminal.light .scan-error-icon) {
:global(html.light) .root :global(.scan-terminal.light .scan-error-icon) {
background: rgba(239, 68, 68, 0.06);
border-color: rgba(239, 68, 68, 0.18);
color: #DC2626;
}
html.light .root :global(.scan-terminal.light .scan-retry-button) {
:global(html.light) .root :global(.scan-terminal.light .scan-retry-button) {
background: rgba(37, 99, 235, 0.08);
border-color: rgba(37, 99, 235, 0.24);
color: #2563EB;
}
html.light .root :global(.scan-terminal.light .scan-retry-button:hover) {
:global(html.light) .root :global(.scan-terminal.light .scan-retry-button:hover) {
background: rgba(37, 99, 235, 0.14);
}
/* ── AMOS runway panel light overrides ── */
html.light .root :global(.scan-terminal.light .scan-amos-runway-panel) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-runway-panel) {
background: rgba(37, 99, 235, 0.03);
border-color: rgba(37, 99, 235, 0.12);
}
html.light .root :global(.scan-terminal.light .scan-amos-runway-card) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-runway-card) {
background: var(--bg-card);
border-color: rgba(37, 99, 235, 0.08);
}
html.light .root :global(.scan-terminal.light .scan-amos-runway-label) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-runway-label) {
color: #2563EB;
}
html.light .root :global(.scan-terminal.light .scan-amos-runway-temp) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-runway-temp) {
color: var(--text-primary);
}
html.light .root :global(.scan-terminal.light .scan-amos-source-tag) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-source-tag) {
background: rgba(37, 99, 235, 0.08);
color: #2563EB;
}
html.light .root :global(.scan-terminal.light .scan-amos-runway-detail) {
:global(html.light) .root :global(.scan-terminal.light .scan-amos-runway-detail) {
color: #64748B;
}
@@ -1337,3 +1337,60 @@
}
@keyframes spin { to { transform: rotate(360deg); } }
/* ── AI prediction dual-card light mode ── */
:global(html.light) .root :global(.scan-ai-prediction-card) {
background: var(--color-bg-raised);
border-color: var(--color-border-default);
}
:global(html.light) .root :global(.scan-ai-prediction-card.ai) {
background: linear-gradient(180deg, rgba(37, 99, 235, 0.08), var(--color-bg-raised));
border-color: rgba(37, 99, 235, 0.22);
}
:global(html.light) .root :global(.scan-ai-prediction-card.deb) {
background: var(--color-bg-raised);
border-color: var(--color-border-default);
}
:global(html.light) .root :global(.scan-ai-prediction-card small) {
color: var(--color-text-muted);
}
:global(html.light) .root :global(.scan-ai-prediction-card strong) {
color: var(--color-text-primary);
}
:global(html.light) .root :global(.scan-ai-prediction-card.ai strong) {
color: var(--color-accent-primary);
}
:global(html.light) .root :global(.scan-ai-prediction-card em) {
color: var(--color-text-muted);
}
:global(html.light) .root :global(.scan-ai-prediction-card.ai.pending) {
background: rgba(37, 99, 235, 0.04);
border-color: rgba(37, 99, 235, 0.12);
}
:global(html.light) .root :global(.scan-ai-prediction-card.ai.pending strong) {
color: var(--color-text-disabled);
}
:global(html.light) .root :global(.scan-ai-confidence) {
background: rgba(37, 99, 235, 0.1);
color: var(--color-accent-primary);
}
:global(html.light) .root :global(.scan-ai-confidence.high) {
background: rgba(16, 185, 129, 0.12);
color: #047857;
}
:global(html.light) .root :global(.scan-ai-confidence.medium) {
background: rgba(245, 158, 11, 0.12);
color: #b45309;
}
@@ -117,6 +117,15 @@ function ScanTerminalScreen() {
}
}, [terminalData?.generated_at]);
useEffect(() => {
if (activeView === "map") {
const timer = setTimeout(() => {
window.dispatchEvent(new Event("resize"));
}, 150);
return () => clearTimeout(timer);
}
}, [activeView]);
const scanTerminalRootClassName = clsx(
styles.root,
scanRootClass,
@@ -520,3 +520,23 @@
@keyframes spin { to { transform: rotate(360deg); } }
/* ── City Jumpbar Light Mode Overrides ── */
:global(html.light) .root :global(.scan-ai-city-jumpbar) {
background: #ffffff;
border-color: #d8e0ec;
box-shadow: var(--shadow-elevation-1);
}
:global(html.light) .root :global(.scan-ai-city-jumpbar button) {
background: var(--color-bg-input);
border-color: var(--color-border-default);
color: var(--color-text-secondary);
}
:global(html.light) .root :global(.scan-ai-city-jumpbar button:hover) {
background: #e2e8f0;
border-color: var(--color-border-hover);
color: var(--color-text-primary);
}
@@ -624,10 +624,6 @@
height: 38px;
}
.root :global(.scan-theme-button) {
width: 38px;
height: 38px;
}
}
/* ── Mobile City Picker ── */
@@ -16,7 +16,7 @@
justify-content: space-between;
gap: 12px;
padding: 6px 0 18px;
border-bottom: 1px solid rgba(118, 146, 188, 0.1);
border-bottom: 1px solid var(--color-border-default);
}
.root :global(.scan-topbar-title) {
@@ -30,12 +30,12 @@
margin: 0;
font-size: 28px;
line-height: 1.08;
letter-spacing: -0.04em;
color: #f3f8ff;
letter-spacing: 0;
color: var(--color-text-primary);
}
.root :global(.scan-topbar-title span) {
color: #8fa4c3;
color: var(--color-text-secondary);
font-size: 14px;
line-height: 1.5;
}
@@ -46,17 +46,17 @@
flex-wrap: wrap;
justify-content: flex-end;
gap: 12px;
color: #b4c8e2;
color: var(--color-text-secondary);
font-size: 14px;
}
.root :global(.scan-locale-switch) {
height: 36px;
padding: 3px;
border-radius: 12px;
border: 1px solid rgba(99, 132, 180, 0.18);
background: rgba(8, 19, 34, 0.9);
color: #a8bdd8;
border-radius: 10px;
border: 1px solid var(--color-border-default);
background: #e2e8f0;
color: var(--color-text-secondary);
display: inline-flex;
align-items: center;
gap: 2px;
@@ -69,20 +69,20 @@
min-width: 34px;
height: 28px;
padding: 0 8px;
border-radius: 8px;
border-radius: 7px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.root :global(.scan-locale-switch span.active) {
color: #eef7ff;
background: rgba(63, 140, 255, 0.16);
box-shadow: inset 0 0 0 1px rgba(63, 140, 255, 0.22);
color: var(--color-text-primary);
background: #ffffff;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
}
.root :global(.scan-topbar-time) {
color: #b4c8e2;
color: var(--color-text-secondary);
font-variant-numeric: tabular-nums;
}
@@ -92,12 +92,11 @@
gap: 16px;
align-items: center;
margin: -4px 0 6px;
border: 1px solid rgba(77, 163, 255, 0.2);
border-radius: 18px;
border: 1px solid #bfdbfe;
border-radius: 12px;
background:
radial-gradient(circle at top left, rgba(77, 163, 255, 0.18), transparent 36%),
linear-gradient(135deg, rgba(18, 33, 58, 0.96), rgba(15, 23, 42, 0.92));
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.2);
linear-gradient(90deg, rgba(239, 246, 255, 0.98), rgba(255, 255, 255, 0.98));
box-shadow: 0 10px 28px rgba(15, 23, 42, 0.08);
padding: 16px 18px;
}
@@ -106,7 +105,7 @@
}
.root :global(.scan-upgrade-announcement-copy span) {
color: #86efac;
color: #047857;
font-size: 12px;
font-weight: 900;
letter-spacing: 0.04em;
@@ -116,14 +115,14 @@
.root :global(.scan-upgrade-announcement-copy strong) {
display: block;
margin-top: 5px;
color: #f3f8ff;
color: var(--color-text-primary);
font-size: 18px;
line-height: 1.25;
}
.root :global(.scan-upgrade-announcement-copy p) {
margin: 6px 0 0;
color: #b4c8e2;
color: var(--color-text-secondary);
font-size: 13px;
line-height: 1.55;
}
@@ -139,10 +138,10 @@
}
.root :global(.scan-upgrade-announcement li) {
border: 1px solid rgba(77, 163, 255, 0.22);
border: 1px solid #bfdbfe;
border-radius: 999px;
background: rgba(77, 163, 255, 0.1);
color: #d7e5f7;
background: #eff6ff;
color: #1d4ed8;
font-size: 12px;
font-weight: 800;
padding: 7px 10px;
@@ -158,16 +157,16 @@
place-items: center;
border: none;
border-radius: 8px;
background: rgba(148, 163, 184, 0.1);
color: #94a3b8;
background: #f1f5f9;
color: #64748b;
font-size: 14px;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.root :global(.scan-announcement-dismiss:hover) {
background: rgba(148, 163, 184, 0.22);
color: #e2e8f0;
background: #e2e8f0;
color: #0f172a;
}
.root :global(.scan-upgrade-announcement) {
@@ -176,14 +175,13 @@
.root :global(.scan-ghost-button),
.root :global(.scan-cta-ghost),
.root :global(.scan-theme-button),
.root :global(.scan-detail-action-button),
.root :global(.scan-detail-icon-button),
.root :global(.scan-view-all-button) {
border: 1px solid rgba(99, 132, 180, 0.18);
background: rgba(8, 19, 34, 0.9);
color: #d7e5f7;
border-radius: 12px;
border: 1px solid var(--color-border-default);
background: var(--color-bg-raised);
color: var(--color-text-primary);
border-radius: 10px;
}
.root :global(.scan-ghost-button),
@@ -202,13 +200,13 @@
min-height: 42px;
padding: 11px 16px;
border: 1px solid rgba(77, 163, 255, 0.42);
border-radius: 12px;
border-radius: 10px;
background: linear-gradient(180deg, var(--color-accent-primary), #3B82F6);
color: #FFFFFF;
font-size: 14px;
font-weight: 900;
text-decoration: none;
box-shadow: 0 10px 24px rgba(59, 130, 246, 0.22);
box-shadow: 0 8px 18px rgba(37, 99, 235, 0.18);
cursor: pointer;
}
@@ -227,18 +225,18 @@
gap: 8px;
min-height: 42px;
padding: 11px 14px;
border: 1px solid rgba(77, 163, 255, 0.3);
border-radius: 12px;
background: linear-gradient(180deg, rgba(77, 163, 255, 0.18), rgba(59, 130, 246, 0.12));
color: #CFE6FF;
border: 1px solid #bfdbfe;
border-radius: 10px;
background: #eff6ff;
color: #1d4ed8;
font-size: 13px;
font-weight: 900;
cursor: pointer;
}
.root :global(.scan-ai-button:hover:not(:disabled)) {
border-color: rgba(111, 183, 255, 0.5);
background: linear-gradient(180deg, rgba(77, 163, 255, 0.26), rgba(59, 130, 246, 0.18));
border-color: #93c5fd;
background: #dbeafe;
}
.root :global(.scan-ai-button:disabled) {
@@ -247,9 +245,9 @@
}
.root :global(.scan-cta-ghost) {
color: var(--color-accent-secondary);
border-color: rgba(23, 217, 139, 0.3);
background: rgba(23, 217, 139, 0.12);
color: #047857;
border-color: #a7f3d0;
background: #ecfdf5;
}
.root :global(.scan-account-button) {
@@ -258,26 +256,19 @@
display: inline-flex;
align-items: center;
justify-content: center;
color: #d7e5f7;
color: var(--color-text-primary);
text-decoration: none;
border: 1px solid rgba(99, 132, 180, 0.18);
background: rgba(8, 19, 34, 0.9);
border-radius: 12px;
border: 1px solid var(--color-border-default);
background: var(--color-bg-raised);
border-radius: 10px;
}
.root :global(.scan-account-button:hover) {
border-color: rgba(63, 140, 255, 0.28);
background: rgba(12, 26, 44, 0.96);
border-color: #94a3b8;
background: #f8fafc;
}
.root :global(.scan-theme-button) {
width: 36px;
height: 36px;
display: inline-grid;
place-items: center;
color: #d7e5f7;
cursor: pointer;
}
.root :global(.scan-ghost-button .spin) {
animation: spin 1s linear infinite;