/* SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-27-p12-cadence-scheduler-monitor-web. */ :root { color-scheme: light; --bg: #f5f7f8; --panel: #ffffff; --panel-soft: #f9fbfb; --text: #17201f; --muted: #5e6b68; --line: #dce3e1; --line-strong: #b8c4c0; --red: #d43c35; --red-soft: #ffe8e5; --amber: #b7791f; --amber-soft: #fff2d6; --green: #1f8a5b; --green-soft: #e4f6ed; --blue: #2a6fbb; --ink: #203330; --shadow: 0 10px 28px rgba(32, 51, 48, 0.08); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } * { box-sizing: border-box; } html, body, #monitor-web-root { min-height: 100%; margin: 0; } body { background: var(--bg); color: var(--text); overflow: auto; } button, select, input { font: inherit; } .monitor-shell { display: flex; min-height: 100dvh; flex-direction: column; gap: 10px; overflow: visible; padding: 12px; } .topbar, .status-strip, .entry-strip, .trend-stage, .workspace-grid, .checks-panel { width: min(100%, 1760px); margin: 0 auto; } .topbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex: 0 0 auto; min-height: 58px; } .title-block { display: flex; min-width: 0; align-items: center; gap: 12px; } .mark { width: 34px; height: 34px; border: 2px solid var(--ink); border-radius: 8px; background: linear-gradient(135deg, #ffffff 0%, #e7f1ef 100%); box-shadow: inset 0 -8px 0 rgba(31, 138, 91, 0.16); } h1, h2, h3, p { margin: 0; } h1 { font-size: 20px; line-height: 1.15; letter-spacing: 0; } .subtitle { display: flex; min-width: 0; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 4px; color: var(--muted); font-size: 12px; } code, .mono { font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; } .pill, .toolbar-button, .entry-link, .legend-item, .metric, .timeline-item, .run-row, .check-table, .check-chip { border: 1px solid var(--line); border-radius: 8px; background: var(--panel); } .toolbar { display: flex; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; gap: 8px; } .toolbar-button, select { min-height: 34px; border: 1px solid var(--line-strong); border-radius: 8px; background: #ffffff; color: var(--text); cursor: pointer; } .toolbar-button { padding: 0 12px; } select { padding: 0 28px 0 10px; } .pill { display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 0 10px; color: var(--muted); font-size: 12px; white-space: nowrap; } .pill::before { content: ""; width: 7px; height: 7px; border-radius: 999px; background: var(--muted); } .pill.blocked, .pill.degraded { border-color: #efb3ad; background: var(--red-soft); color: #8b1f1a; } .pill.blocked::before, .pill.degraded::before { background: var(--red); } .pill.warning { border-color: #e5c06b; background: var(--amber-soft); color: #73500f; } .pill.warning::before { background: var(--amber); } .pill.healthy, .pill.idle { border-color: #b9ddc9; background: var(--green-soft); color: #17633f; } .pill.healthy::before, .pill.idle::before { background: var(--green); } .entry-strip { display: grid; grid-template-columns: minmax(180px, 240px) minmax(0, 1fr); gap: 10px; flex: 0 0 auto; align-items: stretch; } .entry-copy { display: flex; min-height: 52px; flex-direction: column; justify-content: center; color: var(--muted); font-size: 12px; } .entry-copy strong { color: var(--text); font-size: 15px; } .entry-links { display: flex; min-width: 0; gap: 8px; overflow-x: auto; padding-bottom: 2px; } .entry-link { display: grid; grid-template-columns: minmax(130px, 1fr) auto; min-width: 220px; max-width: 360px; gap: 10px; align-items: center; padding: 9px 10px; color: var(--text); text-decoration: none; } .entry-link.current { border-color: var(--green); box-shadow: inset 3px 0 0 var(--green); } .entry-link.disabled { opacity: 0.55; } .entry-link span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .entry-link small { color: var(--muted); font-size: 11px; } .trend-stage { display: grid; grid-template-columns: minmax(420px, 1.55fr) minmax(300px, 0.9fr); gap: 10px; flex: 0 0 auto; align-items: start; min-height: 0; } .trend-panel, .timeline-panel, .pane, .status-strip { border: 1px solid var(--line); border-radius: 8px; background: var(--panel); box-shadow: var(--shadow); } .trend-panel, .timeline-panel { min-width: 0; padding: 12px; } .trend-panel { align-self: start; } .panel-header { display: flex; align-items: start; justify-content: space-between; gap: 12px; margin-bottom: 10px; } .panel-header h2 { font-size: 15px; line-height: 1.25; } .panel-header p, .muted { color: var(--muted); font-size: 12px; } .trend-chart-wrap { position: relative; border: 1px solid var(--line); border-radius: 8px; background: linear-gradient(180deg, #ffffff 0%, #f7faf9 100%); overflow: visible; } .trend-chart { display: block; width: 100%; height: clamp(118px, 13vw, 150px); } .trend-empty { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: 13px; } .trend-duration { fill: none; stroke: var(--blue); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; } .trend-red, .trend-warning, .memory-line { fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; } .trend-red { stroke: var(--red); } .trend-warning { stroke: var(--amber); } .trend-grid-line { stroke: #e5ecea; stroke-width: 1; } .trend-dot-duration { fill: var(--blue); stroke: #ffffff; stroke-width: 1.5; } .trend-dot-red { fill: var(--red); stroke: #ffffff; stroke-width: 1.2; } .trend-dot-warning { fill: var(--amber); stroke: #ffffff; stroke-width: 1.2; } .trend-dot-hit { cursor: default; outline: none; } .trend-dot-hit:focus-visible .trend-hit-area { stroke: var(--blue); stroke-width: 1.5; } .trend-hit-area { fill: transparent; stroke: transparent; } .trend-tooltip { position: absolute; z-index: 8; display: grid; width: min(286px, calc(100% - 16px)); max-width: calc(100% - 16px); gap: 3px; transform: translate(-50%, -100%); border: 1px solid var(--line-strong); border-radius: 8px; background: #ffffff; box-shadow: 0 12px 28px rgba(32, 51, 48, 0.16); color: var(--muted); padding: 9px 10px; pointer-events: none; font-size: 12px; line-height: 1.35; } .trend-tooltip strong { overflow: hidden; color: var(--text); text-overflow: ellipsis; white-space: nowrap; } .trend-legend { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; } .legend-item { display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 9px; color: var(--muted); font-size: 12px; } .legend-swatch { width: 18px; height: 3px; border-radius: 999px; } .legend-swatch.red { background: var(--red); } .legend-swatch.duration { background: var(--blue); } .legend-swatch.warning { background: var(--amber); } .legend-swatch.total { background: var(--blue); } .legend-swatch.memory.memory-line-1, .memory-line-1 { stroke: #2a6fbb; background: #2a6fbb; } .legend-swatch.memory.memory-line-2, .memory-line-2 { stroke: #1f8a5b; background: #1f8a5b; } .legend-swatch.memory.memory-line-3, .memory-line-3 { stroke: #b7791f; background: #b7791f; } .legend-swatch.memory.memory-line-4, .memory-line-4 { stroke: #7a5dc7; background: #7a5dc7; } .legend-swatch.memory.memory-line-5, .memory-line-5 { stroke: #c04f7a; background: #c04f7a; } .legend-swatch.memory.memory-line-6, .memory-line-6 { stroke: #327b89; background: #327b89; } .timeline-panel { display: flex; min-height: 0; flex-direction: column; } .timeline-list { display: grid; max-height: 300px; gap: 7px; overflow: auto; padding-right: 2px; } .timeline-item { display: grid; grid-template-columns: 78px minmax(0, 1fr) minmax(112px, auto); gap: 8px; align-items: center; padding: 7px 8px; font-size: 12px; } .run-alert-tags { display: flex; min-width: 0; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; gap: 4px; } .timeline-item strong, .run-row strong, .check-title-cell strong { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .timeline-marker { width: 9px; height: 9px; border-radius: 999px; background: var(--green); } .timeline-item.red .timeline-marker, .run-row.red .severity-dot, .check-row.red .severity-dot { background: var(--red); } .timeline-item.warning .timeline-marker, .run-row.warning .severity-dot, .check-row.warning .severity-dot { background: var(--amber); } .timeline-item.info .timeline-marker, .run-row.info .severity-dot, .check-row.info .severity-dot { background: var(--blue); } .status-strip { display: grid; grid-template-columns: repeat(5, minmax(120px, 1fr)); gap: 8px; flex: 0 0 auto; padding: 8px; } .metric { display: flex; min-width: 0; flex-direction: column; gap: 2px; padding: 8px 10px; background: var(--panel-soft); } .metric span { color: var(--muted); font-size: 11px; } .metric strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; } .metric.warning { border-color: #e5c06b; background: var(--amber-soft); } .workspace-grid { display: grid; grid-template-columns: minmax(300px, 0.82fr) minmax(520px, 1.55fr); gap: 10px; align-items: stretch; flex: 0 0 auto; height: 80dvh; max-height: 80dvh; min-height: 0; overflow: visible; } .workspace-grid > .pane { height: 100%; } .pane { position: relative; isolation: isolate; display: flex; min-width: 0; min-height: 0; flex-direction: column; overflow: auto; padding: 12px; } .pane-header { position: sticky; top: -12px; z-index: 12; display: flex; align-items: start; justify-content: space-between; gap: 10px; margin: -12px -12px 10px; padding: 12px 12px 13px; border-bottom: 1px solid var(--line); background: var(--panel); box-shadow: 0 10px 16px rgba(32, 51, 48, 0.08); } .pane-header::before { position: absolute; right: 0; left: 0; top: -18px; height: 18px; background: var(--panel); content: ""; } .pane-header h2 { font-size: 15px; } .filter-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; } .filter-row input, .filter-row select { min-width: 0; min-height: 32px; border: 1px solid var(--line-strong); border-radius: 8px; padding: 0 10px; background: #ffffff; } .run-list, .detail-stack { display: grid; align-content: start; gap: 8px; } .checks-panel { flex: 0 0 auto; height: 80dvh; max-height: 80dvh; min-height: 0; } .checks-panel .filter-row select { min-width: 150px; } .checks-panel .filter-row select[aria-label="选择运行记录"] { flex: 1 1 280px; } .checks-panel .filter-row input { flex: 1 1 260px; } .check-summary { display: grid; grid-template-columns: repeat(6, minmax(120px, 1fr)); gap: 8px; margin-bottom: 10px; } .finding-list { min-height: 0; } .run-row { display: grid; gap: 6px; padding: 10px; text-align: left; } .run-row { cursor: pointer; } .check-table-wrap { overflow: auto; border: 1px solid var(--line); border-radius: 8px; background: #ffffff; } .check-table { width: 100%; min-width: 1120px; border-collapse: separate; border-spacing: 0; font-size: 12px; } .check-table th, .check-table td { border-bottom: 1px solid var(--line); padding: 9px 10px; text-align: left; vertical-align: middle; } .check-table th { position: sticky; top: 0; z-index: 2; background: #f7faf9; color: var(--muted); font-weight: 600; } .check-table tr:last-child td { border-bottom: 0; } .check-row { cursor: pointer; } .check-row:hover, .check-row:focus-visible { background: #f3f8f7; outline: none; } .check-row.red { box-shadow: inset 3px 0 0 var(--red); } .check-row.warning { box-shadow: inset 3px 0 0 var(--amber); } .check-title-cell { min-width: 260px; } .check-title-cell strong, .check-title-cell span { display: block; } .check-title-cell span { margin-top: 3px; color: var(--muted); line-height: 1.35; } .detail-link { color: var(--blue); font-weight: 600; } .run-row.selected { border-color: var(--blue); box-shadow: inset 3px 0 0 var(--blue); } .row-line { display: flex; min-width: 0; align-items: center; justify-content: space-between; gap: 8px; } .severity-line { display: flex; align-items: center; gap: 6px; min-width: 0; } .severity-dot { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 999px; background: var(--green); } .check-code { flex: 0 0 auto; border: 1px solid var(--line-strong); border-radius: 6px; background: #ffffff; color: var(--ink); padding: 2px 6px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; font-size: 11px; line-height: 1.2; } .tag { display: inline-flex; align-items: center; min-height: 22px; max-width: 100%; border-radius: 999px; background: #eef3f1; color: var(--muted); padding: 0 8px; font-size: 11px; } .tag.red { background: var(--red-soft); color: #8b1f1a; } .tag.warning { background: var(--amber-soft); color: #73500f; } .tag.healthy { background: var(--green-soft); color: #17633f; } .check-dialog-backdrop { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; background: rgba(17, 32, 30, 0.42); padding: 24px; } .check-dialog { display: flex; width: min(1120px, 96vw); max-height: 88dvh; min-height: min(520px, 88dvh); flex-direction: column; overflow: hidden; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--panel); box-shadow: 0 24px 70px rgba(17, 32, 30, 0.24); } .check-dialog-header { display: flex; flex: 0 0 auto; align-items: start; justify-content: space-between; gap: 16px; border-bottom: 1px solid var(--line); padding: 16px; } .check-dialog-header h2 { margin-top: 8px; font-size: 20px; } .check-dialog-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 8px; } .dialog-close { min-height: 32px; border: 1px solid var(--line-strong); border-radius: 8px; background: #ffffff; color: var(--text); padding: 0 12px; cursor: pointer; } .check-dialog-body { display: grid; grid-template-columns: minmax(300px, 0.82fr) minmax(420px, 1fr); gap: 12px; min-height: 0; overflow: auto; padding: 16px; } .check-dialog-body .detail-card { min-width: 0; } .detail-card-wide { grid-column: 1 / -1; } .detail-card { border: 1px solid var(--line); border-radius: 8px; background: var(--panel-soft); padding: 12px; } .detail-card h3 { margin-bottom: 8px; font-size: 14px; } .detail-card-heading { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; } .detail-card-heading h3 { margin-bottom: 0; } .memory-card { overflow: hidden; } .memory-chart-wrap { display: grid; gap: 8px; } .memory-chart { display: block; width: 100%; height: 192px; border: 1px solid var(--line); border-radius: 8px; background: #ffffff; } .memory-legend { display: flex; min-width: 0; flex-wrap: wrap; gap: 8px; color: var(--muted); font-size: 12px; } .memory-grid-line { stroke: #e5ecea; stroke-width: 1; } .memory-axis-line { stroke: #71817c; stroke-width: 1.2; } .memory-tick-line { stroke: #71817c; stroke-width: 1; } .memory-axis-label { fill: var(--muted); font-size: 11px; } .memory-axis-label-y { text-anchor: end; } .memory-axis-label-x { text-anchor: middle; } .memory-axis-title { fill: #4f625d; font-size: 11px; font-weight: 700; } .memory-axis-title-x { text-anchor: middle; } .detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; } .detail-grid .metric { background: #ffffff; } .summary-list { display: grid; overflow: hidden; border: 1px solid var(--line); border-radius: 8px; background: #ffffff; } .summary-row { display: grid; grid-template-columns: minmax(86px, 0.35fr) minmax(0, 1fr); gap: 10px; align-items: center; min-height: 34px; padding: 7px 10px; border-bottom: 1px solid var(--line); font-size: 12px; } .summary-row:last-child { border-bottom: 0; } .summary-row span { color: var(--muted); } .summary-row strong { min-width: 0; overflow-wrap: anywhere; font-size: 12px; font-weight: 600; } pre { max-height: 240px; margin: 0; overflow: auto; border: 1px solid var(--line); border-radius: 8px; background: #10211e; color: #eef8f4; padding: 10px; font-size: 12px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; } .check-grid { display: flex; flex-wrap: wrap; gap: 6px; } .check-chip { min-height: 26px; padding: 5px 8px; color: var(--muted); font-size: 11px; } .check-chip.ok { border-color: #b9ddc9; background: var(--green-soft); color: #17633f; } .check-chip.bad { border-color: #efb3ad; background: var(--red-soft); color: #8b1f1a; } .banner { width: min(100%, 1760px); margin: 0 auto; flex: 0 0 auto; border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; font-size: 13px; } .banner.error { border-color: #efb3ad; background: var(--red-soft); color: #8b1f1a; } .empty { display: grid; min-height: 120px; place-items: center; border: 1px dashed var(--line-strong); border-radius: 8px; color: var(--muted); font-size: 13px; } @media (max-width: 1120px) { body { overflow: auto; } .monitor-shell { height: auto; min-height: 100dvh; overflow: visible; } .trend-stage, .workspace-grid, .entry-strip { grid-template-columns: 1fr; } .workspace-grid { height: auto; max-height: none; min-height: 0; overflow: visible; } .workspace-grid > .pane { height: auto; } .pane { max-height: 80dvh; } .checks-panel { height: 80dvh; max-height: 80dvh; } .check-dialog-body { grid-template-columns: 1fr; } .status-strip, .check-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 640px) { .monitor-shell { padding: 8px; } .topbar { align-items: stretch; flex-direction: column; } .toolbar { justify-content: stretch; } .toolbar-button, .toolbar select { flex: 1 1 96px; } .entry-link { min-width: 190px; } .status-strip, .check-summary, .detail-grid { grid-template-columns: 1fr; } .timeline-item { grid-template-columns: 62px minmax(0, 1fr); } .timeline-item .run-alert-tags { grid-column: 2; justify-content: flex-start; } .check-dialog-backdrop { padding: 8px; } .check-dialog { width: 100%; max-height: 94dvh; } .check-dialog-header { flex-direction: column; } .check-dialog-actions { width: 100%; justify-content: space-between; } }