/* ══════════════════════════════════════════════════════════════ MONITOR PANEL — Market Monitor board All colours reference design tokens so dark/light theme works. ══════════════════════════════════════════════════════════════ */ .root :global(.monitor-panel) { background: var(--color-bg-base); height: 100%; overflow: auto; padding: 20px 24px; color: var(--color-text-primary); } /* ── Header ── */ .root :global(.monitor-header) { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 24px; padding-bottom: 12px; border-bottom: 1px solid var(--color-border-subtle); flex-wrap: wrap; gap: 8px; } .root :global(.monitor-title) { font-size: 20px; font-weight: 600; color: var(--color-text-primary); } .root :global(.monitor-controls) { display: flex; align-items: center; gap: 12px; } .root :global(.monitor-loading-indicator) { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--color-text-muted); } .root :global(.monitor-load-progress) { margin-top: 3px; font-size: 12px; color: var(--color-text-muted); font-variant-numeric: tabular-nums; } .root :global(.monitor-syncing-badge) { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--color-accent-primary); background: rgba(77, 163, 255, 0.08); border: 1px solid rgba(77, 163, 255, 0.18); border-radius: 999px; padding: 2px 8px; font-variant-numeric: tabular-nums; } .root :global(.monitor-loading-dot) { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--color-accent-primary); animation: monitorPulse 1.2s ease-in-out infinite; flex-shrink: 0; } .root :global(.monitor-notify-btn) { background: none; border: 1px solid var(--color-border-default); border-radius: 6px; padding: 2px 8px; font-size: 16px; cursor: pointer; transition: var(--transition-fast); color: inherit; } .root :global(.monitor-notify-btn:hover) { border-color: var(--color-border-hover); background: var(--color-bg-raised); } .root :global(.monitor-notify-btn.muted) { opacity: 0.4; } .root :global(.monitor-time) { font-size: 13px; color: var(--color-text-muted); font-variant-numeric: tabular-nums; } /* ── Grid ── */ .root :global(.monitor-grid) { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; } /* ── Skeleton card ── */ .root :global(.monitor-skeleton-card) { background: var(--color-bg-raised); border: 1px solid var(--color-border-subtle); border-radius: 12px; padding: 20px 24px; min-height: 148px; animation: monitorShimmer 1.6s ease-in-out infinite; } .root :global(.monitor-skeleton-line) { background: var(--color-border-default); border-radius: 4px; margin-bottom: 8px; } /* ── City card ── */ .root :global(.monitor-card) { background: var(--color-bg-raised); border: 1px solid var(--color-border-default); border-radius: 12px; padding: 20px 24px; transition: border-color var(--transition-base); } .root :global(.monitor-card.new-high) { border-color: rgba(124, 58, 237, 0.3); } .root :global(.monitor-card.clickable) { cursor: pointer; } .root :global(.monitor-card.clickable:hover) { border-color: var(--color-accent, #7c3aed); transform: translateY(-2px); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18); } .root :global(.monitor-card.clickable:focus-visible) { outline: 2px solid var(--color-accent, #7c3aed); outline-offset: 2px; } /* ── Card header ── */ .root :global(.monitor-card-head) { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; font-size: 15px; flex-wrap: wrap; } .root :global(.monitor-city-name) { color: var(--color-text-primary); font-weight: 700; } .root :global(.monitor-airport-name) { color: var(--color-text-secondary); } .root :global(.monitor-obs-time) { margin-left: auto; color: var(--color-text-muted); font-size: 14px; font-variant-numeric: tabular-nums; } .root :global(.monitor-new-high-badge) { font-size: 12px; padding: 1px 6px; border-radius: 4px; background: rgba(124, 58, 237, 0.18); color: #a78bfa; font-weight: 600; } /* ── Temperature display ── */ .root :global(.monitor-temp-display) { margin: 8px 0 10px; line-height: 1.15; } .root :global(.monitor-temp-value) { font-size: 48px; font-weight: 700; letter-spacing: -0.03em; color: var(--color-text-primary); } .root :global(.monitor-temp-value.new-high) { color: #c084fc; } .root :global(.monitor-temp-value.warm) { color: var(--color-signal-warning); } .root :global(.monitor-temp-unit) { font-size: 20px; color: var(--color-text-muted); margin-left: 3px; } .root :global(.monitor-temp-missing) { font-size: 30px; color: var(--color-border-default); } /* ── Stats row ── */ .root :global(.monitor-stats) { font-size: 14px; } .root :global(.monitor-high-row) { display: flex; align-items: baseline; gap: 8px; } .root :global(.monitor-stat-label) { color: var(--color-text-muted); } .root :global(.monitor-high-value) { color: var(--color-text-secondary); } .root :global(.monitor-high-time) { font-size: 12px; color: var(--color-text-muted); margin-left: 2px; font-variant-numeric: tabular-nums; } .root :global(.monitor-stat-missing) { color: var(--color-border-default); } .root :global(.monitor-trend) { margin-left: auto; font-size: 18px; font-weight: 700; } .root :global(.monitor-trend.rising) { color: var(--color-signal-success); } .root :global(.monitor-trend.falling) { color: var(--color-accent-primary); } .root :global(.monitor-trend.flat) { color: var(--color-text-muted); } .root :global(.monitor-obs-row) { display: flex; gap: 8px; margin-top: 4px; } .root :global(.monitor-obs-age) { color: var(--color-text-muted); font-size: 13px; } /* ── Freshness legend ── */ .root :global(.monitor-legend) { display: flex; gap: 16px; margin-bottom: 16px; margin-top: -12px; } .root :global(.monitor-legend-item) { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--color-text-muted); } /* ── Freshness dot ── */ .root :global(.monitor-freshness-dot) { display: inline-block; flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; cursor: help; } .root :global(.monitor-freshness-dot.fresh) { background: var(--color-signal-success); box-shadow: 0 0 5px rgba(34, 197, 94, 0.5); } .root :global(.monitor-freshness-dot.aging) { background: var(--color-signal-warning); box-shadow: 0 0 5px rgba(245, 158, 11, 0.4); } .root :global(.monitor-freshness-dot.stale) { background: var(--color-signal-danger); box-shadow: 0 0 5px rgba(239, 68, 68, 0.4); } .root :global(.monitor-freshness-dot.unknown) { background: var(--color-text-muted); opacity: 0.5; } /* ── Obs-age with freshness colour ── */ .root :global(.monitor-obs-age) { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--color-text-muted); } .root :global(.monitor-obs-age.fresh) { color: var(--color-signal-success); } .root :global(.monitor-obs-age.aging) { color: var(--color-signal-warning); } .root :global(.monitor-obs-age.stale) { color: var(--color-signal-danger); } .root :global(.monitor-obs-age.unknown) { color: var(--color-text-muted); } /* ── Refresh progress bar (top edge of card while fetching) ── */ .root :global(.monitor-refresh-bar) { position: absolute; top: 0; left: 0; right: 0; height: 2px; border-radius: 12px 12px 0 0; background: linear-gradient( 90deg, transparent 0%, var(--color-accent-primary) 50%, transparent 100% ); background-size: 200% 100%; animation: monitorSweep 1.4s linear infinite; } /* ── Card refreshing state ── */ .root :global(.monitor-card.refreshing) { position: relative; overflow: hidden; } /* Slight dim on stale cards so fresh ones stand out */ .root :global(.monitor-card:not(.refreshing)) { position: relative; } /* ══════════════════════════════════════════════════════════════ LIGHT THEME OVERRIDES ══════════════════════════════════════════════════════════════ */ .root :global(.scan-terminal.light .monitor-panel) { background: #F7F9FC; color: #0F172A; } .root :global(.scan-terminal.light .monitor-header) { border-bottom-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-title) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-legend-item) { color: #64748B; } .root :global(.scan-terminal.light .monitor-time), .root :global(.scan-terminal.light .monitor-stat-label), .root :global(.scan-terminal.light .monitor-obs-time), .root :global(.scan-terminal.light .monitor-rw-label), .root :global(.scan-terminal.light .monitor-high-time), .root :global(.scan-terminal.light .monitor-load-progress) { color: #475569; } .root :global(.scan-terminal.light .monitor-card) { background: #FFFFFF; border-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-card.new-high) { border-color: rgba(124, 58, 237, 0.24); } .root :global(.scan-terminal.light .monitor-skeleton-card) { background: #FFFFFF; border-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-skeleton-line) { background: #E2E8F0; } .root :global(.scan-terminal.light .monitor-city-name) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-airport-name), .root :global(.scan-terminal.light .monitor-high-value), .root :global(.scan-terminal.light .monitor-rw-temp) { color: #334155; } .root :global(.scan-terminal.light .monitor-temp-value) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-temp-unit), .root :global(.scan-terminal.light .monitor-temp-missing), .root :global(.scan-terminal.light .monitor-stat-missing) { color: #94A3B8; } .root :global(.scan-terminal.light .monitor-divider) { background: #E2E8F0; } .root :global(.scan-terminal.light .monitor-notify-btn) { border-color: rgba(148, 163, 184, 0.3); color: #334155; } .root :global(.scan-terminal.light .monitor-notify-btn:hover) { border-color: rgba(37, 99, 235, 0.38); background: #EEF2F7; } .root :global(.scan-terminal.light .monitor-trend.rising) { color: #16a34a; } .root :global(.scan-terminal.light .monitor-trend.falling) { color: #2563EB; } .root :global(.scan-terminal.light .monitor-syncing-badge) { color: #2563EB; background: #EFF6FF; border-color: rgba(37, 99, 235, 0.22); } /* obs-age colours stay semantic in light mode */ .root :global(.scan-terminal.light .monitor-obs-age.fresh) { color: #16a34a; } .root :global(.scan-terminal.light .monitor-obs-age.aging) { color: #d97706; } .root :global(.scan-terminal.light .monitor-obs-age.stale) { color: #dc2626; } .root :global(.scan-terminal.light .monitor-obs-age.unknown) { color: #64748b; } /* ── Animations ── */ @keyframes monitorPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } @keyframes monitorShimmer { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } } @keyframes monitorSweep { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } .root :global(.monitor-divider) { height: 1px; background: var(--color-border-subtle); margin: 10px 0 8px; } .root :global(.monitor-rw-row) { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 2px; } .root :global(.monitor-rw-label) { color: var(--color-text-muted); } .root :global(.monitor-rw-temp) { color: var(--color-text-secondary); font-variant-numeric: tabular-nums; } /* ══════════════════════════════════════════════════════════════ LIGHT THEME OVERRIDES Scoped to .scan-terminal.light so the panel responds to the terminal's built-in theme toggle (not html.light). ══════════════════════════════════════════════════════════════ */ .root :global(.scan-terminal.light .monitor-panel) { background: #F7F9FC; color: #0F172A; } .root :global(.scan-terminal.light .monitor-header) { border-bottom-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-title) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-time), .root :global(.scan-terminal.light .monitor-stat-label), .root :global(.scan-terminal.light .monitor-obs-time), .root :global(.scan-terminal.light .monitor-obs-age), .root :global(.scan-terminal.light .monitor-rw-label), .root :global(.scan-terminal.light .monitor-high-time), .root :global(.scan-terminal.light .monitor-loading-indicator) { color: #475569; } .root :global(.scan-terminal.light .monitor-card) { background: #FFFFFF; border-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-card.new-high) { border-color: rgba(124, 58, 237, 0.24); } .root :global(.scan-terminal.light .monitor-skeleton-card) { background: #FFFFFF; border-color: #E2E8F0; } .root :global(.scan-terminal.light .monitor-skeleton-line) { background: #E2E8F0; } .root :global(.scan-terminal.light .monitor-city-name) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-airport-name), .root :global(.scan-terminal.light .monitor-high-value), .root :global(.scan-terminal.light .monitor-rw-temp) { color: #334155; } .root :global(.scan-terminal.light .monitor-temp-value) { color: #0F172A; } .root :global(.scan-terminal.light .monitor-temp-unit), .root :global(.scan-terminal.light .monitor-temp-missing), .root :global(.scan-terminal.light .monitor-stat-missing) { color: #94A3B8; } .root :global(.scan-terminal.light .monitor-divider) { background: #E2E8F0; } .root :global(.scan-terminal.light .monitor-notify-btn) { border-color: rgba(148, 163, 184, 0.3); color: #334155; } .root :global(.scan-terminal.light .monitor-notify-btn:hover) { border-color: rgba(37, 99, 235, 0.38); background: #EEF2F7; } .root :global(.scan-terminal.light .monitor-trend.rising) { color: #16a34a; } .root :global(.scan-terminal.light .monitor-trend.falling) { color: #2563EB; } /* ── Animations ── */ @keyframes monitorPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } @keyframes monitorShimmer { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }