:root { color: #1c2733; background: #eef2f6; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-synthesis: none; line-height: 1.5; text-rendering: optimizeLegibility; } * { box-sizing: border-box; } body { min-width: 320px; min-height: 100vh; margin: 0; background: linear-gradient(180deg, rgba(255, 255, 255, 0.75), rgba(238, 242, 246, 0.15) 280px), #eef2f6; } button, select, input { font: inherit; } button { min-height: 36px; border: 1px solid transparent; border-radius: 7px; padding: 0 13px; cursor: pointer; font-weight: 700; white-space: nowrap; } .status-chip { cursor: default; } button.status-chip { cursor: pointer; } button:focus-visible, select:focus-visible, input:focus-visible { outline: 3px solid rgba(20, 184, 166, 0.32); outline-offset: 2px; } button:disabled { cursor: not-allowed; opacity: 0.48; } .app-shell { display: flex; min-height: 100vh; flex-direction: column; gap: 14px; padding: 18px; } .dashboard-header, .toolbar, .run-summary, .coverage-preview, .pane, .list-panel, .detail-panel, .modal, .key-modal { border: 1px solid #d6dde5; border-radius: 8px; background: #ffffff; box-shadow: 0 12px 32px rgba(28, 39, 51, 0.07); } .dashboard-header { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 16px 18px; } .brand-block { min-width: 0; } .eyebrow { display: block; margin-bottom: 2px; color: #5e6f81; font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; } h1, h2, p { margin: 0; } h1 { color: #111923; font-size: 34px; font-weight: 850; line-height: 1.05; letter-spacing: 0; } .brand-block p { margin-top: 6px; color: #586777; font-size: 13px; } .header-controls { display: grid; max-width: 540px; justify-items: end; gap: 8px; } .api-controls { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; } .service-health { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; } .auto-start-button { min-height: 28px; border: 1px solid #b7d9ed; border-radius: 999px; background: #ecf7ff; color: #075985; padding: 4px 11px; font-size: 12px; font-weight: 850; } .stop-apis-button { min-height: 28px; border: 1px solid #fecaca; border-radius: 999px; background: #fff1f2; color: #b42339; padding: 4px 11px; font-size: 12px; font-weight: 850; } .auto-start-button:disabled, .stop-apis-button:disabled { cursor: wait; opacity: 0.7; } .status-chip, .pill, .catalog-count { display: inline-flex; min-height: 28px; align-items: center; gap: 7px; border: 1px solid #dbe3ea; border-radius: 999px; padding: 4px 10px; background: #f8fafc; color: #46586a; font-size: 12px; font-weight: 800; } .status-chip.ready, .status-chip.available { border-color: #b8ded7; background: #ecfdf8; color: #0d6b61; } .status-chip.starting { border-color: #fed7aa; background: #fff7ed; color: #9a3412; } .status-chip.unavailable { border-color: #fecaca; background: #fff1f2; color: #b42339; } .status-chip.muted { background: #f5f7f9; } .status-dot { width: 8px; height: 8px; border-radius: 999px; background: #15a585; box-shadow: 0 0 0 4px rgba(21, 165, 133, 0.13); } .status-chip.starting .status-dot { background: #f97316; box-shadow: 0 0 0 4px rgba(249, 115, 22, 0.14); } .status-chip.unavailable .status-dot { background: #e11d48; box-shadow: 0 0 0 4px rgba(225, 29, 72, 0.12); } .status-chip.unknown .status-dot { background: #94a3b8; box-shadow: 0 0 0 4px rgba(148, 163, 184, 0.13); } .toolbar { display: grid; grid-template-columns: minmax(220px, 1fr) auto; align-items: center; gap: 14px; padding: 12px; } .profile-control, .input-label { display: grid; gap: 6px; color: #5d6d7e; font-size: 12px; font-weight: 800; } .profile-control { width: 150px; } select, input { width: 100%; min-height: 38px; border: 1px solid #cbd6e2; border-radius: 7px; background: #ffffff; color: #1d2a37; padding: 0 11px; } .progress-block { display: grid; gap: 8px; min-width: 0; } .progress-copy { display: flex; align-items: center; justify-content: space-between; gap: 12px; color: #5b6a79; font-size: 12px; text-transform: capitalize; } .progress-copy b { color: #1c2733; text-transform: none; } .progress-rate { white-space: nowrap; text-transform: none; } .progress-track { position: relative; height: 10px; overflow: hidden; border-radius: 999px; background: #dfe7ee; } .progress-fill { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: inherit; background: linear-gradient(90deg, #0d9488, #38bdf8); transition: width 180ms ease; } .run-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; } .speed-control { display: grid; grid-template-columns: auto minmax(92px, 130px) minmax(52px, auto); min-height: 38px; align-items: center; gap: 7px; border: 1px solid #dbe3ea; border-radius: 7px; background: #f8fafc; color: #526274; padding: 5px 9px; font-size: 12px; font-weight: 800; } .speed-control select { width: 100%; min-height: auto; padding: 0 8px; } .speed-control b { color: #1d2a37; font-size: 11px; white-space: nowrap; } .primary { background: #0f766e; color: #ffffff; } .secondary { border-color: #cbd6e2; background: #ffffff; color: #223142; } .danger { border-color: #fecaca; background: #fff1f2; color: #b42339; } .dashboard-main { display: grid; gap: 14px; } .coverage-preview { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(260px, 0.65fr); gap: 14px; padding: 14px; } .coverage-header { grid-column: 1 / -1; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; } .coverage-header h2 { margin: 2px 0 0; color: #14202c; font-size: 18px; line-height: 1.15; } .coverage-map { position: relative; aspect-ratio: 1 / 1; min-height: 520px; overflow: hidden; border: 1px solid #d8e1ea; border-radius: 7px; background: linear-gradient(90deg, rgba(255, 255, 255, 0.55) 1px, transparent 1px) 0 0 / 56px 56px, linear-gradient(180deg, rgba(255, 255, 255, 0.55) 1px, transparent 1px) 0 0 / 56px 56px, linear-gradient(145deg, #d9edf0, #e6ecf3 54%, #dfe8df); cursor: grab; touch-action: none; user-select: none; } .coverage-map.dragging { cursor: grabbing; } .tile-map, .coverage-static-layer { position: absolute; inset: 0; } .tile-map { z-index: 1; } .tile-map img { position: absolute; object-fit: fill; display: block; } .coverage-static-layer { z-index: 2; pointer-events: auto; } .point { position: absolute; width: 14px; height: 14px; border: 2px solid #ffffff; border-radius: 999px; margin: -7px 0 0 -7px; background: #64748b; box-shadow: 0 2px 8px rgba(22, 31, 43, 0.2); pointer-events: auto; } .point.raster-point { width: 5px; height: 5px; border-width: 1px; margin: -2.5px 0 0 -2.5px; box-shadow: 0 1px 3px rgba(22, 31, 43, 0.18); pointer-events: none; } .point.queued, .point-state.queued { background: #64748b; } .point.active, .point-state.active { background: #0284c7; } .point.passed, .point-state.passed { background: #16a34a; } .point.failed, .point-state.failed { background: #dc2626; } .point.blocked, .point-state.blocked { background: #f97316; } .map-controls { position: absolute; top: 12px; left: 12px; z-index: 4; display: flex; flex-wrap: wrap; gap: 8px; max-width: calc(100% - 24px); } .map-controls button { min-height: 32px; border-color: rgba(203, 213, 225, 0.9); background: rgba(248, 250, 252, 0.94); box-shadow: 0 10px 24px rgba(22, 31, 43, 0.12); font-size: 12px; } .map-controls button.active { border-color: rgba(15, 118, 110, 0.45); background: rgba(204, 251, 241, 0.94); color: #0f5f59; } .map-progress { position: absolute; top: 12px; right: 12px; z-index: 4; display: grid; width: min(270px, calc(100% - 24px)); gap: 6px; border: 1px solid rgba(203, 213, 225, 0.9); border-radius: 7px; background: rgba(248, 250, 252, 0.94); color: #223142; padding: 9px 10px; box-shadow: 0 10px 24px rgba(22, 31, 43, 0.12); } .map-progress-copy, .map-progress-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; } .map-progress-copy span { color: #526274; font-size: 11px; font-weight: 850; text-transform: uppercase; } .map-progress-copy strong { color: #0f766e; font-size: 16px; line-height: 1; } .map-progress-track { height: 7px; overflow: hidden; border-radius: 999px; background: #e2e8f0; } .map-progress-track span { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #0f766e, #16a34a); } .map-progress-meta { color: #475569; font-size: 11px; font-weight: 800; } .map-progress code { overflow: hidden; color: #334155; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } .map-legend { position: absolute; right: 12px; bottom: 12px; z-index: 3; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px 10px; max-width: min(520px, calc(100% - 24px)); border: 1px solid rgba(203, 213, 225, 0.9); border-radius: 7px; background: rgba(248, 250, 252, 0.92); color: #243447; padding: 7px 9px; font-size: 11px; font-weight: 800; box-shadow: 0 10px 24px rgba(22, 31, 43, 0.12); } .map-legend span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; } .legend-point { position: static; display: inline-block; width: 10px; height: 10px; margin: 0; border-width: 1px; box-shadow: none; } .coverage-side { display: grid; min-width: 0; align-content: start; gap: 8px; } .coverage-side h2 { color: #14202c; font-size: 18px; line-height: 1.15; } .coverage-side p { color: #5c6c7b; font-size: 13px; } .segmented { display: inline-flex; width: fit-content; overflow: hidden; border: 1px solid #cbd6e2; border-radius: 7px; } .segmented button { min-height: 32px; border: 0; border-radius: 0; background: #ffffff; color: #46586a; } .segmented button.active { background: #0f766e; color: #ffffff; } .fixture-table { width: 100%; margin-top: 4px; border-collapse: collapse; color: #273544; font-size: 13px; } .fixture-table td { border-top: 1px solid #e2e8ef; padding: 9px 0; } .fixture-table td:last-child { width: 92px; padding-left: 10px; text-align: right; } .non-location-row td:first-child { display: grid; gap: 3px; } .non-location-row strong { color: #182533; font-size: 13px; } .non-location-row span { color: #627284; font-size: 12px; line-height: 1.35; } .request-count { display: inline-flex; min-width: 78px; justify-content: center; border-radius: 999px; background: #e8eef5; color: #46586a !important; padding: 3px 8px; font-size: 11px !important; font-weight: 850; white-space: nowrap; } .point-state { display: inline-flex; min-width: 72px; justify-content: center; border-radius: 999px; color: #ffffff; padding: 3px 8px; font-size: 11px; font-weight: 850; text-transform: uppercase; } .detail-body .label { overflow: hidden; color: #6b7b8b; font-size: 12px; font-weight: 800; text-overflow: ellipsis; white-space: nowrap; } .label-note { color: #7f8d9b; font-weight: 700; text-transform: none; } .metric-fail { color: #be123c !important; } .run-summary { display: grid; grid-template-columns: repeat(4, minmax(110px, 1fr)); overflow: hidden; } .summary-item { display: grid; min-width: 0; align-content: center; gap: 2px; min-height: 62px; border-right: 1px solid #e3e9ef; padding: 12px 14px; } .summary-item:last-child { border-right: 0; } .summary-item .label { overflow: hidden; color: #6b7b8b; font-size: 12px; font-weight: 800; text-overflow: ellipsis; white-space: nowrap; } .summary-item b { overflow: hidden; color: #15202b; font-size: 21px; line-height: 1.1; text-overflow: ellipsis; white-space: nowrap; } .workspace { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(300px, 0.85fr); gap: 14px; align-items: start; } .service-stack, .inspector-stack { display: grid; gap: 14px; min-width: 0; } .workspace-head { display: flex; align-items: end; justify-content: space-between; gap: 12px; min-width: 0; } .workspace-head h2 { overflow-wrap: anywhere; color: #14202c; font-size: 20px; line-height: 1.15; } .service-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } .pane { display: grid; gap: 12px; min-width: 0; padding: 14px; } .pane-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; } .pane-title h2 { color: #13202c; font-size: 16px; line-height: 1.15; } .pill { min-height: 24px; border-color: #cfd9e3; background: #f6f8fb; } .pill.ok { border-color: #bbf7d0; background: #f0fdf4; color: #166534; } .pill.error { border-color: #fecaca; background: #fff1f2; color: #b42339; } .request { overflow: hidden; border: 1px solid #dce4ec; border-radius: 7px; background: #f8fafc; color: #2c3946; padding: 9px 10px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } .request span { margin-right: 8px; color: #0f766e; font-weight: 900; } .response { min-height: 140px; max-height: 220px; margin: 0; overflow: auto; border: 1px solid #dce4ec; border-radius: 7px; background: #101820; color: #d8e8ef; padding: 12px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; font-size: 12px; line-height: 1.45; } .list-panel, .detail-panel { min-width: 0; overflow: hidden; } .panel-head { display: flex; min-height: 44px; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid #e2e8ef; padding: 0 13px; color: #1d2b38; font-size: 13px; font-weight: 850; } .failure-list { display: grid; gap: 8px; max-height: 320px; overflow: auto; padding: 10px; } .empty-list { border: 1px dashed #cbd6e2; border-radius: 7px; background: #f8fafc; color: #6a7a89; padding: 16px 12px; text-align: center; font-size: 13px; font-weight: 700; } .failure { display: grid; gap: 3px; width: 100%; height: auto; min-height: 74px; border-color: #dce3eb; background: #ffffff; color: #253342; padding: 10px; text-align: left; white-space: normal; } .failure:hover, .failure.selected { border-color: #0f766e; background: #f0fdfa; } .failure strong, .failure span { overflow: hidden; text-overflow: ellipsis; } .failure strong { font-size: 13px; } .failure span { color: #6a7a88; font-size: 12px; } .failure .kind { color: #b42339; font-weight: 800; } .detail-body { display: grid; gap: 8px; padding: 12px; } .detail-body code { display: block; min-height: 78px; max-height: 170px; overflow: auto; border: 1px solid #dce4ec; border-radius: 7px; background: #f8fafc; color: #273544; padding: 10px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; font-size: 12px; line-height: 1.45; white-space: pre-wrap; } .save-note { border: 1px solid #bbf7d0; border-radius: 7px; background: #f0fdf4; color: #166534; padding: 10px 12px; font-size: 13px; font-weight: 800; } .modal-backdrop { position: fixed; inset: 0; z-index: 10; display: grid; place-items: center; padding: 18px; background: rgba(12, 18, 26, 0.54); } .key-modal { display: grid; width: min(460px, 100%); gap: 12px; padding: 18px; } .modal-head h2 { color: #14202c; font-size: 22px; line-height: 1.15; } .key-modal p { color: #5c6c7b; font-size: 14px; } .error { color: #b42339 !important; font-weight: 800; } .success { color: #166534 !important; font-weight: 800; } .modal-actions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 2px; } .copy-status { color: #166534; font-size: 13px; font-weight: 800; } .report-modal, .service-modal { display: grid; width: min(780px, 100%); max-height: min(760px, calc(100vh - 36px)); gap: 12px; overflow: hidden; padding: 18px; } .report-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; } .report-preview { max-height: 520px; overflow: auto; border: 1px solid #dce4ec; border-radius: 7px; background: #f8fafc; padding: 14px; } .report-preview h1, .report-preview h2, .report-preview h3 { margin: 0 0 8px; color: #14202c; line-height: 1.15; } .report-preview h1 { font-size: 22px; } .report-preview h2 { margin-top: 14px; font-size: 18px; } .report-preview h3 { margin-top: 12px; font-size: 15px; } .report-preview p, .report-preview li { color: #314253; font-size: 13px; } .report-preview pre, .service-log { overflow: auto; border: 1px solid #dce4ec; border-radius: 7px; background: #101820; color: #d8e8ef; padding: 10px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; font-size: 12px; line-height: 1.45; } .service-config-grid { display: grid; gap: 10px; } .service-actions { justify-content: flex-start; } .service-progress { display: inline-flex; width: fit-content; align-items: center; gap: 8px; border: 1px solid #dbe3ea; border-radius: 999px; background: #f8fafc; color: #46586a; padding: 5px 10px; font-size: 12px; font-weight: 850; } .service-progress.available { border-color: #b8ded7; background: #ecfdf8; color: #0d6b61; } .service-progress.starting { border-color: #fed7aa; background: #fff7ed; color: #9a3412; } .service-progress.unavailable { border-color: #fecaca; background: #fff1f2; color: #b42339; } .service-progress.unknown .status-dot { background: #94a3b8; box-shadow: 0 0 0 4px rgba(148, 163, 184, 0.13); } .service-progress.starting .status-dot { background: #f97316; box-shadow: 0 0 0 4px rgba(249, 115, 22, 0.14); } .service-progress.unavailable .status-dot { background: #e11d48; box-shadow: 0 0 0 4px rgba(225, 29, 72, 0.12); } .service-log { min-height: 120px; max-height: 240px; margin: 0; } @media (max-width: 1120px) { .dashboard-header, .toolbar { align-items: stretch; grid-template-columns: 1fr; } .dashboard-header { flex-direction: column; } .service-health, .api-controls, .run-controls { justify-content: flex-start; } .header-controls { max-width: none; justify-items: start; } .toolbar { display: grid; } .workspace, .coverage-preview { grid-template-columns: 1fr; } } @media (max-width: 760px) { .app-shell { padding: 12px; } h1 { font-size: 28px; } .workspace-head, .pane-title, .progress-copy { align-items: flex-start; flex-direction: column; } .service-grid { grid-template-columns: 1fr; } .run-controls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } .run-controls button { width: 100%; } }