style(assets): compact history trends and overview spacing
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-10-24 13:29:13 +08:00
parent d8871964a4
commit a237df8b75
4 changed files with 74 additions and 79 deletions
@@ -8,6 +8,7 @@ import type { OverviewViewProps } from './overview/types';
export function OverviewView(props: OverviewViewProps) { export function OverviewView(props: OverviewViewProps) {
return ( return (
<> <>
<div className="flex flex-col gap-2">
<SummaryMetrics <SummaryMetrics
summary={props.summary} summary={props.summary}
operatingRate={props.operatingRate} operatingRate={props.operatingRate}
@@ -17,6 +18,7 @@ export function OverviewView(props: OverviewViewProps) {
/> />
<AssetHistorySection subject={props.selectedSubject} onSubjects={props.onHistorySubjects} /> <AssetHistorySection subject={props.selectedSubject} onSubjects={props.onHistorySubjects} />
</div>
<FlowStatisticsCard <FlowStatisticsCard
flowRange={props.flowRange} flowRange={props.flowRange}
@@ -10,7 +10,7 @@ export function SummaryMetrics({
return ( return (
<> <>
{/* Header Summary - Ultra Compact */} {/* Header Summary - Ultra Compact */}
<div className="grid grid-cols-2 md:grid-cols-3 gap-2 mb-2"> <div className="grid grid-cols-2 md:grid-cols-3 gap-2">
{/* Total Assets */} {/* Total Assets */}
<div className="rounded-2xl border border-slate-100 bg-white p-3 shadow-sm flex items-center gap-2 cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md" <div className="rounded-2xl border border-slate-100 bg-white p-3 shadow-sm flex items-center gap-2 cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md"
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', source: 'asset', title: '资产概览' })}> onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', source: 'asset', title: '资产概览' })}>
@@ -66,7 +66,7 @@ export function SummaryMetrics({
</div> </div>
<div data-testid="asset-operation-ratio-strip" className="mb-3 rounded-2xl border border-slate-100 bg-white/85 px-3 py-2 shadow-sm"> <div data-testid="asset-operation-ratio-strip" className="rounded-xl border border-slate-100 bg-white/85 px-3 py-1 shadow-sm">
<div className="flex items-center justify-between gap-3"> <div className="flex items-center justify-between gap-3">
<div className="shrink-0 text-[11px] font-black text-slate-400">运营概览</div> <div className="shrink-0 text-[11px] font-black text-slate-400">运营概览</div>
<div className="grid min-w-0 flex-1 grid-cols-2 divide-x divide-slate-100 text-center"> <div className="grid min-w-0 flex-1 grid-cols-2 divide-x divide-slate-100 text-center">
@@ -69,18 +69,17 @@ export function AssetHistorySection({ subject, onSubjects }: { subject: string |
<div className="asset-history-toolbar"> <div className="asset-history-toolbar">
{mode === 'monthly' && <HistorySelect label="历史年份" value={String(year)} options={(data?.years || [year]).map(y => ({ value: String(y), label: `${y}年` }))} onChange={value => { setYear(Number(value)); setDetails(null); }} />} {mode === 'monthly' && <HistorySelect label="历史年份" value={String(year)} options={(data?.years || [year]).map(y => ({ value: String(y), label: `${y}年` }))} onChange={value => { setYear(Number(value)); setDetails(null); }} />}
{data && <HistorySelect label="统计期间" value={selected || ''} onChange={value => { setSelected(value); setDetails(null); }} options={data.points.map(p => ({ value: p.period, label: p.label, detail: p.state === 'RECONSTRUCTED' ? '估算' : p.state === 'LIVE' ? '实时' : p.state === 'ARCHIVED' ? '归档' : p.state === 'FUTURE' ? '未来' : p.state === 'MISSING' ? '缺失' : HISTORY_STATE_LABELS[p.state] }))} />} {data && <HistorySelect label="统计期间" value={selected || ''} onChange={value => { setSelected(value); setDetails(null); }} options={data.points.map(p => ({ value: p.period, label: p.label, detail: p.state === 'RECONSTRUCTED' ? '估算' : p.state === 'LIVE' ? '实时' : p.state === 'ARCHIVED' ? '归档' : p.state === 'FUTURE' ? '未来' : p.state === 'MISSING' ? '缺失' : HISTORY_STATE_LABELS[p.state] }))} />}
<span title="每月最后一天北京时间17:00采集;年度复用12月快照">月末 17:00</span> <span className="asset-history-cutoff" title="每月最后一天北京时间17:00采集;年度复用12月快照">月末 17:00</span>
<button type="button" className="asset-history-refresh" aria-label="刷新资产历史趋势" disabled={loading} onClick={() => setRetry(x => x + 1)}><RefreshCw size={15} /></button> <button type="button" className="asset-history-refresh" aria-label="刷新资产历史趋势" disabled={loading} onClick={() => setRetry(x => x + 1)}><RefreshCw size={15} /></button>
</div> </div>
</div> </div>
{loading && !data ? <p className="asset-history-empty" role="status">正在加载资产历史趋势…</p> : !data ? <p className="asset-history-empty" role="alert">{error || '暂无可用数据'} <button type="button" onClick={() => setRetry(x => x + 1)}>重试</button></p> : <> {loading && !data ? <p className="asset-history-empty" role="status">正在加载资产历史趋势…</p> : !data ? <p className="asset-history-empty" role="alert">{error || '暂无可用数据'} <button type="button" onClick={() => setRetry(x => x + 1)}>重试</button></p> : <>
{error && <p className="asset-history-warning" role="alert">{error} · 保留上次查询结果 <button type="button" onClick={() => setRetry(x => x + 1)}>重试</button></p>} {error && <p className="asset-history-warning" role="alert">{error} · 保留上次查询结果 <button type="button" onClick={() => setRetry(x => x + 1)}>重试</button></p>}
<p className="asset-history-unit">数量(台)</p>
<div className="asset-history-chart" role="img" aria-label="运营数与库存数堆叠柱,资产总数折线;精确数值和缺失状态可通过上方统计期间选择框查看"> <div className="asset-history-chart" role="img" aria-label="运营数与库存数堆叠柱,资产总数折线;精确数值和缺失状态可通过上方统计期间选择框查看">
<ResponsiveContainer width="100%" height="100%" minWidth={0} initialDimension={{ width: 480, height: 200 }}> <ResponsiveContainer width="100%" height="100%" minWidth={0} initialDimension={{ width: 480, height: 200 }}>
<ComposedChart data={chart} margin={{ top: 10, right: 14, bottom: 0, left: 0 }} onClick={state => { const p = chart.find(p => p.label === String(state?.activeLabel)); if (p) setSelected(p.period); }}> <ComposedChart data={chart} margin={{ top: 18, right: 10, bottom: 0, left: 0 }} onClick={state => { const p = chart.find(p => p.label === String(state?.activeLabel)); if (p) setSelected(p.period); }}>
<CartesianGrid stroke="#e9eff7" vertical={false} /><XAxis dataKey="label" tick={{ fontSize: 10, fill: '#64748b' }} axisLine={{ stroke: '#dbe4ef' }} tickLine={false} interval={mode === 'monthly' ? 0 : 'preserveStartEnd'} minTickGap={4} /> <CartesianGrid stroke="#e9eff7" vertical={false} /><XAxis dataKey="label" tick={{ fontSize: 10, fill: '#64748b' }} axisLine={{ stroke: '#dbe4ef' }} tickLine={false} interval={mode === 'monthly' ? 0 : 'preserveStartEnd'} minTickGap={4} />
<YAxis allowDecimals={false} width={44} tick={{ fontSize: 11, fill: '#64748b' }} axisLine={false} tickLine={false} /> <YAxis allowDecimals={false} tickCount={4} width={36} tick={{ fontSize: 11, fill: '#64748b' }} axisLine={false} tickLine={false} />
<Tooltip content={({ active, payload }) => { <Tooltip content={({ active, payload }) => {
const item = payload?.[0]?.payload as HistoryPoint | undefined; const item = payload?.[0]?.payload as HistoryPoint | undefined;
const values = item && displayHistoryCounts(item); const values = item && displayHistoryCounts(item);
@@ -92,16 +91,19 @@ export function AssetHistorySection({ subject, onSubjects }: { subject: string |
</ComposedChart> </ComposedChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>
<div className="asset-history-legend" aria-hidden="true"><span><i className="operating" />运营数</span><span><i className="inventory" />库存数</span><span><i className="total" />资产总数</span></div> <div className="asset-history-legend" aria-hidden="true"><span><i className="operating" />运营数</span><span><i className="inventory" />库存数</span><span><i className="total" />资产总数</span><span className="asset-history-unit">台</span></div>
{point && <div className="asset-history-selected" aria-live="polite"> {point && <div className="asset-history-selected" aria-live="polite">
<div className="asset-history-selected-heading"><strong>{mode === 'annual' || point.state === 'LIVE' ? point.label : `${point.label}末`}</strong><span>{HISTORY_STATE_LABELS[point.state]}</span>{point.asOf && <time dateTime={point.asOf} aria-label={`截至 ${historyTime(point.asOf)}`}>{historyTime(point.asOf)}</time>}</div> <div className="asset-history-selected-heading"><strong>{mode === 'annual' || point.state === 'LIVE' ? point.label : `${point.label}末`}</strong><span>{HISTORY_STATE_LABELS[point.state]}</span></div>
<div className="asset-history-counts">{([['total', '总数'], ['inventory', '库存'], ['operating', '运营']] as const).map(([key, label]) => <div key={key}><span aria-label={`${label}(台)`}>{label}(台)</span><strong>{displayHistoryCounts(point)?.[key]?.toLocaleString() ?? (point.reconstruction && key === 'total' ? '待核实' : '—')}</strong></div>)}</div> <div className="asset-history-counts">{([['total', '总数'], ['inventory', '库存'], ['operating', '运营']] as const).map(([key, label]) => <div key={key}><span aria-label={`${label}(台)`}>{label}</span><strong>{displayHistoryCounts(point)?.[key]?.toLocaleString() ?? (point.reconstruction && key === 'total' ? '待核实' : '—')}</strong></div>)}</div>
{hasComparison ? <div className="asset-history-comparison"><span>{point.comparisonLabel}</span><div>{(['total', 'inventory', 'operating'] as const).map(key => { {hasComparison ? <div className="asset-history-comparison"><span>{point.comparisonLabel}</span><div>{(['total', 'inventory', 'operating'] as const).map(key => {
const difference = displayHistoryDifference(point, key); const difference = displayHistoryDifference(point, key);
return <span key={key} className={difference != null && difference > 0 ? 'asset-history-increase' : difference != null && difference < 0 ? 'asset-history-decrease' : ''}>{difference != null ? signedCount(difference) : '—'}</span>; return <span key={key} className={difference != null && difference > 0 ? 'asset-history-increase' : difference != null && difference < 0 ? 'asset-history-decrease' : ''}>{difference != null ? signedCount(difference) : '—'}</span>;
})}</div></div> : <p>{point.comparisonLabel}</p>} })}</div></div> : null}
<div className="asset-history-selected-footer">
<div className="asset-history-point-meta">{point.asOf && <time dateTime={point.asOf} aria-label={`截至 ${historyTime(point.asOf)}`}>{historyTime(point.asOf)}</time>}{!hasComparison && <span>{point.comparisonLabel}</span>}</div>
{mode === 'monthly' && <button type="button" className="asset-history-detail-button" disabled={!point.detailAvailable} onClick={() => setDetails(point)}><span>{point.reconstruction ? '查看月度回溯明细' : '查看月度明细'}</span><ChevronRight size={16} aria-hidden="true" /></button>}
</div>
</div>} </div>}
{point && mode === 'monthly' && <button type="button" className="asset-history-detail-button" disabled={!point.detailAvailable} onClick={() => setDetails(point)}><span>{point.reconstruction ? '查看月度回溯明细' : '查看月度明细'}</span><ChevronRight size={18} /></button>}
<p className="asset-history-footnote">历史库存状态快照缺失,核对中,暂不展示。</p> <p className="asset-history-footnote">历史库存状态快照缺失,核对中,暂不展示。</p>
</>} </>}
{details && <HistoryDetailsDialog point={details} subject={subject} close={closeDetails} />} {details && <HistoryDetailsDialog point={details} subject={subject} close={closeDetails} />}
+51 -60
View File
@@ -1,41 +1,43 @@
.asset-history { --history-blue:#1559e8; margin:8px 0 16px; padding:16px; border:1px solid #e6edf5; border-radius:20px; background:#fff; color:#142b4e; box-shadow:0 5px 24px rgb(22 53 90 / 3%); } .asset-history { --history-blue:#1559e8; --history-ink:#142b4e; --history-muted:#62748b; --history-border:#e3ebf5; margin:0; padding:16px; border:1px solid var(--history-border); border-radius:16px; background:#fff; color:var(--history-ink); box-shadow:0 2px 12px rgb(22 53 90 / 3%); }
.asset-history button,.asset-history-dialog button { cursor:pointer; } .asset-history button,.asset-history-dialog button { cursor:pointer; touch-action:manipulation; }
.asset-history button:disabled,.asset-history-dialog button:disabled { cursor:default; opacity:.45; } .asset-history button:disabled,.asset-history-dialog button:disabled { cursor:default; opacity:.45; }
.asset-history button:focus-visible,.asset-history select:focus-visible,.asset-history-dialog :is(button,input,select):focus-visible { outline:2px solid #2563eb; outline-offset:3px; } .asset-history button:focus-visible,.asset-history-dialog :is(button,input,select):focus-visible { outline:2px solid #2563eb; outline-offset:3px; }
.asset-history-header { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px; } .asset-history-header { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px; }
.asset-history-header h2 { margin:0; font-size:20px; font-weight:750; letter-spacing:-.5px; } .asset-history-header h2 { margin:0; font-size:18px; font-weight:700; letter-spacing:-.4px; }
.asset-history-modes { display:flex; gap:2px; background:#eef3fa; border:1px solid #e7edf6; border-radius:11px; padding:3px; } .asset-history-modes { display:flex; gap:2px; background:#f0f4f9; border-radius:10px; padding:0 3px; }
.asset-history-modes button { padding:7px 20px; min-height:34px; border-radius:8px; font-size:13px; font-weight:600; transition:background .15s,color .15s,box-shadow .15s; color:#64748b; } .asset-history-modes button { position:relative; isolation:isolate; min-width:52px; min-height:44px; padding:8px 14px; font-size:13px; font-weight:600; color:var(--history-muted); transition:color .16s; }
.asset-history-modes button[aria-pressed=true] { background:#fff; color:#1559e8; box-shadow:0 1px 4px #193c6920, inset 0 0 0 1px #dce7f5; } .asset-history-modes button::before { content:""; position:absolute; inset:5px 0; z-index:-1; border-radius:7px; transition:background .16s,box-shadow .16s; }
.asset-history-toolbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:8px 0 4px; font-size:12px; color:#64748b; } .asset-history-modes button[aria-pressed=true] { color:var(--history-blue); }
.asset-history-modes button[aria-pressed=true]::before { background:#fff; box-shadow:0 1px 4px #193c691a,0 0 0 1px #e0e8f3; }
.asset-history-toolbar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:4px 0 0; color:var(--history-muted); font-size:12px; }
.asset-history-toolbar>span { margin-left:auto; } .asset-history-toolbar>span { margin-left:auto; }
.asset-history-toolbar .asset-history-annual-note { margin-left:0; margin-right:auto; } .asset-history-refresh { display:grid; place-items:center; min-width:44px; min-height:44px; padding:8px; border-radius:8px; color:var(--history-muted); transition:background .16s,color .16s; }
.asset-history-refresh { display:grid; place-items:center; padding:8px; border-radius:8px; color:#7c8da5; transition:background .15s,color .15s; }
.asset-history-warning { margin:8px 0; font-size:12px; line-height:1.7; color:#74613a; background:#fff9ec; padding:9px 12px; border-radius:9px; } .asset-history-warning { margin:8px 0; font-size:12px; line-height:1.7; color:#74613a; background:#fff9ec; padding:9px 12px; border-radius:9px; }
.asset-history-warning button,.asset-history-empty button { color:#1559e8; text-decoration:underline; padding:6px; } .asset-history-warning button,.asset-history-empty button { color:var(--history-blue); text-decoration:underline; padding:6px; }
.asset-history-unit { font-size:12px; color:#64748b; margin:6px 0 0; } .asset-history-chart { height:180px; width:100%; min-width:0; }
.asset-history-chart { height:200px; width:100%; min-width:0; } .asset-history-tooltip { background:#fff; border:1px solid var(--history-border); border-radius:10px; padding:10px 12px; box-shadow:0 4px 16px #142b4e15; font-size:12px; }
.asset-history-tooltip { background:#fff; border:1px solid #dce5ef; border-radius:10px; padding:10px 12px; box-shadow:0 4px 16px #142b4e15; font-size:12px; }
.asset-history-tooltip p { margin-top:4px; } .asset-history-tooltip p { margin-top:4px; }
.asset-history-legend { display:flex; justify-content:center; flex-wrap:wrap; gap:22px; color:#64748b; font-size:12px; margin:6px 0; } .asset-history-legend { display:flex; justify-content:center; align-items:center; flex-wrap:wrap; gap:16px; color:var(--history-muted); font-size:12px; line-height:18px; margin:2px 0 8px; }
.asset-history-legend span { display:flex; align-items:center; gap:7px; } .asset-history-legend span { display:flex; align-items:center; gap:6px; }
.asset-history-legend i { display:inline-block; height:11px; width:11px; border-radius:2px; } .asset-history-legend i { display:inline-block; height:8px; width:8px; border-radius:2px; }
.asset-history-legend .operating { background:#347df5; }.asset-history-legend .inventory { background:#9ed1fa; } .asset-history-legend .operating { background:#347df5; }.asset-history-legend .inventory { background:#9ed1fa; }
.asset-history-legend .total { width:20px; height:2px; background:#132e57; } .asset-history-legend .total { position:relative; width:16px; height:2px; background:#132e57; }
.asset-history-selected { margin-top:8px; display:grid; grid-template-columns:90px minmax(0,1fr); align-items:center; gap:0 10px; padding:10px 14px; background:linear-gradient(115deg,#f3f7fe,#edf5ff); border:1px solid #e7effb; border-radius:12px; } .asset-history-legend .total::after { content:""; position:absolute; top:-2px; left:6px; width:6px; height:6px; border:2px solid #132e57; border-radius:50%; background:white; }
.asset-history-legend .asset-history-unit { padding-left:8px; border-left:1px solid var(--history-border); }
.asset-history-selected { display:grid; grid-template-columns:94px minmax(0,1fr); align-items:center; gap:0 8px; padding:10px 12px 0; background:#f2f7ff; border:1px solid #e4edfa; border-radius:10px; }
.asset-history-selected-heading { display:flex; flex-direction:column; align-items:flex-start; gap:3px; min-width:0; } .asset-history-selected-heading { display:flex; flex-direction:column; align-items:flex-start; gap:3px; min-width:0; }
.asset-history-selected-heading>strong { color:#1559e8; font-size:17px; font-weight:750; } .asset-history-selected-heading>strong { color:var(--history-blue); font-size:18px; line-height:24px; font-weight:700; }
.asset-history-selected-heading>span,.asset-history-selected-heading>time { color:#64748b; font-size:11px; } .asset-history-selected-heading>span { color:var(--history-muted); font-size:12px; line-height:18px; }
.asset-history-counts { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); } .asset-history-counts { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); }
.asset-history-counts>div { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; min-width:0; border-right:1px solid #d4e2f4; } .asset-history-counts>div { display:flex; flex-direction:column; align-items:center; gap:3px; min-width:0; border-left:1px solid #dce7f6; }
.asset-history-counts>div:last-child { border:0; } .asset-history-counts>div>span { color:var(--history-muted); font-size:12px; line-height:18px; }
.asset-history-counts>div>span { color:#64748b; font-size:12px; } .asset-history-counts strong { font-size:24px; font-weight:700; line-height:28px; letter-spacing:-.4px; font-variant-numeric:tabular-nums; }
.asset-history-counts strong { font-size:23px; font-weight:750; line-height:1.2; font-variant-numeric:tabular-nums; }
.asset-history-increase { color:#bf2f30; }.asset-history-decrease { color:#14864a; } .asset-history-increase { color:#bf2f30; }.asset-history-decrease { color:#14864a; }
.asset-history-selected>p { grid-column:1 / -1; color:#64748b; font-size:11px; text-align:center; padding-top:6px; } .asset-history-selected-footer { grid-column:1/-1; display:flex; align-items:center; justify-content:space-between; gap:8px; margin-top:8px; border-top:1px solid #e0eaf8; min-height:44px; }
.asset-history-detail-button { display:flex; width:100%; align-items:center; justify-content:space-between; min-height:44px; padding:8px 12px; margin-top:8px; border:1px solid #dce8f8; border-radius:10px; background:#f7faff; color:#18385d; font-size:14px; font-weight:600; } .asset-history-point-meta { display:flex; flex-wrap:wrap; gap:2px 12px; color:var(--history-muted); font-size:12px; line-height:18px; }
.asset-history-footnote { display:flex; align-items:center; flex-wrap:wrap; gap:6px; color:#64748b; font-size:11px; margin-top:8px; } .asset-history-detail-button { display:flex; flex-shrink:0; align-items:center; justify-content:space-between; gap:4px; min-height:44px; padding:8px 0 8px 8px; color:var(--history-blue); font-size:12px; font-weight:600; border-radius:6px; transition:color .16s,background .16s; }
.asset-history-empty { padding:32px 12px; text-align:center; font-size:13px; color:#64748b; } .asset-history-footnote { color:var(--history-muted); font-size:12px; line-height:18px; margin-top:8px; }
.asset-history-empty { padding:32px 12px; text-align:center; font-size:13px; color:var(--history-muted); }
.asset-history-overlay { position:fixed; inset:0; z-index:120; background:#0c1e3b66; display:flex; justify-content:center; align-items:center; padding:24px; } .asset-history-overlay { position:fixed; inset:0; z-index:120; background:#0c1e3b66; display:flex; justify-content:center; align-items:center; padding:24px; }
.asset-history-dialog { display:flex; flex-direction:column; width:min(980px,100%); max-height:88dvh; border-radius:18px; background:white; color:#183454; box-shadow:0 24px 64px #142b4e30; overflow:hidden; outline:none; } .asset-history-dialog { display:flex; flex-direction:column; width:min(980px,100%); max-height:88dvh; border-radius:18px; background:white; color:#183454; box-shadow:0 24px 64px #142b4e30; overflow:hidden; outline:none; }
.asset-history-dialog>header { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; padding:20px 22px; border-bottom:1px solid #e6edf5; } .asset-history-dialog>header { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; padding:20px 22px; border-bottom:1px solid #e6edf5; }
@@ -58,12 +60,12 @@
.asset-history-dialog footer { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 22px; border-top:1px solid #e6edf5; color:#64748b; font-size:12px; } .asset-history-dialog footer { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 22px; border-top:1px solid #e6edf5; color:#64748b; font-size:12px; }
.asset-history-dialog footer>div { display:flex; gap:8px; }.asset-history-dialog footer button { padding:9px; border:1px solid #dce5f0; border-radius:7px; } .asset-history-dialog footer>div { display:flex; gap:8px; }.asset-history-dialog footer button { padding:9px; border:1px solid #dce5f0; border-radius:7px; }
@media(max-width:640px) { @media(max-width:640px) {
.asset-history { padding:12px; border-radius:16px; } .asset-history { padding:12px; border-radius:14px; }
.asset-history-header h2 { font-size:18px; }.asset-history-modes button { padding:7px 15px; min-height:38px; } .asset-history-header h2 { font-size:17px; }
.asset-history-toolbar { gap:6px; }.asset-history-toolbar>span { font-size:10px; } .asset-history-chart { height:140px; }
.asset-history-chart { height:170px; } .asset-history-selected { grid-template-columns:84px minmax(0,1fr); padding:8px 10px 0; gap:0 6px; }
.asset-history-selected { grid-template-columns:72px minmax(0,1fr); gap:0 6px; padding:8px 10px; }.asset-history-selected-heading { gap:2px; }.asset-history-selected-heading>span,.asset-history-selected-heading>time { font-size:10px; } .asset-history-counts strong { font-size:22px; line-height:26px; }
.asset-history-counts strong { font-size:21px; }.asset-history-counts>div>span { font-size:11px; } .asset-history-point-meta { flex-direction:column; gap:0; }
.asset-history-overlay { padding:10px; }.asset-history-dialog { max-height:94dvh; border-radius:14px; } .asset-history-overlay { padding:10px; }.asset-history-dialog { max-height:94dvh; border-radius:14px; }
.asset-history-dialog>header { padding:14px; }.asset-history-dialog h2 { font-size:16px; }.asset-history-detail-tools { padding:12px 14px; } .asset-history-dialog>header { padding:14px; }.asset-history-dialog h2 { font-size:16px; }.asset-history-detail-tools { padding:12px 14px; }
.asset-history-detail-note { padding:10px 14px; }.asset-history-dialog :is(input,select) { font-size:16px; }.asset-history-dialog footer { padding:12px 14px; } .asset-history-detail-note { padding:10px 14px; }.asset-history-dialog :is(input,select) { font-size:16px; }.asset-history-dialog footer { padding:12px 14px; }
@@ -79,31 +81,18 @@
} }
@media(min-width:900px) { @media(min-width:900px) {
.asset-history-controls { display:flex; align-items:center; flex-wrap:wrap; gap:8px 24px; } .asset-history-controls { display:flex; align-items:center; gap:24px; flex-wrap:wrap; }
.asset-history-header { flex:1; gap:16px; } .asset-history-header { flex:1; gap:16px; }
.asset-history-toolbar { margin:0; } .asset-history-toolbar { margin:0; }
.asset-history-selected { display:grid; grid-template-columns:minmax(150px,1fr) 3fr; align-items:center; gap:0 18px; } .asset-history-selected { grid-template-columns:minmax(150px,1fr) 3fr; gap:0 16px; }
.asset-history-selected-heading { display:grid; grid-template-columns:auto 1fr; align-items:center; gap:2px 12px; margin:0; } .asset-history-selected-heading { flex-direction:row; align-items:center; gap:12px; }
.asset-history-selected-heading>strong { grid-row:span 2; }
.asset-history-selected-heading>span,.asset-history-selected-heading>time { grid-column:2; }
.asset-history-selected>p { grid-column:1 / -1; }
} }
@media(max-width:640px) { .asset-history-comparison { grid-column:1/-1; display:grid; grid-template-columns:94px minmax(0,1fr); gap:8px; align-items:center; margin-top:8px; padding-top:6px; border-top:1px solid #dce7f6; font-size:12px; color:var(--history-muted); }
.asset-history-modes button,.asset-history-refresh { min-height:44px; }
.asset-history-refresh { min-width:44px; }
.asset-history-toolbar { gap:4px; }
}
.asset-history-comparison { grid-column:1 / -1; display:grid; grid-template-columns:90px minmax(0,1fr); gap:10px; align-items:center; margin-top:6px; padding-top:6px; border-top:1px solid #d4e2f4; font-size:11px; color:#64748b; }
.asset-history-comparison>div { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); text-align:center; font-size:13px; font-weight:600; } .asset-history-comparison>div { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); text-align:center; font-size:13px; font-weight:600; }
@media(min-width:900px) { @media(min-width:900px) { .asset-history-comparison { grid-template-columns:minmax(150px,1fr) 3fr; gap:16px; } }
.asset-history-comparison { grid-template-columns:minmax(150px,1fr) 3fr; gap:18px; } @media(max-width:640px) { .asset-history-comparison { grid-template-columns:84px minmax(0,1fr); gap:6px; } }
}
@media(max-width:640px) {
.asset-history-comparison { grid-template-columns:72px minmax(0,1fr); gap:6px; }
}
.asset-history-select { display:inline-flex; align-items:center; justify-content:space-between; gap:12px; min-width:76px; min-height:36px; padding:7px 11px; border:1px solid #dce5f1; border-radius:9px; background:#fff; color:#254365; font-size:13px; font-weight:550; box-shadow:0 1px 2px #173c6310; transition:border-color .15s,box-shadow .15s; } .asset-history-select { display:inline-flex; align-items:center; justify-content:space-between; gap:12px; min-width:76px; min-height:44px; padding:7px 11px; border:1px solid #dce5f1; border-radius:8px; background:#fff; color:#254365; font-size:13px; font-weight:550; box-shadow:0 1px 2px #173c6310; transition:border-color .15s,box-shadow .15s; }
.asset-history-select[data-state=open] { border-color:#8fb4f2; box-shadow:0 0 0 3px #dbeaff80; } .asset-history-select[data-state=open] { border-color:#8fb4f2; box-shadow:0 0 0 3px #dbeaff80; }
.asset-history-select-icon { color:#8b9db5; display:flex; transition:transform .15s; } .asset-history-select-icon { color:#8b9db5; display:flex; transition:transform .15s; }
.asset-history-select[data-state=open] .asset-history-select-icon { transform:rotate(180deg); } .asset-history-select[data-state=open] .asset-history-select-icon { transform:rotate(180deg); }
@@ -115,17 +104,19 @@
.asset-history-option-detail { margin-left:auto; color:#7b8da5; font-size:11px; font-weight:400; } .asset-history-option-detail { margin-left:auto; color:#7b8da5; font-size:11px; font-weight:400; }
.asset-history-option-check { position:absolute; right:9px; display:flex; color:#2563eb; } .asset-history-option-check { position:absolute; right:9px; display:flex; color:#2563eb; }
.asset-history-select-scroll { display:flex; align-items:center; justify-content:center; height:24px; color:#7b8da5; } .asset-history-select-scroll { display:flex; align-items:center; justify-content:center; height:24px; color:#7b8da5; }
.asset-history-detail-button>svg { padding:3px; width:24px; height:24px; border-radius:7px; background:#eaf2ff; color:#527eb7; } .asset-history-detail-button>svg { flex-shrink:0; }
@media(hover:hover) { @media(hover:hover) {
.asset-history-modes button:not([aria-pressed=true]):hover { color:#1559e8; background:#e5edf9; } .asset-history-modes button:not([aria-pressed=true]):hover::before { background:#e5edf9; }
.asset-history-select:hover { border-color:#adc5e8; } .asset-history-select:hover { border-color:#adc5e8; }
.asset-history-refresh:hover { color:#2563eb; background:#eef5ff; } .asset-history-refresh:hover { color:#2563eb; background:#eef5ff; }
.asset-history-detail-button:hover { background:#eef5ff; border-color:#bcd3f3; } .asset-history-detail-button:hover { color:#103eaa; background:#e9f1ff; }
} }
@media(max-width:640px) { @media(max-width:640px) {
.asset-history-select { min-height:44px; padding:8px 10px; font-size:12px; gap:10px; } .asset-history-select { min-height:44px; padding:8px 10px; font-size:12px; gap:10px; }
.asset-history-select-option { min-height:44px; } .asset-history-select-option { min-height:44px; }
} }
@media(prefers-reduced-motion:reduce) { @media(prefers-reduced-motion:reduce) {
.asset-history-modes button,.asset-history-select,.asset-history-select-icon,.asset-history-refresh { transition:none; } .asset-history-modes button,.asset-history-modes button::before,.asset-history-select,.asset-history-select-icon,.asset-history-refresh,.asset-history-detail-button { transition:none; }
} }
.asset-history :is(.asset-history-select,.asset-history-refresh,.asset-history-detail-button):active { background:#e6effe; }