同源 API
@@ -106,15 +60,7 @@ function isNavItemActive(item: NavItem): boolean {
-
+
+
diff --git a/web/hwlab-cloud-web/src/components/layout/BoundedWorkspace.vue b/web/hwlab-cloud-web/src/components/layout/BoundedWorkspace.vue
new file mode 100644
index 00000000..c93afd95
--- /dev/null
+++ b/web/hwlab-cloud-web/src/components/layout/BoundedWorkspace.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/hwlab-cloud-web/src/components/layout/PageCommandBar.vue b/web/hwlab-cloud-web/src/components/layout/PageCommandBar.vue
new file mode 100644
index 00000000..acca3f88
--- /dev/null
+++ b/web/hwlab-cloud-web/src/components/layout/PageCommandBar.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/web/hwlab-cloud-web/src/components/layout/SectionFrame.vue b/web/hwlab-cloud-web/src/components/layout/SectionFrame.vue
new file mode 100644
index 00000000..a3f975ae
--- /dev/null
+++ b/web/hwlab-cloud-web/src/components/layout/SectionFrame.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/hwlab-cloud-web/src/components/layout/StatusStrip.vue b/web/hwlab-cloud-web/src/components/layout/StatusStrip.vue
new file mode 100644
index 00000000..990a8f22
--- /dev/null
+++ b/web/hwlab-cloud-web/src/components/layout/StatusStrip.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ ;
+ density: ComputedRef;
+ q: ComputedRef;
+ filter: ComputedRef;
+ sort: ComputedRef;
+ cursor: ComputedRef;
+ tab: ComputedRef;
+ update: (patch: Partial, replace?: boolean) => Promise;
+}
+
+export function useConsoleViewState(defaults: ConsoleViewStateDefaults = {}): ConsoleViewState {
+ const route = useRoute();
+ const router = useRouter();
+
+ const view = computed(() => queryEnum(route.query.view, ["cards", "list"] as const, defaults.view ?? "cards"));
+ const density = computed(() => queryEnum(route.query.density, ["compact", "comfortable"] as const, defaults.density ?? "comfortable"));
+ const q = computed(() => queryText(route.query.q) || defaults.q || "");
+ const filter = computed(() => queryText(route.query.filter) || defaults.filter || "");
+ const sort = computed(() => queryText(route.query.sort) || defaults.sort || "");
+ const cursor = computed(() => queryText(route.query.cursor) || defaults.cursor || "");
+ const tab = computed(() => queryText(route.query.tab) || defaults.tab || "");
+
+ async function update(patch: Partial, replace = true): Promise {
+ const query: LocationQueryRaw = { ...route.query };
+ for (const [key, value] of Object.entries(patch)) {
+ if (value === undefined || value === null || value === "") delete query[key];
+ else query[key] = value;
+ }
+ if ("q" in patch || "filter" in patch || "sort" in patch) delete query.cursor;
+ const location = { path: route.path, query, hash: route.hash };
+ if (replace) await router.replace(location);
+ else await router.push(location);
+ }
+
+ return { view, density, q, filter, sort, cursor, tab, update };
+}
+
+function queryText(value: unknown): string {
+ if (Array.isArray(value)) return queryText(value[0]);
+ return typeof value === "string" ? value.trim() : "";
+}
+
+function queryEnum(value: unknown, allowed: readonly T[], fallback: T): T {
+ const text = queryText(value);
+ return allowed.includes(text as T) ? text as T : fallback;
+}
diff --git a/web/hwlab-cloud-web/src/composables/useOverlaySurface.ts b/web/hwlab-cloud-web/src/composables/useOverlaySurface.ts
new file mode 100644
index 00000000..0a566255
--- /dev/null
+++ b/web/hwlab-cloud-web/src/composables/useOverlaySurface.ts
@@ -0,0 +1,112 @@
+// SPEC: PJ2026-010405 云端控制台.
+// Implementation reference: draft-2026-07-13-p0-cloud-console.
+
+import { nextTick, onBeforeUnmount, type Ref, watch } from "vue";
+
+interface OverlaySurfaceOptions {
+ modal?: boolean;
+ trapFocus?: boolean;
+ closeOnEscape?: boolean;
+ initialFocusSelector?: string;
+}
+
+const FOCUSABLE_SELECTOR = [
+ "a[href]",
+ "button:not([disabled])",
+ "input:not([disabled])",
+ "select:not([disabled])",
+ "textarea:not([disabled])",
+ "[tabindex]:not([tabindex='-1'])"
+].join(",");
+
+let overlayIdCounter = 0;
+let scrollLockCount = 0;
+
+export function nextOverlayId(prefix: string): string {
+ overlayIdCounter += 1;
+ return `${prefix}-${overlayIdCounter}`;
+}
+
+export function useOverlaySurface(
+ open: Ref,
+ surface: Ref,
+ requestClose: () => void,
+ options: OverlaySurfaceOptions = {}
+): void {
+ const modal = options.modal ?? true;
+ const trapFocus = options.trapFocus ?? modal;
+ const closeOnEscape = options.closeOnEscape ?? true;
+ let restoreTarget: HTMLElement | null = null;
+ let ownsScrollLock = false;
+
+ watch(open, async (visible) => {
+ if (!visible) {
+ deactivate();
+ return;
+ }
+ restoreTarget = document.activeElement instanceof HTMLElement ? document.activeElement : null;
+ if (modal) acquireScrollLock();
+ window.addEventListener("keydown", onKeydown, true);
+ await nextTick();
+ const target = options.initialFocusSelector
+ ? surface.value?.querySelector(options.initialFocusSelector)
+ : firstFocusable(surface.value);
+ (target ?? surface.value)?.focus({ preventScroll: true });
+ }, { immediate: true });
+
+ onBeforeUnmount(deactivate);
+
+ function onKeydown(event: KeyboardEvent): void {
+ if (!open.value || !surface.value) return;
+ if (event.key === "Escape" && closeOnEscape) {
+ event.preventDefault();
+ event.stopPropagation();
+ requestClose();
+ return;
+ }
+ if (event.key !== "Tab" || !trapFocus) return;
+ const focusable = Array.from(surface.value.querySelectorAll(FOCUSABLE_SELECTOR)).filter(isFocusable);
+ if (focusable.length === 0) {
+ event.preventDefault();
+ surface.value.focus({ preventScroll: true });
+ return;
+ }
+ const first = focusable[0];
+ const last = focusable.at(-1);
+ if (!first || !last) return;
+ if (event.shiftKey && document.activeElement === first) {
+ event.preventDefault();
+ last.focus();
+ } else if (!event.shiftKey && document.activeElement === last) {
+ event.preventDefault();
+ first.focus();
+ }
+ }
+
+ function acquireScrollLock(): void {
+ if (ownsScrollLock) return;
+ ownsScrollLock = true;
+ scrollLockCount += 1;
+ document.body.classList.add("console-scroll-locked");
+ }
+
+ function deactivate(): void {
+ window.removeEventListener("keydown", onKeydown, true);
+ if (ownsScrollLock) {
+ ownsScrollLock = false;
+ scrollLockCount = Math.max(0, scrollLockCount - 1);
+ if (scrollLockCount === 0) document.body.classList.remove("console-scroll-locked");
+ }
+ const target = restoreTarget;
+ restoreTarget = null;
+ if (target?.isConnected) void nextTick(() => target.focus({ preventScroll: true }));
+ }
+}
+
+function firstFocusable(surface: HTMLElement | null): HTMLElement | null {
+ return Array.from(surface?.querySelectorAll(FOCUSABLE_SELECTOR) ?? []).find(isFocusable) ?? null;
+}
+
+function isFocusable(element: HTMLElement): boolean {
+ return !element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true" && element.tabIndex >= 0;
+}
diff --git a/web/hwlab-cloud-web/src/main.ts b/web/hwlab-cloud-web/src/main.ts
index 941ec5cb..3914b190 100644
--- a/web/hwlab-cloud-web/src/main.ts
+++ b/web/hwlab-cloud-web/src/main.ts
@@ -1,3 +1,6 @@
+// SPEC: PJ2026-010405 云端控制台.
+// Implementation reference: draft-2026-07-13-p0-cloud-console.
+
import { createApp } from "vue";
import { createPinia } from "pinia";
import { PiniaColada } from "@pinia/colada";
@@ -7,8 +10,12 @@ import i18n, { initI18n } from "./i18n";
import { useAppStore } from "@/stores/app";
import { workbenchRuntimePolicy } from "@/config/workbench-runtime-policy";
import { installWebRum } from "@/utils/rum";
+import "./styles/tokens.css";
import "./style.css";
+import "./styles/console-legacy.css";
import "./styles/workbench.css";
+import "./styles/console-pages.css";
+import "./styles/console-foundation.css";
function initThemeClass(): void {
const savedTheme = localStorage.getItem("theme");
diff --git a/web/hwlab-cloud-web/src/router/meta.d.ts b/web/hwlab-cloud-web/src/router/meta.d.ts
index 80b375a4..f83ddd8a 100644
--- a/web/hwlab-cloud-web/src/router/meta.d.ts
+++ b/web/hwlab-cloud-web/src/router/meta.d.ts
@@ -1,4 +1,6 @@
// SPEC: PJ2026-010404 项目管理 draft-2026-06-25-p0-project-management-mdtodo.
+// SPEC: PJ2026-010405 云端控制台.
+// Implementation reference: draft-2026-07-13-p0-cloud-console.
// Responsibility: Router metadata sections for Cloud Web navigation, including project management.
import "vue-router";
@@ -8,6 +10,7 @@ declare module "vue-router" {
requiresAuth?: boolean;
requiresAdmin?: boolean;
navId?: string;
+ navParent?: string;
title?: string;
section?: "workbench" | "workbench-debug" | "opencode" | "project" | "admin" | "user" | "system";
}
diff --git a/web/hwlab-cloud-web/src/style.css b/web/hwlab-cloud-web/src/style.css
index a5a0ccef..8c2534e4 100644
--- a/web/hwlab-cloud-web/src/style.css
+++ b/web/hwlab-cloud-web/src/style.css
@@ -1,3 +1,6 @@
+/* SPEC: PJ2026-010405 云端控制台. */
+/* Implementation reference: draft-2026-07-13-p0-cloud-console. */
+
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -5,16 +8,30 @@
@layer base {
html {
color-scheme: light;
- font-family: ui-sans-serif, system-ui, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
+ width: 100%;
+ min-width: 320px;
+ height: 100%;
+ overflow: hidden;
+ font-family: var(--console-font-sans);
scroll-behavior: smooth;
}
body {
+ width: 100%;
min-width: 320px;
- min-height: 100vh;
+ height: 100%;
+ min-height: 100%;
margin: 0;
- background: #eef3f8;
- color: #111827;
+ overflow: hidden;
+ background: var(--console-canvas);
+ color: var(--console-graphite-900);
+ }
+
+ #app {
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ min-height: 0;
}
button,
@@ -26,6 +43,16 @@
* {
box-sizing: border-box;
}
+
+ @media (prefers-reduced-motion: reduce) {
+ html { scroll-behavior: auto; }
+ *, *::before, *::after {
+ scroll-behavior: auto !important;
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+ }
}
@layer components {
diff --git a/web/hwlab-cloud-web/src/styles/console-foundation.css b/web/hwlab-cloud-web/src/styles/console-foundation.css
new file mode 100644
index 00000000..7826c5d6
--- /dev/null
+++ b/web/hwlab-cloud-web/src/styles/console-foundation.css
@@ -0,0 +1,992 @@
+/* SPEC: PJ2026-010405 云端控制台. */
+/* Implementation reference: draft-2026-07-13-p0-cloud-console. */
+
+.page-command-bar {
+ display: grid;
+ min-width: 0;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: var(--console-space-3) var(--console-space-4);
+ align-items: end;
+ padding: var(--console-space-2) 0 var(--console-space-4);
+}
+
+.page-command-bar[data-sticky="true"] {
+ position: sticky;
+ top: 0;
+ z-index: 12;
+ border-bottom: 1px solid var(--console-border);
+ background: color-mix(in srgb, var(--console-canvas) 92%, transparent);
+ backdrop-filter: blur(10px);
+}
+
+.page-command-copy,
+.page-command-title,
+.page-command-description {
+ min-width: 0;
+ margin: 0;
+}
+
+.page-command-copy {
+ display: grid;
+ gap: var(--console-space-1);
+}
+
+.page-command-eyebrow {
+ color: var(--console-cyan-700);
+ font-family: var(--console-font-mono);
+ font-size: 11px;
+ font-weight: 760;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.page-command-title {
+ color: var(--console-graphite-950);
+ font-size: clamp(22px, 2.5vw, 30px);
+ font-weight: 760;
+ letter-spacing: -0.025em;
+ line-height: 1.1;
+}
+
+.page-command-description {
+ max-width: 78ch;
+ color: var(--console-graphite-600);
+ font-size: 13px;
+ line-height: 1.5;
+}
+
+.page-command-actions,
+.page-command-filters {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: var(--console-space-2);
+}
+
+.page-command-actions {
+ justify-content: flex-end;
+}
+
+.page-command-filters {
+ grid-column: 1 / -1;
+}
+
+.console-status-strip {
+ display: flex;
+ min-width: 0;
+ align-items: stretch;
+ gap: 1px;
+ overflow-x: auto;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-border);
+ scrollbar-width: thin;
+}
+
+.console-status-item {
+ display: grid;
+ min-width: 138px;
+ flex: 1 1 170px;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 2px var(--console-space-2);
+ align-items: center;
+ background: var(--console-surface-raised);
+ padding: 8px 10px;
+}
+
+.console-status-item::before {
+ width: 6px;
+ height: 6px;
+ grid-row: 1 / span 2;
+ border-radius: 50%;
+ background: var(--console-graphite-300);
+ content: "";
+}
+
+.console-status-item[data-tone="ok"]::before { background: var(--console-green-700); }
+.console-status-item[data-tone="warn"]::before { background: var(--console-amber-500); }
+.console-status-item[data-tone="error"]::before { background: var(--console-red-700); }
+.console-status-item[data-tone="info"]::before { background: var(--console-cyan-600); }
+
+.console-status-item dt,
+.console-status-item dd {
+ min-width: 0;
+ margin: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.console-status-item dt {
+ color: var(--console-graphite-600);
+ font-family: var(--console-font-mono);
+ font-size: 10px;
+ font-weight: 720;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.console-status-item dd {
+ color: var(--console-graphite-900);
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.console-section-frame {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ grid-template-rows: auto minmax(0, 1fr);
+ overflow: hidden;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-md);
+ background: var(--console-surface-raised);
+ box-shadow: var(--console-shadow-sm);
+}
+
+.console-section-frame[data-tone="inset"] {
+ background: var(--console-surface-muted);
+ box-shadow: none;
+}
+
+.console-section-header {
+ display: flex;
+ min-width: 0;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: var(--console-space-3);
+ border-bottom: 1px solid var(--console-border);
+ padding: 11px 13px;
+}
+
+.console-section-heading {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+}
+
+.console-section-heading h2,
+.console-section-heading p {
+ min-width: 0;
+ margin: 0;
+}
+
+.console-section-heading h2 {
+ color: var(--console-graphite-950);
+ font-size: 14px;
+ font-weight: 760;
+}
+
+.console-section-heading p {
+ color: var(--console-graphite-600);
+ font-size: 12px;
+ line-height: 1.45;
+}
+
+.console-section-body {
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ padding: var(--console-space-3);
+ overscroll-behavior: contain;
+}
+
+.bounded-workspace {
+ display: grid;
+ width: 100%;
+ height: 100%;
+ min-width: 0;
+ min-height: 0;
+ grid-template-columns: minmax(0, 1fr);
+ overflow: hidden;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-md);
+ background: var(--console-surface-raised);
+}
+
+.bounded-workspace[data-inspector-open="true"] {
+ grid-template-columns: minmax(0, 1fr) minmax(280px, var(--console-inspector-width, 36%));
+}
+
+.bounded-workspace-main,
+.bounded-workspace-inspector {
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ overscroll-behavior: contain;
+}
+
+.bounded-workspace-inspector {
+ border-left: 1px solid var(--console-border);
+ background: var(--console-surface-muted);
+}
+
+.resource-collection {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ grid-template-rows: auto minmax(0, 1fr);
+ gap: var(--console-space-3);
+}
+
+.resource-collection-toolbar {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--console-space-2);
+}
+
+.resource-collection-count {
+ color: var(--console-graphite-600);
+ font-family: var(--console-font-mono);
+ font-size: 11px;
+}
+
+.segmented-control {
+ display: inline-flex;
+ align-items: center;
+ gap: 1px;
+ border: 1px solid var(--console-border-strong);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-border);
+ overflow: hidden;
+}
+
+.segmented-control button {
+ min-height: 30px;
+ border: 0;
+ background: var(--console-surface-raised);
+ padding: 0 10px;
+ color: var(--console-graphite-600);
+ font-size: 11px;
+ font-weight: 720;
+}
+
+.segmented-control button[aria-pressed="true"] {
+ background: var(--console-graphite-900);
+ color: #fff;
+}
+
+.resource-collection-items {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ align-content: start;
+ gap: var(--console-space-3);
+ overflow: auto;
+ overscroll-behavior: contain;
+}
+
+.resource-collection-items[data-view="cards"] {
+ grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
+}
+
+.resource-collection-items[data-view="list"] {
+ grid-template-columns: minmax(0, 1fr);
+}
+
+.resource-collection-items[data-density="compact"] { gap: var(--console-space-2); }
+
+.entity-card {
+ position: relative;
+ display: grid;
+ min-width: 0;
+ align-content: start;
+ gap: 10px;
+ overflow: hidden;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-surface-raised);
+ padding: 13px;
+ color: var(--console-graphite-900);
+ box-shadow: var(--console-shadow-sm);
+}
+
+.entity-card[data-interactive="true"] {
+ cursor: pointer;
+ transition: border-color var(--console-duration-fast) ease, box-shadow var(--console-duration-fast) ease, transform var(--console-duration-fast) ease;
+}
+
+.entity-card[data-interactive="true"]:hover {
+ border-color: var(--console-cyan-600);
+ box-shadow: 0 8px 24px rgb(11 17 19 / 10%);
+ transform: translateY(-1px);
+}
+
+.entity-card[data-selected="true"] {
+ border-color: var(--console-cyan-600);
+ box-shadow: inset 3px 0 0 var(--console-cyan-500), var(--console-shadow-sm);
+}
+
+.entity-card[data-disabled="true"] {
+ cursor: not-allowed;
+ opacity: 0.58;
+}
+
+.entity-card-header {
+ display: flex;
+ min-width: 0;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: var(--console-space-2);
+}
+
+.entity-card-title-stack {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+}
+
+.entity-card-title-stack strong,
+.entity-card-title-stack small {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.entity-card-title-stack strong { font-size: 14px; }
+.entity-card-title-stack small { color: var(--console-graphite-600); font-size: 11px; }
+
+.entity-card-body {
+ min-width: 0;
+ color: var(--console-graphite-700);
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.entity-card-footer {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: var(--console-space-2);
+ border-top: 1px solid var(--console-graphite-100);
+ padding-top: 9px;
+}
+
+.console-data-grid-wrap {
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-surface-raised);
+ overscroll-behavior: contain;
+}
+
+.console-data-grid {
+ width: 100%;
+ min-width: max-content;
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+.console-data-grid th,
+.console-data-grid td {
+ min-width: 0;
+ border-bottom: 1px solid var(--console-graphite-100);
+ padding: 10px 12px;
+ color: var(--console-graphite-800);
+ font-size: 12px;
+ text-align: left;
+ vertical-align: middle;
+}
+
+.console-data-grid[data-density="compact"] th,
+.console-data-grid[data-density="compact"] td { padding-block: 7px; }
+
+.console-data-grid th {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ background: var(--console-surface-muted);
+ color: var(--console-graphite-600);
+ font-family: var(--console-font-mono);
+ font-size: 10px;
+ font-weight: 760;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.console-data-grid th[data-align="right"],
+.console-data-grid td[data-align="right"] { text-align: right; }
+
+.console-data-grid tbody tr[data-interactive="true"] { cursor: pointer; }
+.console-data-grid tbody tr[data-selected="true"] td { background: var(--console-cyan-100); }
+.console-data-grid tbody tr:hover td { background: color-mix(in srgb, var(--console-cyan-100) 45%, white); }
+.console-data-grid tbody tr:last-child td { border-bottom: 0; }
+
+.console-virtual-list {
+ position: relative;
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ overscroll-behavior: contain;
+}
+
+.console-virtual-list-spacer { position: relative; width: 100%; }
+.console-virtual-list-window { position: absolute; inset: 0 0 auto; display: grid; }
+
+.console-async-boundary {
+ position: relative;
+ min-width: 0;
+ min-height: 0;
+}
+
+.console-async-indicator {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ border: 1px solid var(--console-cyan-200);
+ border-radius: var(--console-radius-xs);
+ background: var(--console-cyan-100);
+ padding: 4px 7px;
+ color: var(--console-cyan-700);
+ font-size: 11px;
+ font-weight: 700;
+}
+
+.console-async-indicator[data-state="partial"] {
+ border-color: #edc87f;
+ background: var(--console-amber-100);
+ color: var(--console-amber-700);
+}
+
+.console-overlay-backdrop {
+ position: fixed;
+ inset: 0;
+ z-index: 100;
+ display: grid;
+ place-items: center;
+ background: rgb(11 17 19 / 48%);
+ padding: var(--console-space-4);
+ backdrop-filter: blur(2px);
+}
+
+.console-overlay-surface {
+ display: grid;
+ width: min(680px, 100%);
+ max-height: min(820px, calc(100dvh - 32px));
+ grid-template-rows: auto minmax(0, 1fr) auto;
+ overflow: hidden;
+ border: 1px solid var(--console-border-strong);
+ border-radius: var(--console-radius-md);
+ background: var(--console-surface-raised);
+ box-shadow: var(--console-shadow-md);
+}
+
+.console-overlay-surface[data-wide="true"] { width: min(960px, 100%); }
+
+.console-overlay-header,
+.console-overlay-footer {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--console-space-3);
+ padding: 13px 15px;
+}
+
+.console-overlay-header { border-bottom: 1px solid var(--console-border); }
+.console-overlay-footer { justify-content: flex-end; border-top: 1px solid var(--console-border); }
+
+.console-overlay-title-stack {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+}
+
+.console-overlay-title-stack h2,
+.console-overlay-title-stack p {
+ min-width: 0;
+ margin: 0;
+}
+
+.console-overlay-title-stack h2 { color: var(--console-graphite-950); font-size: 16px; }
+.console-overlay-title-stack p { color: var(--console-graphite-600); font-size: 12px; line-height: 1.45; }
+
+.console-overlay-body {
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ padding: 15px;
+ overscroll-behavior: contain;
+}
+
+.console-overlay-close {
+ display: inline-grid;
+ width: 32px;
+ height: 32px;
+ flex: 0 0 auto;
+ place-items: center;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-surface-muted);
+ color: var(--console-graphite-700);
+ font-size: 18px;
+ line-height: 1;
+}
+
+.console-drawer-backdrop { place-items: stretch end; padding: 0; }
+.console-drawer {
+ width: min(440px, calc(100vw - 24px));
+ max-height: 100dvh;
+ height: 100dvh;
+ border-block: 0;
+ border-right: 0;
+ border-radius: 0;
+}
+
+.console-drawer[data-placement="left"] { justify-self: start; border-right: 1px solid var(--console-border-strong); border-left: 0; }
+
+.console-popover-anchor { position: relative; display: inline-flex; }
+.console-popover {
+ position: fixed;
+ z-index: 120;
+ width: min(360px, calc(100vw - 24px));
+ max-height: min(520px, calc(100dvh - 24px));
+ overflow: auto;
+ border: 1px solid var(--console-border-strong);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-surface-raised);
+ padding: var(--console-space-3);
+ box-shadow: var(--console-shadow-md);
+}
+
+.content-viewer {
+ display: grid;
+ min-width: 0;
+ min-height: 220px;
+ grid-template-rows: auto minmax(0, 1fr);
+ overflow: hidden;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-surface-raised);
+}
+
+.content-viewer[data-fullscreen="true"] {
+ position: fixed;
+ inset: 12px;
+ z-index: 130;
+ min-height: 0;
+ box-shadow: var(--console-shadow-md);
+}
+
+.content-viewer-toolbar {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: var(--console-space-2);
+ border-bottom: 1px solid var(--console-border);
+ background: var(--console-surface-muted);
+ padding: 7px 9px;
+}
+
+.content-viewer-toolbar strong {
+ margin-right: auto;
+ color: var(--console-graphite-700);
+ font-family: var(--console-font-mono);
+ font-size: 11px;
+ text-transform: uppercase;
+}
+
+.content-viewer-search {
+ width: min(220px, 44vw);
+ min-height: 30px;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-xs);
+ background: #fff;
+ padding: 4px 8px;
+ color: var(--console-graphite-900);
+ font-size: 12px;
+}
+
+.content-viewer-body {
+ min-width: 0;
+ min-height: 0;
+ overflow: auto;
+ background: #f7f8f5;
+ overscroll-behavior: contain;
+}
+
+.content-viewer-pre {
+ min-width: max-content;
+ margin: 0;
+ padding: 13px;
+ color: #243238;
+ font-family: var(--console-font-mono);
+ font-size: 12px;
+ line-height: 1.6;
+ tab-size: 2;
+}
+
+.content-viewer-pre[data-wrap="true"] { min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
+.content-viewer-line { display: block; min-height: 1.6em; }
+.content-viewer-line[data-match="true"] { background: var(--console-amber-100); }
+.content-viewer-line-number { display: inline-block; width: 4ch; margin-right: 12px; color: var(--console-graphite-500); text-align: right; user-select: none; }
+
+.content-viewer-markdown {
+ max-width: 920px;
+ margin: 0 auto;
+ padding: 20px;
+ color: var(--console-graphite-900);
+ font-size: 13px;
+ line-height: 1.65;
+}
+
+.content-viewer-markdown pre,
+.content-viewer-markdown code {
+ font-family: var(--console-font-mono);
+}
+
+.content-viewer-markdown pre {
+ max-width: 100%;
+ overflow: auto;
+ border: 1px solid var(--console-border);
+ border-radius: var(--console-radius-sm);
+ background: #eef1ed;
+ padding: 12px;
+}
+
+.content-viewer-markdown table { display: block; max-width: 100%; overflow: auto; border-collapse: collapse; }
+.content-viewer-markdown th,
+.content-viewer-markdown td { border: 1px solid var(--console-border); padding: 6px 9px; text-align: left; }
+
+:where(button, a, input, select, textarea, [tabindex]):focus-visible {
+ outline: 2px solid var(--console-focus);
+ outline-offset: 2px;
+}
+
+body.console-scroll-locked { overflow: hidden; }
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ clip-path: inset(50%);
+ white-space: nowrap;
+}
+
+.platform-shell {
+ display: grid;
+ width: 100%;
+ height: 100dvh;
+ min-width: 0;
+ min-height: 100vh;
+ grid-template-columns: var(--console-sidebar-width) minmax(0, 1fr);
+ overflow: hidden;
+ background: var(--console-canvas);
+ color: var(--console-graphite-900);
+ font-family: var(--console-font-sans);
+}
+
+.platform-shell.is-sidebar-collapsed {
+ grid-template-columns: var(--console-sidebar-collapsed-width) minmax(0, 1fr);
+}
+
+.platform-sidebar {
+ position: relative;
+ display: flex;
+ width: auto;
+ height: 100dvh;
+ min-width: 0;
+ min-height: 0;
+ flex-direction: column;
+ gap: var(--console-space-5);
+ overflow-x: hidden;
+ overflow-y: auto;
+ border-right: 1px solid #344247;
+ background:
+ linear-gradient(180deg, rgb(0 161 168 / 10%), transparent 180px),
+ var(--console-graphite-950);
+ padding: 16px 12px;
+ color: #e9efed;
+ overscroll-behavior: contain;
+ scrollbar-width: thin;
+}
+
+.platform-sidebar[data-collapsed="true"] {
+ align-items: stretch;
+ padding-inline: 8px;
+}
+
+.brand-lockup {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 11px;
+ padding: 2px 4px 11px;
+ border-bottom: 1px solid rgb(255 255 255 / 10%);
+}
+
+.brand-mark {
+ display: inline-grid;
+ width: 38px;
+ height: 38px;
+ flex: 0 0 auto;
+ place-items: center;
+ border: 1px solid var(--console-cyan-500);
+ border-radius: var(--console-radius-sm);
+ background: var(--console-graphite-1000);
+ color: #baf2ef;
+ font-family: var(--console-font-mono);
+ font-size: 12px;
+ font-weight: 780;
+ letter-spacing: 0.08em;
+ box-shadow: inset 0 0 0 3px rgb(0 161 168 / 8%);
+}
+
+.brand-copy {
+ display: grid;
+ min-width: 0;
+ gap: 1px;
+}
+
+.brand-copy strong,
+.brand-copy small {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.brand-copy strong { color: #fff; font-size: 14px; letter-spacing: 0.14em; }
+.brand-copy small { color: #91a09f; font-family: var(--console-font-mono); font-size: 10px; }
+
+.platform-sidebar[data-collapsed="true"] .brand-copy,
+.platform-sidebar[data-collapsed="true"] .nav-section h2,
+.platform-sidebar[data-collapsed="true"] .nav-label { display: none; }
+
+.platform-sidebar[data-collapsed="true"] .brand-lockup,
+.platform-sidebar[data-collapsed="true"] .nav-item { justify-content: center; }
+
+.nav-groups {
+ display: grid;
+ min-width: 0;
+ align-content: start;
+ gap: 17px;
+}
+
+.nav-section {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+}
+
+.nav-section h2 {
+ margin: 0 0 4px;
+ padding: 0 8px;
+ color: #778886;
+ font-family: var(--console-font-mono);
+ font-size: 9px;
+ font-weight: 720;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+}
+
+.nav-item {
+ display: flex;
+ width: 100%;
+ min-width: 0;
+ min-height: 36px;
+ align-items: center;
+ gap: 9px;
+ border: 1px solid transparent;
+ border-radius: var(--console-radius-sm);
+ background: transparent;
+ padding: 6px 8px;
+ color: #b9c5c3;
+ font-size: 12px;
+ text-align: left;
+}
+
+.nav-item:hover { border-color: rgb(255 255 255 / 8%); background: rgb(255 255 255 / 5%); color: #fff; }
+
+.nav-item[data-active="true"] {
+ border-color: rgb(0 161 168 / 52%);
+ background: linear-gradient(90deg, rgb(0 161 168 / 23%), rgb(0 161 168 / 5%));
+ color: #eafffd;
+ box-shadow: inset 2px 0 0 var(--console-cyan-500);
+}
+
+.nav-icon {
+ display: inline-grid;
+ width: 24px;
+ height: 22px;
+ flex: 0 0 auto;
+ place-items: center;
+ border: 1px solid #46575b;
+ border-radius: var(--console-radius-xs);
+ background: rgb(0 0 0 / 15%);
+ color: #8ed5d4;
+ font-family: var(--console-font-mono);
+ font-size: 9px;
+ font-weight: 760;
+}
+
+.nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+
+.platform-main {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ grid-template-rows: var(--console-topbar-height) minmax(0, 1fr);
+ overflow: hidden;
+}
+
+.platform-topbar {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid var(--console-border);
+ background:
+ linear-gradient(90deg, transparent 0 70%, rgb(0 161 168 / 6%)),
+ color-mix(in srgb, var(--console-surface) 94%, transparent);
+ padding: 0 12px;
+ backdrop-filter: blur(10px);
+}
+
+.platform-content {
+ min-width: 0;
+ min-height: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 14px;
+ overscroll-behavior: contain;
+}
+
+.platform-content > * { min-width: 0; min-height: 0; }
+
+.topbar-status {
+ display: flex;
+ min-width: 0;
+ flex: 1;
+ align-items: center;
+ gap: 9px;
+ color: var(--console-graphite-600);
+ font-family: var(--console-font-mono);
+ font-size: 10px;
+}
+
+.topbar-status::before {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--console-green-700);
+ box-shadow: 0 0 0 3px var(--console-green-100);
+ content: "";
+}
+
+.topbar-status strong {
+ min-width: 0;
+ overflow: hidden;
+ color: var(--console-graphite-900);
+ font-family: var(--console-font-sans);
+ font-size: 12px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.topbar-actions { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 8px; }
+.mobile-sidebar-toggle { display: none; }
+
+.btn,
+.icon-button,
+.table-action {
+ border-radius: var(--console-radius-sm);
+ font-family: var(--console-font-sans);
+ transition: background-color var(--console-duration-fast) ease, border-color var(--console-duration-fast) ease, color var(--console-duration-fast) ease;
+}
+
+.btn-primary {
+ border-color: var(--console-cyan-700);
+ background: var(--console-cyan-700);
+ color: #fff;
+}
+
+.btn-primary:hover { background: #005d63; }
+.btn-secondary,
+.icon-button,
+.table-action { border-color: var(--console-border-strong); background: var(--console-surface-raised); color: var(--console-graphite-700); }
+.btn-secondary:hover,
+.icon-button:hover,
+.table-action:hover { border-color: var(--console-cyan-600); background: var(--console-cyan-100); color: var(--console-cyan-700); }
+
+.input,
+input,
+select,
+textarea {
+ border-color: var(--console-border);
+ border-radius: var(--console-radius-sm);
+ font-family: var(--console-font-sans);
+}
+
+.page-header {
+ display: grid;
+ gap: 5px;
+ padding: 4px 0 16px;
+}
+
+.page-header h1 { color: var(--console-graphite-950); font-size: clamp(22px, 2.5vw, 30px); letter-spacing: -0.025em; }
+.page-eyebrow { color: var(--console-cyan-700); font-family: var(--console-font-mono); letter-spacing: 0.08em; }
+.page-description { color: var(--console-graphite-600); }
+
+.status-badge {
+ border-radius: var(--console-radius-xs);
+ font-family: var(--console-font-mono);
+ letter-spacing: 0.035em;
+}
+
+.auth-main,
+.login-shell {
+ background:
+ linear-gradient(135deg, rgb(0 161 168 / 12%), transparent 45%),
+ repeating-linear-gradient(90deg, transparent 0 39px, rgb(24 34 38 / 4%) 40px),
+ var(--console-canvas);
+}
+
+.login-card {
+ border-color: var(--console-border-strong);
+ border-radius: var(--console-radius-md);
+ background: var(--console-surface);
+ box-shadow: var(--console-shadow-md);
+}
+
+@media (max-width: 720px) {
+ .page-command-bar { grid-template-columns: minmax(0, 1fr); align-items: start; }
+ .page-command-actions { justify-content: flex-start; }
+ .bounded-workspace[data-inspector-open="true"] { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(160px, 40%); }
+ .bounded-workspace-inspector { border-top: 1px solid var(--console-border); border-left: 0; }
+ .resource-collection-items[data-view="cards"] { grid-template-columns: minmax(0, 1fr); }
+ .console-overlay-backdrop { padding: var(--console-space-2); }
+ .console-overlay-surface { max-height: calc(100dvh - 16px); }
+ .content-viewer-toolbar { align-items: stretch; }
+ .content-viewer-search { width: 100%; }
+ .platform-shell,
+ .platform-shell.is-sidebar-collapsed { grid-template-columns: minmax(0, 1fr); }
+ .platform-sidebar { display: none; }
+ .platform-main { height: 100dvh; grid-template-rows: var(--console-topbar-height) minmax(0, 1fr); }
+ .platform-content { min-height: 0; overflow-x: hidden; overflow-y: auto; padding: 10px; }
+ .desktop-sidebar-toggle { display: none; }
+ .mobile-sidebar-toggle { display: inline-flex; }
+ .console-drawer .brand-lockup { border-color: var(--console-border); }
+ .console-drawer .brand-copy strong { color: var(--console-graphite-950); }
+ .console-drawer .brand-copy small { color: var(--console-graphite-600); }
+ .console-drawer .nav-section h2 { color: var(--console-graphite-500); }
+ .console-drawer .nav-item { color: var(--console-graphite-700); }
+ .console-drawer .nav-item:hover { border-color: var(--console-border); background: var(--console-surface-muted); color: var(--console-graphite-950); }
+ .console-drawer .nav-item[data-active="true"] { border-color: var(--console-cyan-200); background: var(--console-cyan-100); color: var(--console-cyan-700); }
+ .console-drawer .nav-icon { border-color: var(--console-border); background: var(--console-surface-muted); color: var(--console-cyan-700); }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .entity-card[data-interactive="true"] { transition: none; }
+ .entity-card[data-interactive="true"]:hover { transform: none; }
+}
diff --git a/web/hwlab-cloud-web/src/styles/console-legacy.css b/web/hwlab-cloud-web/src/styles/console-legacy.css
new file mode 100644
index 00000000..c5a787d5
--- /dev/null
+++ b/web/hwlab-cloud-web/src/styles/console-legacy.css
@@ -0,0 +1,634 @@
+/* SPEC: PJ2026-010405 云端控制台. */
+/* Implementation reference: draft-2026-07-13-p0-cloud-console. */
+.platform-shell {
+ display: grid;
+ height: 100dvh;
+ min-height: 100vh;
+ grid-template-columns: 248px minmax(0, 1fr);
+ overflow: hidden;
+ background: #eef3f8;
+}
+
+.platform-shell.is-sidebar-collapsed {
+ grid-template-columns: 76px minmax(0, 1fr);
+}
+
+.platform-sidebar {
+ position: sticky;
+ top: 0;
+ display: flex;
+ height: 100vh;
+ min-height: 0;
+ flex-direction: column;
+ gap: 20px;
+ border-right: 1px solid #d8e1eb;
+ background: #f8fafc;
+ overflow-x: hidden;
+ overflow-y: auto;
+ overscroll-behavior: contain;
+ padding: 18px 14px;
+ scrollbar-width: none;
+}
+
+.platform-sidebar::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+}
+
+.platform-sidebar[data-collapsed="true"] {
+ width: auto;
+ align-items: center;
+ overflow-x: hidden;
+ padding-right: 8px;
+ padding-left: 8px;
+}
+
+.platform-main {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ grid-template-rows: 44px minmax(0, 1fr);
+}
+
+.platform-topbar {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid #d8e1eb;
+ background: rgba(248, 250, 252, 0.92);
+ padding: 0 12px;
+}
+
+.platform-content {
+ min-height: 0;
+ min-width: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 12px;
+}
+
+.platform-content > * {
+ min-height: 0;
+}
+
+.brand-lockup {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 10px;
+}
+
+.brand-lockup.centered {
+ justify-content: center;
+}
+
+.brand-mark {
+ display: inline-flex;
+ width: 36px;
+ height: 36px;
+ flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ border-radius: 8px;
+ background: #111827;
+ color: #67e8f9;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
+ font-size: 13px;
+ font-weight: 850;
+}
+
+.brand-lockup strong,
+.brand-lockup small {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.brand-lockup small,
+.topbar-status span {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.nav-groups,
+.nav-section,
+.route-stack,
+.workbench-route {
+ display: grid;
+ gap: 16px;
+}
+
+.route-stack {
+ align-content: start;
+ overflow: visible;
+}
+
+.workbench-route {
+ height: 100%;
+ min-height: 0;
+ grid-template-rows: minmax(0, 1fr);
+ gap: 0;
+ overflow: hidden;
+}
+
+.nav-section h2 {
+ margin: 0 0 4px;
+ color: #94a3b8;
+ font-size: 11px;
+ font-weight: 800;
+ letter-spacing: 0;
+ text-transform: uppercase;
+}
+
+.nav-item {
+ display: flex;
+ width: 100%;
+ align-items: center;
+ gap: 10px;
+ border: 0;
+ border-radius: 8px;
+ background: transparent;
+ padding: 9px 10px;
+ color: #334155;
+ text-align: left;
+}
+
+.nav-icon {
+ display: inline-flex;
+ width: 24px;
+ height: 24px;
+ flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ border-radius: 7px;
+ background: #e2e8f0;
+ color: #334155;
+ font-size: 12px;
+ font-weight: 850;
+}
+
+.nav-item[data-active="true"] .nav-icon {
+ background: #bae6fd;
+ color: #075985;
+}
+
+.platform-sidebar[data-collapsed="true"] .brand-lockup div,
+.platform-sidebar[data-collapsed="true"] .nav-section h2,
+.platform-sidebar[data-collapsed="true"] .nav-label {
+ display: none;
+}
+
+.platform-sidebar[data-collapsed="true"] .nav-item {
+ justify-content: center;
+ padding: 9px;
+}
+
+.nav-item[data-active="true"] {
+ background: #e0f2fe;
+ color: #0c4a6e;
+ font-weight: 750;
+}
+
+.nav-dot {
+ width: 8px;
+ height: 8px;
+ flex: 0 0 auto;
+ border-radius: 999px;
+ background: #94a3b8;
+}
+
+.nav-item[data-active="true"] .nav-dot {
+ background: #0891b2;
+}
+
+.topbar-status {
+ display: flex;
+ min-width: 0;
+ flex: 1;
+ align-items: center;
+ gap: 10px;
+}
+
+.topbar-actions {
+ display: inline-flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 8px;
+}
+
+.topbar-progress {
+ display: inline-flex;
+ width: 18px;
+ height: 18px;
+ align-items: center;
+ justify-content: center;
+}
+
+.topbar-progress span {
+ width: 14px;
+ height: 14px;
+ border: 2px solid #bae6fd;
+ border-top-color: #0e7490;
+ border-radius: 999px;
+ animation: workbench-spin 0.8s linear infinite;
+}
+
+@keyframes workbench-spin {
+ to { transform: rotate(360deg); }
+}
+
+.auth-main,
+.login-shell {
+ display: grid;
+ min-height: 100vh;
+ place-items: center;
+ background: #eef3f8;
+ padding: 20px;
+}
+
+.login-card {
+ display: grid;
+ width: min(420px, 100%);
+ gap: 14px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 22px;
+ box-shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
+}
+
+.register-card {
+ width: min(520px, 100%);
+}
+
+.auth-link {
+ color: #0e7490;
+ font-size: 13px;
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.login-card label,
+.settings-grid label {
+ display: grid;
+ gap: 6px;
+ color: #475569;
+ font-size: 13px;
+ font-weight: 650;
+}
+
+.login-note,
+.form-error {
+ margin: 0;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.form-error {
+ color: #b91c1c;
+}
+
+.api-error-diagnostic {
+ display: inline-grid;
+ max-width: min(720px, 100%);
+ width: fit-content;
+ gap: 8px;
+ border-left: 3px solid #b91c1c;
+ background: #f8fafc;
+ padding: 8px 10px;
+ text-align: left;
+}
+
+.empty-state .api-error-diagnostic {
+ max-width: min(760px, 100%);
+ margin: 4px auto 0;
+}
+
+.api-error-diagnostic-summary {
+ display: inline-flex;
+ min-width: 0;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.api-error-diagnostic-summary-text {
+ display: inline-flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: baseline;
+ gap: 4px 8px;
+}
+
+.api-error-diagnostic strong {
+ display: block;
+ color: #991b1b;
+ font-size: 13px;
+}
+
+.api-error-diagnostic p {
+ min-width: 0;
+ margin: 0;
+ overflow-wrap: anywhere;
+ color: #334155;
+ font-size: 13px;
+ line-height: 1.35;
+}
+
+.api-error-diagnostic-toggle {
+ display: inline-flex;
+ width: 22px;
+ height: 22px;
+ flex: 0 0 auto;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid #f59e0b;
+ border-radius: 999px;
+ background: #fff7ed;
+ color: #92400e;
+ cursor: pointer;
+ padding: 0;
+ font-size: 12px;
+ font-weight: 850;
+ line-height: 1;
+}
+
+.api-error-diagnostic-toggle[aria-expanded="true"] {
+ background: #fffbeb;
+ color: #78350f;
+}
+
+.api-error-diagnostic-details {
+ display: grid;
+ gap: 8px;
+ justify-items: start;
+}
+
+.api-error-diagnostic-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+ gap: 8px;
+ margin: 0;
+}
+
+.api-error-diagnostic-grid div {
+ min-width: 0;
+}
+
+.api-error-diagnostic-grid dt,
+.api-error-diagnostic-grid dd {
+ min-width: 0;
+ margin: 0;
+}
+
+.api-error-diagnostic-grid dt {
+ color: #64748b;
+ font-size: 11px;
+ font-weight: 750;
+}
+
+.api-error-diagnostic-grid dd {
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 12px;
+ line-height: 1.45;
+}
+
+.api-error-diagnostic-grid code {
+ white-space: normal;
+}
+
+.workbench-diagnostics-toggle {
+ display: inline-flex;
+ min-height: 32px;
+ align-items: center;
+ gap: 8px;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: white;
+ color: #334155;
+ padding: 4px 8px;
+ font-weight: 800;
+}
+
+.workbench-diagnostics-toggle > span:first-child,
+.message-detail-button {
+ display: inline-flex;
+ width: 22px;
+ height: 22px;
+ align-items: center;
+ justify-content: center;
+ border-radius: 999px;
+ background: #e0f2fe;
+ color: #0c4a6e;
+ font-size: 12px;
+ font-weight: 850;
+}
+
+.workbench-diagnostics-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 10px;
+}
+
+.workbench-diagnostics-summary {
+ display: grid;
+ grid-column: 1 / -1;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8px;
+ margin: 0;
+}
+
+.workbench-diagnostics-summary div {
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 8px;
+}
+
+.workbench-diagnostics-summary dt,
+.workbench-diagnostics-summary dd {
+ min-width: 0;
+ margin: 0;
+ overflow-wrap: anywhere;
+}
+
+.workbench-diagnostics-summary dt {
+ color: #64748b;
+ font-size: 11px;
+ font-weight: 800;
+ text-transform: uppercase;
+}
+
+.workbench-diagnostics-summary dd {
+ color: #0f172a;
+ font-size: 12px;
+ font-weight: 750;
+}
+
+.probe-card,
+.live-build-summary {
+ min-width: min(320px, 100%);
+ flex: 1 1 320px;
+}
+
+.status-chip-button {
+ display: flex;
+ width: 100%;
+ min-height: 42px;
+ min-width: 0;
+ align-items: center;
+ gap: 8px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 8px 10px;
+ color: #334155;
+ text-align: left;
+}
+
+.status-chip-label,
+.status-chip-meta {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.status-chip-label {
+ color: #0f172a;
+ font-size: 12px;
+ font-weight: 800;
+}
+
+.status-chip-meta {
+ margin-left: auto;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.workbench-dialog-backdrop {
+ position: fixed;
+ inset: 0;
+ z-index: 80;
+ display: grid;
+ place-items: center;
+ background: rgba(15, 23, 42, 0.34);
+ padding: 18px;
+}
+
+.workbench-dialog {
+ display: grid;
+ width: min(720px, 100%);
+ max-height: min(760px, calc(100vh - 36px));
+ gap: 12px;
+ overflow: auto;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 16px;
+ box-shadow: 0 20px 45px rgba(15, 23, 42, 0.2);
+}
+
+.workbench-dialog.wide {
+ width: min(920px, 100%);
+}
+
+.workbench-dialog header,
+.hwpod-event-panel header {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+}
+
+.dialog-close {
+ width: 30px;
+ height: 30px;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: #f8fafc;
+ color: #334155;
+ font-weight: 800;
+}
+
+.dialog-title-stack {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+}
+
+.dialog-title-stack h2,
+.dialog-title-stack p {
+ margin: 0;
+}
+
+.dialog-title-stack p {
+ color: #64748b;
+ font-size: 13px;
+}
+
+.dialog-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.probe-list,
+.live-build-list,
+.hwpod-errors ul {
+ display: grid;
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.probe-row,
+.live-build-row,
+.hwpod-errors {
+ display: grid;
+ gap: 8px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.probe-row-head,
+.live-build-row-head {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.probe-row-label,
+.live-build-row strong {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.probe-row-meta,
+.live-build-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.probe-row p,
+.live-build-dialog-summary p,
+.live-build-reason {
+ margin: 0;
+ color: #475569;
+ font-size: 12px;
+ line-height: 1.45;
+}
diff --git a/web/hwlab-cloud-web/src/styles/console-pages.css b/web/hwlab-cloud-web/src/styles/console-pages.css
new file mode 100644
index 00000000..688af6be
--- /dev/null
+++ b/web/hwlab-cloud-web/src/styles/console-pages.css
@@ -0,0 +1,1845 @@
+/* SPEC: PJ2026-010405 云端控制台. */
+/* Implementation reference: draft-2026-07-13-p0-cloud-console. */
+
+.data-panel,
+.empty-state,
+.metric-card {
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
+}
+
+.mini-log,
+.json-panel,
+.help-body {
+ max-height: 420px;
+ overflow: auto;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: #0f172a;
+ color: #dbeafe;
+ padding: 12px;
+ white-space: pre-wrap;
+}
+
+.empty-state {
+ display: grid;
+ align-self: start;
+ justify-items: start;
+ gap: 8px;
+}
+
+.empty-state h2,
+.empty-state p {
+ margin: 0;
+}
+
+.empty-state-mark {
+ display: inline-flex;
+ width: 34px;
+ height: 34px;
+ align-items: center;
+ justify-content: center;
+ border-radius: 8px;
+ background: #e0f2fe;
+ color: #075985;
+ font-weight: 850;
+}
+
+.overview-grid,
+.settings-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.metric-card {
+ display: grid;
+ gap: 6px;
+ padding: 14px;
+}
+
+.metric-card span {
+ color: #64748b;
+ font-size: 13px;
+}
+
+.usage-metrics .metric-card strong {
+ color: #0f172a;
+ font-size: 28px;
+ line-height: 1.15;
+}
+
+.usage-panels {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.usage-panel {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+ overflow: auto;
+}
+
+.admin-crud-panel,
+.table-page-layout {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+}
+
+.table-page-layout {
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
+}
+
+.table-page-header small,
+.panel-header small {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.table-page-actions,
+.table-actions-inline,
+.table-pagination,
+.table-pagination div {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+}
+
+.table-pagination {
+ justify-content: space-between;
+ color: #64748b;
+ font-size: 13px;
+}
+
+.data-table-wrap {
+ max-width: 100%;
+ min-width: 0;
+ overflow-x: auto;
+ overflow-y: hidden;
+ -webkit-overflow-scrolling: touch;
+}
+
+.data-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ overflow: hidden;
+ background: white;
+}
+
+.data-table th,
+.data-table td {
+ border-bottom: 1px solid #e2e8f0;
+ padding: 10px;
+ text-align: left;
+}
+
+.data-table th[data-align="right"],
+.data-table td[data-align="right"] {
+ text-align: right;
+}
+
+.crud-table td {
+ vertical-align: top;
+}
+
+.crud-table small,
+.provider-admin-page small,
+.access-admin-page small {
+ display: block;
+ margin-top: 3px;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.link-button {
+ display: grid;
+ width: 100%;
+ min-width: 0;
+ border: 0;
+ background: transparent;
+ color: #0f172a;
+ cursor: pointer;
+ padding: 0;
+ text-align: left;
+}
+
+.link-button[data-selected="true"] strong {
+ color: #0f766e;
+}
+
+.usage-table th,
+.usage-table td {
+ white-space: nowrap;
+}
+
+.usage-table code {
+ color: #0f766e;
+ font-size: 12px;
+}
+
+.admin-billing-panel {
+ overflow-x: auto;
+}
+
+.admin-billing-table td {
+ vertical-align: top;
+}
+
+.admin-billing-table td > strong,
+.admin-billing-table td > small {
+ display: block;
+}
+
+.admin-billing-table td > small {
+ margin-top: 3px;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.admin-action-error {
+ margin: 0;
+}
+
+.inline-form-row,
+.inline-edit-row,
+.admin-users-filters,
+.pagination-row {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+}
+
+.inline-form-row .input,
+.admin-users-filters .input {
+ min-width: 180px;
+ flex: 1;
+}
+
+.secret-once-box,
+.detail-subpanel {
+ display: grid;
+ min-width: 0;
+ gap: 10px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 12px;
+}
+
+.secret-once-box code {
+ overflow-wrap: anywhere;
+ color: #0f766e;
+}
+
+.admin-users-layout,
+.admin-detail-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.5fr) minmax(320px, 0.85fr);
+ gap: 12px;
+}
+
+.admin-users-list-panel,
+.admin-user-create-panel,
+.admin-user-detail-panel,
+.admin-users-toolbar {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+}
+
+.form-grid {
+ display: grid;
+ min-width: 0;
+ gap: 10px;
+}
+
+.form-grid.two-col {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.form-grid label {
+ display: grid;
+ gap: 6px;
+ color: #475569;
+ font-size: 13px;
+ font-weight: 650;
+}
+
+.span-2 {
+ grid-column: 1 / -1;
+}
+
+.admin-billing-table tr[data-selected="true"] td {
+ background: #f0fdfa;
+}
+
+.table-action {
+ min-width: 64px;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: #f8fafc;
+ color: #0f172a;
+ cursor: pointer;
+ font-size: 12px;
+ font-weight: 750;
+ padding: 7px 10px;
+}
+
+.table-action:hover:not(:disabled) {
+ border-color: #0891b2;
+ color: #0c4a6e;
+}
+
+.table-action.danger:hover:not(:disabled) {
+ border-color: #ef4444;
+ color: #991b1b;
+}
+
+.table-action:disabled {
+ cursor: wait;
+ opacity: 0.55;
+}
+
+.status-pill {
+ display: inline-flex;
+ align-items: center;
+ border: 1px solid #cbd5e1;
+ border-radius: 999px;
+ padding: 3px 8px;
+ background: #f8fafc;
+ color: #334155;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.status-pill[data-status="active"] {
+ border-color: #99f6e4;
+ background: #ccfbf1;
+ color: #0f766e;
+}
+
+.status-pill[data-status="disabled"] {
+ border-color: #fecaca;
+ background: #fee2e2;
+ color: #991b1b;
+}
+
+.status-pill[data-status="admin"],
+.status-pill[data-status="completed"],
+.status-pill[data-status="ready"] {
+ border-color: #bbf7d0;
+ background: #dcfce7;
+ color: #166534;
+}
+
+.status-pill[data-status="failed"],
+.status-pill[data-status="blocked"],
+.status-pill[data-status="error"] {
+ border-color: #fecaca;
+ background: #fee2e2;
+ color: #991b1b;
+}
+
+.status-pill[data-status="dry-run"],
+.status-pill[data-status="planned"],
+.status-pill[data-status="pending"] {
+ border-color: #bae6fd;
+ background: #e0f2fe;
+ color: #075985;
+}
+
+.field-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 10px;
+ margin: 0;
+}
+
+.field-grid div {
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.field-grid dt,
+.field-grid dd {
+ min-width: 0;
+ margin: 0;
+}
+
+.field-grid dt {
+ color: #64748b;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.field-grid dd {
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 13px;
+ font-weight: 750;
+}
+
+.form-grid,
+.admin-form {
+ display: grid;
+ gap: 12px;
+}
+
+.compact-form-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.form-grid label,
+.admin-form label {
+ display: grid;
+ gap: 6px;
+ color: #475569;
+ font-size: 13px;
+ font-weight: 700;
+}
+
+.form-grid select,
+.admin-form input,
+.admin-form select,
+.admin-form textarea {
+ min-width: 0;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: white;
+ color: #0f172a;
+ font: inherit;
+ padding: 9px 10px;
+}
+
+.admin-form textarea {
+ resize: vertical;
+ font-family: "SFMono-Regular", Consolas, monospace;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.form-notice {
+ margin: 0;
+ color: #0f766e;
+ font-size: 12px;
+}
+
+.access-user-head,
+.tool-toggle-grid,
+.tuple-list,
+.provider-validation-panel {
+ display: grid;
+ gap: 10px;
+}
+
+.tool-toggle-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.tool-toggle-row input {
+ width: 18px;
+ height: 18px;
+}
+
+.tuple-list h3 {
+ margin: 0;
+ font-size: 14px;
+}
+
+.tuple-list ul {
+ display: grid;
+ gap: 6px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.tuple-list li {
+ display: grid;
+ grid-template-columns: minmax(0, 1.1fr) auto minmax(0, 1.3fr);
+ gap: 8px;
+ align-items: center;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ padding: 8px;
+}
+
+.tuple-list code,
+.provider-admin-page code {
+ overflow-wrap: anywhere;
+ color: #0f766e;
+ font-size: 12px;
+}
+
+.secrets-admin-page code {
+ overflow-wrap: anywhere;
+ color: #0f766e;
+ font-size: 12px;
+}
+
+.secrets-compact-toolbar,
+.secrets-detail-commandbar {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: #ffffff;
+ padding: 10px 12px;
+}
+
+.secrets-compact-toolbar > div:first-child {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+}
+
+.secrets-compact-toolbar strong {
+ color: #0f172a;
+ font-size: 15px;
+}
+
+.secrets-compact-toolbar small {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.secrets-external-table .data-table {
+ min-width: 980px;
+}
+
+.secrets-external-table .data-table th,
+.secrets-external-table .data-table td {
+ padding: 6px 8px;
+ font-size: 12px;
+ line-height: 1.25;
+ vertical-align: middle;
+}
+
+.secrets-external-table .data-table th {
+ color: #475569;
+ font-size: 11px;
+ letter-spacing: 0;
+}
+
+.secrets-external-table .crud-table small {
+ margin-top: 2px;
+ max-width: 280px;
+ line-height: 1.2;
+}
+
+.secrets-name-link {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+ color: #0f766e;
+ text-decoration: none;
+}
+
+.secrets-name-link:hover strong {
+ text-decoration: underline;
+}
+
+.secrets-detail-status-panel {
+ padding: 12px;
+}
+
+.secrets-status-lines {
+ display: grid;
+ min-height: 78px;
+ min-width: 0;
+ gap: 8px;
+ margin: 0;
+}
+
+.secrets-status-lines div {
+ display: grid;
+ grid-template-columns: 120px minmax(0, 1fr);
+ align-items: center;
+ min-width: 0;
+ gap: 10px;
+}
+
+.secrets-status-lines dt,
+.secrets-status-lines dd {
+ margin: 0;
+ min-width: 0;
+}
+
+.secrets-status-lines dt {
+ color: #64748b;
+ font-size: 12px;
+ font-weight: 750;
+ text-transform: uppercase;
+}
+
+.secrets-status-lines dd {
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 14px;
+ font-weight: 750;
+}
+
+.secrets-segmented-tabs {
+ display: inline-flex;
+ align-items: center;
+ width: fit-content;
+ max-width: 100%;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f8fafc;
+}
+
+.secrets-segmented-tabs button {
+ min-width: 116px;
+ border: 0;
+ border-right: 1px solid #cbd5e1;
+ background: transparent;
+ color: #334155;
+ cursor: pointer;
+ font-size: 12px;
+ font-weight: 800;
+ letter-spacing: 0;
+ padding: 9px 14px;
+}
+
+.secrets-segmented-tabs button:last-child {
+ border-right: 0;
+}
+
+.secrets-segmented-tabs button[data-active="true"] {
+ background: #0f766e;
+ color: white;
+}
+
+.secrets-detail-content {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+}
+
+.secrets-detail-section {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+}
+
+.secrets-detail-fact-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8px;
+ margin: 0;
+}
+
+.secrets-detail-fact-grid div {
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 8px 9px;
+}
+
+.secrets-detail-fact-grid dt,
+.secrets-detail-fact-grid dd {
+ min-width: 0;
+ margin: 0;
+}
+
+.secrets-detail-fact-grid dt {
+ color: #64748b;
+ font-size: 11px;
+ font-weight: 750;
+}
+
+.secrets-detail-fact-grid dd {
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 12px;
+ font-weight: 750;
+}
+
+.secrets-ref-table {
+ display: grid;
+ max-width: 100%;
+ min-width: 0;
+ overflow-x: auto;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+}
+
+.secrets-ref-table [role="row"] {
+ display: grid;
+ min-width: 840px;
+ grid-template-columns: 140px minmax(220px, 1.4fr) 140px 120px minmax(180px, 1fr);
+ border-bottom: 1px solid #e2e8f0;
+}
+
+.secrets-ref-table [role="row"]:last-child {
+ border-bottom: 0;
+}
+
+.secrets-ref-table span {
+ min-width: 0;
+ overflow-wrap: anywhere;
+ padding: 8px 9px;
+ color: #334155;
+ font-size: 12px;
+}
+
+.secrets-ref-head span {
+ background: #f8fafc;
+ color: #64748b;
+ font-size: 11px;
+ font-weight: 800;
+ text-transform: uppercase;
+}
+
+.secrets-resource-event-list {
+ max-height: none;
+}
+
+.secrets-summary-grid,
+.secrets-readiness-grid,
+.secrets-detail-grid {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+}
+
+.secrets-summary-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.secrets-readiness-grid {
+ grid-template-columns: minmax(0, 1fr);
+}
+
+.secrets-detail-grid {
+ grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.75fr);
+}
+
+.secrets-target-panel,
+.secrets-contract-panel,
+.secrets-eso-panel,
+.secrets-rollout-panel {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+}
+
+.secrets-fact-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 10px;
+ margin: 0;
+}
+
+.secrets-fact-grid div {
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.secrets-fact-grid dt,
+.secrets-fact-grid dd {
+ min-width: 0;
+ margin: 0;
+}
+
+.secrets-fact-grid dt {
+ color: #64748b;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.secrets-fact-grid dd {
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 13px;
+ font-weight: 750;
+}
+
+.secrets-subsection {
+ display: grid;
+ min-width: 0;
+ gap: 8px;
+}
+
+.secrets-subsection h3 {
+ margin: 0;
+ color: #334155;
+ font-size: 13px;
+}
+
+.secrets-chip-list {
+ display: grid;
+ min-width: 0;
+ gap: 8px;
+}
+
+.secrets-chip {
+ display: grid;
+ min-width: 0;
+ gap: 3px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 9px 10px;
+}
+
+.secrets-chip strong,
+.secrets-chip small {
+ min-width: 0;
+ overflow-wrap: anywhere;
+}
+
+.secrets-chip small {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.secrets-plan-panel {
+ border-color: #bae6fd;
+ background: #f8fcff;
+}
+
+.secrets-plan-steps {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.secrets-plan-steps li {
+ display: grid;
+ min-width: 0;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 7px;
+ align-items: center;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 8px 10px;
+ color: #334155;
+ font-size: 12px;
+ font-weight: 750;
+}
+
+.secrets-plan-steps strong {
+ display: inline-grid;
+ width: 22px;
+ height: 22px;
+ place-items: center;
+ border-radius: 999px;
+ background: #0f766e;
+ color: white;
+ font-size: 11px;
+}
+
+.secrets-plan-form {
+ gap: 12px;
+}
+
+.secrets-plan-fieldset {
+ display: grid;
+ min-width: 0;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 10px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ margin: 0;
+ padding: 12px;
+}
+
+.secrets-plan-fieldset legend {
+ padding: 0 4px;
+ color: #0f766e;
+ font-size: 12px;
+ font-weight: 800;
+}
+
+.secrets-plan-fieldset input[readonly] {
+ background: #f8fafc;
+ color: #475569;
+}
+
+.secrets-plan-note {
+ margin: 0;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.secrets-plan-toggle {
+ grid-template-columns: auto minmax(0, 1fr);
+ align-items: center;
+ align-self: end;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 9px 10px;
+}
+
+.secrets-plan-toggle input {
+ width: 16px;
+ height: 16px;
+ margin: 0;
+}
+
+.secrets-plan-result {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 12px;
+}
+
+.secrets-plan-result h3 {
+ margin: 0;
+ color: #0f172a;
+ font-size: 14px;
+}
+
+.secrets-plan-result-grid {
+ display: grid;
+ min-width: 0;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.secrets-plan-checks {
+ display: flex;
+ min-width: 0;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.secrets-event-list {
+ display: grid;
+ max-height: 560px;
+ min-width: 0;
+ gap: 8px;
+ margin: 0;
+ overflow: auto;
+ padding: 0;
+ list-style: none;
+}
+
+.secrets-event-list li {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 10px;
+ align-items: start;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.secrets-event-list strong,
+.secrets-event-list p,
+.secrets-event-list small {
+ min-width: 0;
+ overflow-wrap: anywhere;
+}
+
+.secrets-event-list p {
+ margin: 3px 0;
+ color: #334155;
+ font-size: 13px;
+}
+
+.secrets-event-list small {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.toast-host {
+ position: fixed;
+ right: 16px;
+ bottom: 16px;
+ z-index: 50;
+ display: grid;
+ gap: 8px;
+}
+
+.toast-item {
+ max-width: min(380px, calc(100vw - 32px));
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+ background: white;
+ padding: 10px 12px;
+ box-shadow: 0 12px 30px rgba(15, 23, 42, 0.14);
+ text-align: left;
+}
+
+.system-page .data-table td small,
+.provider-admin-page .data-table td small {
+ display: block;
+ margin-top: 3px;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.system-summary-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.system-summary-grid .metric-card {
+ display: grid;
+ gap: 5px;
+ padding: 14px;
+}
+
+.system-summary-grid .metric-card span,
+.rum-bar-row span,
+.skill-tree-list small {
+ color: #64748b;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.system-summary-grid .metric-card strong {
+ min-width: 0;
+ overflow-wrap: anywhere;
+ color: #0f172a;
+ font-size: 20px;
+ line-height: 1.15;
+}
+
+.system-summary-grid .metric-card small {
+ min-width: 0;
+ overflow-wrap: anywhere;
+ color: #64748b;
+ font-size: 12px;
+}
+
+.system-filter-bar {
+ display: grid;
+ grid-template-columns: minmax(140px, 220px) minmax(240px, 1fr);
+ gap: 10px;
+}
+
+.system-filter-bar label {
+ display: grid;
+ gap: 5px;
+ color: #475569;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.system-filter-bar select,
+.system-filter-bar input {
+ min-height: 36px;
+ min-width: 0;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: white;
+ padding: 7px 10px;
+}
+
+.system-row-detail {
+ display: -webkit-box;
+ max-width: 520px;
+ overflow: hidden;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+}
+
+.system-drilldown {
+ display: grid;
+ gap: 8px;
+}
+
+.system-drilldown h3,
+.system-drilldown p {
+ margin: 0;
+}
+
+.system-drilldown h3 {
+ font-size: 13px;
+}
+
+.system-drilldown ul,
+.skill-tree-list {
+ display: grid;
+ gap: 6px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.system-drilldown li,
+.skill-tree-list li {
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 8px;
+}
+
+.rum-chart-panel {
+ display: grid;
+ gap: 10px;
+ padding: 14px;
+}
+
+.rum-bar-row {
+ display: grid;
+ grid-template-columns: minmax(100px, 160px) minmax(0, 1fr) 48px;
+ align-items: center;
+ gap: 10px;
+}
+
+.rum-bar-row div {
+ height: 10px;
+ overflow: hidden;
+ border-radius: 999px;
+ background: #e2e8f0;
+}
+
+.rum-bar-row i {
+ display: block;
+ height: 100%;
+ border-radius: inherit;
+ background: #0e7490;
+}
+
+.rum-bar-row strong {
+ text-align: right;
+}
+
+.performance-window-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ flex-wrap: wrap;
+}
+
+.performance-window-tabs {
+ display: inline-flex;
+ align-items: center;
+ gap: 2px;
+ padding: 3px;
+ border: 1px solid #cbd5e1;
+ background: #f8fafc;
+ border-radius: 8px;
+}
+
+.performance-window-tabs button {
+ min-width: 56px;
+ height: 30px;
+ padding: 0 10px;
+ border: 0;
+ border-radius: 6px;
+ background: transparent;
+ color: #475569;
+ font-size: 0.82rem;
+ font-weight: 650;
+ cursor: pointer;
+}
+
+.performance-window-tabs button[data-selected="true"] {
+ background: #fff;
+ color: #0f172a;
+ box-shadow: 0 1px 3px rgba(15, 23, 42, 0.14);
+}
+
+.performance-window-toolbar > span {
+ color: #64748b;
+ font-size: 0.86rem;
+ font-weight: 650;
+}
+
+.performance-health-strip {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.performance-health-card {
+ min-height: 112px;
+ border-left: 4px solid #64748b;
+}
+
+.performance-health-card.is-ok {
+ border-left-color: #0f766e;
+}
+
+.performance-health-card.is-warn {
+ border-left-color: #b45309;
+}
+
+.performance-health-card.is-blocked {
+ border-left-color: #b91c1c;
+}
+
+.performance-contract-strip {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 10px;
+ border: 1px solid #dbe3ef;
+ border-radius: 8px;
+ background: #ffffff;
+ padding: 12px;
+}
+
+.performance-contract-item {
+ display: grid;
+ min-width: 0;
+ gap: 4px;
+ border-left: 3px solid #0e7490;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.performance-contract-item span,
+.performance-contract-item small,
+.performance-row-contract {
+ min-width: 0;
+ overflow: hidden;
+ color: #64748b;
+ font-size: 12px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-contract-item strong {
+ min-width: 0;
+ overflow: hidden;
+ color: #0f172a;
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-row-contract {
+ display: block;
+ margin-top: 4px;
+}
+
+.performance-freshness-panel {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ align-items: center;
+ gap: 12px;
+ border: 1px solid #dbe3ef;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 12px 14px;
+}
+
+.performance-freshness-panel div {
+ display: grid;
+ gap: 3px;
+ min-width: 0;
+}
+
+.performance-freshness-panel strong {
+ color: #0f172a;
+ font-size: 14px;
+}
+
+.performance-freshness-panel span,
+.performance-chart-card header span,
+.performance-top-row span,
+.performance-chart-legend span {
+ color: #64748b;
+ font-size: 12px;
+}
+
+.performance-collection-strip {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 10px;
+}
+
+.performance-collection-item {
+ display: grid;
+ min-width: 0;
+ gap: 4px;
+ border: 1px solid #dbe3ef;
+ border-left: 3px solid #475569;
+ border-radius: 8px;
+ background: #ffffff;
+ padding: 10px;
+}
+
+.performance-collection-item span,
+.performance-collection-item small,
+.performance-collection-diagnostics small {
+ min-width: 0;
+ overflow: hidden;
+ color: #64748b;
+ font-size: 12px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-collection-item strong,
+.performance-collection-diagnostics strong {
+ min-width: 0;
+ overflow: hidden;
+ color: #0f172a;
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-collection-diagnostics {
+ display: grid;
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.performance-collection-diagnostics li {
+ display: grid;
+ grid-template-columns: minmax(120px, 0.28fr) minmax(0, 1fr);
+ gap: 10px;
+ align-items: center;
+ border: 1px solid #dbe3ef;
+ border-left: 3px solid #64748b;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 9px 10px;
+}
+
+.performance-collection-diagnostics li.is-ok {
+ border-left-color: #0f766e;
+}
+
+.performance-collection-diagnostics li.is-warn {
+ border-left-color: #b45309;
+}
+
+.performance-collection-diagnostics li.is-blocked {
+ border-left-color: #b91c1c;
+}
+
+.performance-diagnostic-panel {
+ padding: 18px;
+}
+
+.performance-chart-grid,
+.performance-analytics-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 14px;
+}
+
+.performance-chart-card {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ border: 1px solid #dbe3ef;
+ border-radius: 8px;
+ background: #ffffff;
+ padding: 14px;
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
+}
+
+.performance-chart-card header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+ min-width: 0;
+}
+
+.performance-chart-card header div {
+ display: grid;
+ gap: 3px;
+ min-width: 0;
+}
+
+.performance-chart-card header strong {
+ color: #0f172a;
+ font-size: 14px;
+}
+
+.performance-chart-card header em {
+ flex: 0 0 auto;
+ border: 1px solid #cbd5e1;
+ border-radius: 999px;
+ color: #475569;
+ font-size: 12px;
+ font-style: normal;
+ line-height: 1;
+ padding: 5px 8px;
+}
+
+.performance-line-chart {
+ width: 100%;
+ height: 150px;
+ overflow: visible;
+}
+
+.chart-grid-line {
+ fill: none;
+ stroke: #e2e8f0;
+ stroke-width: 1;
+}
+
+.chart-line {
+ fill: none;
+ stroke: #0f766e;
+ stroke-width: 3;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.chart-point {
+ fill: #64748b;
+ stroke: #ffffff;
+ stroke-width: 2;
+}
+
+.chart-point.is-ok,
+.performance-bar-row i.is-ok,
+.performance-top-row i.is-ok {
+ fill: #0f766e;
+ background: #0f766e;
+}
+
+.chart-point.is-warn,
+.performance-bar-row i.is-warn,
+.performance-top-row i.is-warn {
+ fill: #b45309;
+ background: #b45309;
+}
+
+.chart-point.is-blocked,
+.performance-bar-row i.is-blocked,
+.performance-top-row i.is-blocked {
+ fill: #b91c1c;
+ background: #b91c1c;
+}
+
+.performance-chart-legend {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.performance-chart-legend li {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+ border-top: 1px solid #e2e8f0;
+ padding-top: 8px;
+}
+
+.performance-chart-legend strong {
+ color: #0f172a;
+ font-size: 13px;
+}
+
+.performance-bar-list,
+.performance-top-list {
+ display: grid;
+ gap: 10px;
+}
+
+.performance-bar-row {
+ display: grid;
+ grid-template-columns: minmax(80px, 128px) minmax(0, 1fr) 48px;
+ align-items: center;
+ gap: 10px;
+}
+
+.performance-bar-row > span {
+ min-width: 0;
+ overflow: hidden;
+ color: #334155;
+ font-size: 12px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-bar-row div,
+.performance-top-row > div:nth-child(2) {
+ height: 9px;
+ overflow: hidden;
+ border-radius: 999px;
+ background: #e2e8f0;
+}
+
+.performance-bar-row i,
+.performance-top-row i {
+ display: block;
+ height: 100%;
+ min-width: 6px;
+ border-radius: inherit;
+ background: #64748b;
+}
+
+.performance-bar-row strong {
+ color: #0f172a;
+ font-size: 12px;
+ text-align: right;
+}
+
+.performance-top-row {
+ display: grid;
+ grid-template-columns: minmax(0, 1.4fr) minmax(96px, 0.8fr) minmax(70px, auto);
+ align-items: center;
+ gap: 10px;
+}
+
+.performance-top-row > div:first-child {
+ display: grid;
+ min-width: 0;
+ gap: 2px;
+}
+
+.performance-top-row strong,
+.performance-top-row span {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.performance-top-row > div:first-child strong {
+ color: #0f172a;
+ font-size: 12px;
+}
+
+.performance-top-row em {
+ color: #0f172a;
+ font-size: 12px;
+ font-style: normal;
+ text-align: right;
+}
+
+.system-split-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 14px;
+}
+
+.hwpod-groups-section,
+.hwpod-raw-panel {
+ display: grid;
+ min-width: 0;
+ gap: 12px;
+ padding: 14px;
+}
+
+.hwpod-node-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+ gap: 10px;
+}
+
+.hwpod-node-row {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 6px 10px;
+ min-width: 0;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 10px;
+}
+
+.hwpod-node-row strong,
+.hwpod-node-row small,
+.hwpod-node-row code {
+ min-width: 0;
+ overflow-wrap: anywhere;
+}
+
+.hwpod-node-row small,
+.hwpod-node-row code {
+ grid-column: 1 / -1;
+ color: #475569;
+}
+
+.hwpod-op-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.hwpod-op-list code {
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: #f8fafc;
+ padding: 5px 8px;
+ font-size: 12px;
+}
+
+.hwpod-blocker {
+ color: #7f1d1d;
+}
+
+.performance-wide-panel {
+ grid-column: 1 / -1;
+}
+
+.performance-page .table-page-layout {
+ overflow: hidden;
+}
+
+.performance-page .data-table-wrap {
+ border: 1px solid #d8e1eb;
+ border-radius: 8px;
+}
+
+.performance-page .data-table {
+ width: max-content;
+ min-width: 780px;
+ border: 0;
+}
+
+.performance-page .data-table th,
+.performance-page .data-table td {
+ white-space: nowrap;
+}
+
+.performance-page .performance-dimensions {
+ min-width: 220px;
+ white-space: normal;
+}
+
+.performance-dimensions {
+ display: block;
+ max-width: 360px;
+ min-width: 0;
+ overflow-wrap: anywhere;
+ color: #334155;
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+.skills-tree-panel,
+.skills-preview-panel {
+ display: grid;
+ align-content: start;
+ gap: 12px;
+ padding: 14px;
+}
+
+.skill-tree-list {
+ max-height: 420px;
+ overflow: auto;
+}
+
+.skill-tree-list li {
+ display: grid;
+ grid-template-columns: 48px minmax(0, 1fr) auto;
+ align-items: center;
+ gap: 8px;
+}
+
+.skill-tree-list button {
+ min-height: 26px;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ background: white;
+ color: #334155;
+ font-size: 11px;
+ font-weight: 800;
+ text-transform: uppercase;
+}
+
+.skill-tree-list button:disabled {
+ color: #94a3b8;
+}
+
+.skill-tree-list span {
+ min-width: 0;
+ overflow-wrap: anywhere;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
+ font-size: 12px;
+}
+
+.skills-preview-panel .mini-log {
+ max-height: 460px;
+ min-height: 240px;
+ overflow: auto;
+ white-space: pre-wrap;
+}
+
+@media (max-width: 1180px) {
+ .platform-shell {
+ grid-template-columns: 76px minmax(0, 1fr);
+ }
+
+ .platform-sidebar {
+ padding: 14px 8px;
+ }
+
+ .platform-sidebar .brand-lockup div,
+ .nav-section h2,
+ .nav-label {
+ display: none;
+ }
+
+ .overview-grid,
+ .settings-grid,
+ .usage-panels,
+ .admin-users-layout,
+ .admin-detail-grid,
+ .system-summary-grid,
+ .system-split-grid,
+ .performance-health-strip,
+ .performance-contract-strip,
+ .performance-collection-strip,
+ .performance-chart-grid,
+ .performance-analytics-grid,
+ .secrets-summary-grid,
+ .secrets-readiness-grid,
+ .secrets-detail-grid,
+ .secrets-plan-fieldset,
+ .secrets-plan-result-grid,
+ .field-grid,
+ .form-grid.two-col,
+ .compact-form-grid,
+ .secrets-detail-fact-grid,
+ .secrets-fact-grid,
+ .secrets-plan-steps {
+ grid-template-columns: 1fr;
+ }
+
+ .secrets-status-lines div {
+ grid-template-columns: 1fr;
+ gap: 4px;
+ }
+
+ .secrets-segmented-tabs {
+ display: flex;
+ width: 100%;
+ }
+
+ .secrets-segmented-tabs button {
+ flex: 1;
+ min-width: 0;
+ }
+}
+
+@media (max-width: 720px) {
+ .platform-shell {
+ height: 100dvh;
+ min-height: 100dvh;
+ grid-template-columns: minmax(0, 1fr);
+ overflow: hidden;
+ }
+
+ .platform-sidebar {
+ display: none;
+ }
+
+ .platform-main {
+ height: 100dvh;
+ min-height: 0;
+ grid-template-rows: 44px minmax(0, 1fr);
+ }
+
+ .platform-content {
+ min-height: 0;
+ padding: 12px;
+ overflow: hidden;
+ }
+
+ .platform-topbar {
+ min-width: 0;
+ gap: 8px;
+ padding: 0 10px;
+ }
+
+ .topbar-status {
+ gap: 6px;
+ }
+
+ .topbar-status strong {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .system-filter-bar,
+ .rum-bar-row,
+ .performance-freshness-panel,
+ .performance-collection-diagnostics li,
+ .performance-bar-row,
+ .performance-top-row,
+ .skill-tree-list li {
+ grid-template-columns: 1fr;
+ }
+
+ .performance-health-card {
+ min-height: 92px;
+ }
+
+ .performance-chart-card header,
+ .performance-freshness-panel {
+ align-items: stretch;
+ }
+
+ .performance-chart-card header,
+ .performance-freshness-panel,
+ .performance-collection-diagnostics li,
+ .performance-top-row {
+ gap: 8px;
+ }
+
+ .performance-chart-legend {
+ grid-template-columns: 1fr;
+ }
+
+ .performance-line-chart {
+ height: 128px;
+ }
+
+ .performance-top-row em {
+ text-align: left;
+ }
+}
diff --git a/web/hwlab-cloud-web/src/styles/tokens.css b/web/hwlab-cloud-web/src/styles/tokens.css
new file mode 100644
index 00000000..23cec6b8
--- /dev/null
+++ b/web/hwlab-cloud-web/src/styles/tokens.css
@@ -0,0 +1,62 @@
+/* SPEC: PJ2026-010405 云端控制台. */
+/* Implementation reference: draft-2026-07-13-p0-cloud-console. */
+
+:root {
+ color-scheme: light;
+ --console-font-sans: "IBM Plex Sans", "Noto Sans SC", "Source Han Sans SC", "Segoe UI", sans-serif;
+ --console-font-mono: "IBM Plex Mono", "Cascadia Code", "SFMono-Regular", Consolas, monospace;
+ --console-graphite-1000: #0b1113;
+ --console-graphite-950: #11191c;
+ --console-graphite-900: #182226;
+ --console-graphite-800: #253237;
+ --console-graphite-700: #39484d;
+ --console-graphite-600: #546267;
+ --console-graphite-500: #748186;
+ --console-graphite-300: #b9c2c3;
+ --console-graphite-200: #d4dbda;
+ --console-graphite-100: #e8ecea;
+ --console-canvas: #e6ebe8;
+ --console-surface: #fbfaf5;
+ --console-surface-raised: #ffffff;
+ --console-surface-muted: #f1f3ef;
+ --console-cyan-700: #006d73;
+ --console-cyan-600: #00838a;
+ --console-cyan-500: #00a1a8;
+ --console-cyan-200: #9edee0;
+ --console-cyan-100: #dff3f2;
+ --console-amber-700: #8a5200;
+ --console-amber-500: #d79216;
+ --console-amber-100: #fff1cf;
+ --console-red-700: #9b302c;
+ --console-red-100: #fee8e5;
+ --console-green-700: #346a45;
+ --console-green-100: #e1f2e5;
+ --console-focus: #00a1a8;
+ --console-border: #cbd3d1;
+ --console-border-strong: #aab7b5;
+ --console-shadow-sm: 0 1px 2px rgb(11 17 19 / 8%);
+ --console-shadow-md: 0 16px 44px rgb(11 17 19 / 18%);
+ --console-radius-xs: 3px;
+ --console-radius-sm: 6px;
+ --console-radius-md: 10px;
+ --console-radius-lg: 14px;
+ --console-space-1: 4px;
+ --console-space-2: 8px;
+ --console-space-3: 12px;
+ --console-space-4: 16px;
+ --console-space-5: 20px;
+ --console-space-6: 24px;
+ --console-duration-fast: 120ms;
+ --console-duration-normal: 180ms;
+ --console-sidebar-width: 264px;
+ --console-sidebar-collapsed-width: 72px;
+ --console-topbar-height: 48px;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ :root {
+ scroll-behavior: auto;
+ --console-duration-fast: 0ms;
+ --console-duration-normal: 0ms;
+ }
+}
diff --git a/web/hwlab-cloud-web/src/styles/workbench.css b/web/hwlab-cloud-web/src/styles/workbench.css
index d7d278a5..5b47d691 100644
--- a/web/hwlab-cloud-web/src/styles/workbench.css
+++ b/web/hwlab-cloud-web/src/styles/workbench.css
@@ -1,636 +1,5 @@
-/* SPEC: PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. */
-.platform-shell {
- display: grid;
- height: 100dvh;
- min-height: 100vh;
- grid-template-columns: 248px minmax(0, 1fr);
- overflow: hidden;
- background: #eef3f8;
-}
-
-.platform-shell.is-sidebar-collapsed {
- grid-template-columns: 76px minmax(0, 1fr);
-}
-
-.platform-sidebar {
- position: sticky;
- top: 0;
- display: flex;
- height: 100vh;
- min-height: 0;
- flex-direction: column;
- gap: 20px;
- border-right: 1px solid #d8e1eb;
- background: #f8fafc;
- overflow-x: hidden;
- overflow-y: auto;
- overscroll-behavior: contain;
- padding: 18px 14px;
- scrollbar-width: none;
-}
-
-.platform-sidebar::-webkit-scrollbar {
- width: 0;
- height: 0;
-}
-
-.platform-sidebar[data-collapsed="true"] {
- width: auto;
- align-items: center;
- overflow-x: hidden;
- padding-right: 8px;
- padding-left: 8px;
-}
-
-.platform-main {
- display: grid;
- min-width: 0;
- min-height: 0;
- grid-template-rows: 44px minmax(0, 1fr);
-}
-
-.platform-topbar {
- display: flex;
- align-items: center;
- gap: 10px;
- border-bottom: 1px solid #d8e1eb;
- background: rgba(248, 250, 252, 0.92);
- padding: 0 12px;
-}
-
-.platform-content {
- min-height: 0;
- min-width: 0;
- overflow-x: hidden;
- overflow-y: auto;
- padding: 12px;
-}
-
-.platform-content > * {
- min-height: 0;
-}
-
-.brand-lockup {
- display: flex;
- min-width: 0;
- align-items: center;
- gap: 10px;
-}
-
-.brand-lockup.centered {
- justify-content: center;
-}
-
-.brand-mark {
- display: inline-flex;
- width: 36px;
- height: 36px;
- flex: 0 0 auto;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- background: #111827;
- color: #67e8f9;
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
- font-size: 13px;
- font-weight: 850;
-}
-
-.brand-lockup strong,
-.brand-lockup small {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.brand-lockup small,
-.topbar-status span {
- color: #64748b;
- font-size: 12px;
-}
-
-.nav-groups,
-.nav-section,
-.route-stack,
-.workbench-route {
- display: grid;
- gap: 16px;
-}
-
-.route-stack {
- align-content: start;
- overflow: visible;
-}
-
-.workbench-route {
- height: 100%;
- min-height: 0;
- grid-template-rows: minmax(0, 1fr);
- gap: 0;
- overflow: hidden;
-}
-
-.nav-section h2 {
- margin: 0 0 4px;
- color: #94a3b8;
- font-size: 11px;
- font-weight: 800;
- letter-spacing: 0;
- text-transform: uppercase;
-}
-
-.nav-item {
- display: flex;
- width: 100%;
- align-items: center;
- gap: 10px;
- border: 0;
- border-radius: 8px;
- background: transparent;
- padding: 9px 10px;
- color: #334155;
- text-align: left;
-}
-
-.nav-icon {
- display: inline-flex;
- width: 24px;
- height: 24px;
- flex: 0 0 auto;
- align-items: center;
- justify-content: center;
- border-radius: 7px;
- background: #e2e8f0;
- color: #334155;
- font-size: 12px;
- font-weight: 850;
-}
-
-.nav-item[data-active="true"] .nav-icon {
- background: #bae6fd;
- color: #075985;
-}
-
-.platform-sidebar[data-collapsed="true"] .brand-lockup div,
-.platform-sidebar[data-collapsed="true"] .nav-section h2,
-.platform-sidebar[data-collapsed="true"] .nav-label {
- display: none;
-}
-
-.platform-sidebar[data-collapsed="true"] .nav-item {
- justify-content: center;
- padding: 9px;
-}
-
-.nav-item[data-active="true"] {
- background: #e0f2fe;
- color: #0c4a6e;
- font-weight: 750;
-}
-
-.nav-dot {
- width: 8px;
- height: 8px;
- flex: 0 0 auto;
- border-radius: 999px;
- background: #94a3b8;
-}
-
-.nav-item[data-active="true"] .nav-dot {
- background: #0891b2;
-}
-
-.topbar-status {
- display: flex;
- min-width: 0;
- flex: 1;
- align-items: center;
- gap: 10px;
-}
-
-.topbar-actions {
- display: inline-flex;
- flex: 0 0 auto;
- align-items: center;
- gap: 8px;
-}
-
-.topbar-progress {
- display: inline-flex;
- width: 18px;
- height: 18px;
- align-items: center;
- justify-content: center;
-}
-
-.topbar-progress span {
- width: 14px;
- height: 14px;
- border: 2px solid #bae6fd;
- border-top-color: #0e7490;
- border-radius: 999px;
- animation: workbench-spin 0.8s linear infinite;
-}
-
-@keyframes workbench-spin {
- to { transform: rotate(360deg); }
-}
-
-.auth-main,
-.login-shell {
- display: grid;
- min-height: 100vh;
- place-items: center;
- background: #eef3f8;
- padding: 20px;
-}
-
-.login-card {
- display: grid;
- width: min(420px, 100%);
- gap: 14px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 22px;
- box-shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
-}
-
-.register-card {
- width: min(520px, 100%);
-}
-
-.auth-link {
- color: #0e7490;
- font-size: 13px;
- font-weight: 700;
- text-decoration: none;
-}
-
-.login-card label,
-.settings-grid label {
- display: grid;
- gap: 6px;
- color: #475569;
- font-size: 13px;
- font-weight: 650;
-}
-
-.login-note,
-.form-error {
- margin: 0;
- font-size: 12px;
- line-height: 1.5;
-}
-
-.form-error {
- color: #b91c1c;
-}
-
-.api-error-diagnostic {
- display: inline-grid;
- max-width: min(720px, 100%);
- width: fit-content;
- gap: 8px;
- border-left: 3px solid #b91c1c;
- background: #f8fafc;
- padding: 8px 10px;
- text-align: left;
-}
-
-.empty-state .api-error-diagnostic {
- max-width: min(760px, 100%);
- margin: 4px auto 0;
-}
-
-.api-error-diagnostic-summary {
- display: inline-flex;
- min-width: 0;
- align-items: center;
- justify-content: space-between;
- gap: 8px;
-}
-
-.api-error-diagnostic-summary-text {
- display: inline-flex;
- min-width: 0;
- flex-wrap: wrap;
- align-items: baseline;
- gap: 4px 8px;
-}
-
-.api-error-diagnostic strong {
- display: block;
- color: #991b1b;
- font-size: 13px;
-}
-
-.api-error-diagnostic p {
- min-width: 0;
- margin: 0;
- overflow-wrap: anywhere;
- color: #334155;
- font-size: 13px;
- line-height: 1.35;
-}
-
-.api-error-diagnostic-toggle {
- display: inline-flex;
- width: 22px;
- height: 22px;
- flex: 0 0 auto;
- align-items: center;
- justify-content: center;
- border: 1px solid #f59e0b;
- border-radius: 999px;
- background: #fff7ed;
- color: #92400e;
- cursor: pointer;
- padding: 0;
- font-size: 12px;
- font-weight: 850;
- line-height: 1;
-}
-
-.api-error-diagnostic-toggle[aria-expanded="true"] {
- background: #fffbeb;
- color: #78350f;
-}
-
-.api-error-diagnostic-details {
- display: grid;
- gap: 8px;
- justify-items: start;
-}
-
-.api-error-diagnostic-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
- gap: 8px;
- margin: 0;
-}
-
-.api-error-diagnostic-grid div {
- min-width: 0;
-}
-
-.api-error-diagnostic-grid dt,
-.api-error-diagnostic-grid dd {
- min-width: 0;
- margin: 0;
-}
-
-.api-error-diagnostic-grid dt {
- color: #64748b;
- font-size: 11px;
- font-weight: 750;
-}
-
-.api-error-diagnostic-grid dd {
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 12px;
- line-height: 1.45;
-}
-
-.api-error-diagnostic-grid code {
- white-space: normal;
-}
-
-.workbench-diagnostics-toggle {
- display: inline-flex;
- min-height: 32px;
- align-items: center;
- gap: 8px;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: white;
- color: #334155;
- padding: 4px 8px;
- font-weight: 800;
-}
-
-.workbench-diagnostics-toggle > span:first-child,
-.message-detail-button {
- display: inline-flex;
- width: 22px;
- height: 22px;
- align-items: center;
- justify-content: center;
- border-radius: 999px;
- background: #e0f2fe;
- color: #0c4a6e;
- font-size: 12px;
- font-weight: 850;
-}
-
-.workbench-diagnostics-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 10px;
-}
-
-.workbench-diagnostics-summary {
- display: grid;
- grid-column: 1 / -1;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 8px;
- margin: 0;
-}
-
-.workbench-diagnostics-summary div {
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 8px;
-}
-
-.workbench-diagnostics-summary dt,
-.workbench-diagnostics-summary dd {
- min-width: 0;
- margin: 0;
- overflow-wrap: anywhere;
-}
-
-.workbench-diagnostics-summary dt {
- color: #64748b;
- font-size: 11px;
- font-weight: 800;
- text-transform: uppercase;
-}
-
-.workbench-diagnostics-summary dd {
- color: #0f172a;
- font-size: 12px;
- font-weight: 750;
-}
-
-.probe-card,
-.live-build-summary {
- min-width: min(320px, 100%);
- flex: 1 1 320px;
-}
-
-.status-chip-button {
- display: flex;
- width: 100%;
- min-height: 42px;
- min-width: 0;
- align-items: center;
- gap: 8px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 8px 10px;
- color: #334155;
- text-align: left;
-}
-
-.status-chip-label,
-.status-chip-meta {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.status-chip-label {
- color: #0f172a;
- font-size: 12px;
- font-weight: 800;
-}
-
-.status-chip-meta {
- margin-left: auto;
- color: #64748b;
- font-size: 12px;
-}
-
-.workbench-dialog-backdrop {
- position: fixed;
- inset: 0;
- z-index: 80;
- display: grid;
- place-items: center;
- background: rgba(15, 23, 42, 0.34);
- padding: 18px;
-}
-
-.workbench-dialog {
- display: grid;
- width: min(720px, 100%);
- max-height: min(760px, calc(100vh - 36px));
- gap: 12px;
- overflow: auto;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 16px;
- box-shadow: 0 20px 45px rgba(15, 23, 42, 0.2);
-}
-
-.workbench-dialog.wide {
- width: min(920px, 100%);
-}
-
-.workbench-dialog header,
-.hwpod-event-panel header {
- display: flex;
- min-width: 0;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
-}
-
-.dialog-close {
- width: 30px;
- height: 30px;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: #f8fafc;
- color: #334155;
- font-weight: 800;
-}
-
-.dialog-title-stack {
- display: grid;
- min-width: 0;
- gap: 3px;
-}
-
-.dialog-title-stack h2,
-.dialog-title-stack p {
- margin: 0;
-}
-
-.dialog-title-stack p {
- color: #64748b;
- font-size: 13px;
-}
-
-.dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 8px;
-}
-
-.probe-list,
-.live-build-list,
-.hwpod-errors ul {
- display: grid;
- gap: 8px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.probe-row,
-.live-build-row,
-.hwpod-errors {
- display: grid;
- gap: 8px;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.probe-row-head,
-.live-build-row-head {
- display: flex;
- min-width: 0;
- align-items: center;
- justify-content: space-between;
- gap: 8px;
-}
-
-.probe-row-label,
-.live-build-row strong {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.probe-row-meta,
-.live-build-meta {
- display: flex;
- flex-wrap: wrap;
- gap: 6px;
- color: #64748b;
- font-size: 12px;
-}
-
-.probe-row p,
-.live-build-dialog-summary p,
-.live-build-reason {
- margin: 0;
- color: #475569;
- font-size: 12px;
- line-height: 1.45;
-}
+/* SPEC: PJ2026-010401 Web工作台; PJ2026-010405 云端控制台. */
+/* Responsibility: Workbench-only layout, projection, trace and composer styling. */
.workbench-grid {
display: grid;
@@ -644,9 +13,6 @@
.session-rail,
.hwpod-panel,
.caserun-panel,
-.data-panel,
-.empty-state,
-.metric-card,
.message-card {
border: 1px solid #d8e1eb;
border-radius: 8px;
@@ -2131,1739 +1497,7 @@
font-size: 12px;
}
-.mini-log,
-.json-panel,
-.help-body {
- max-height: 420px;
- overflow: auto;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: #0f172a;
- color: #dbeafe;
- padding: 12px;
- white-space: pre-wrap;
-}
-
-.empty-state {
- display: grid;
- align-self: start;
- justify-items: start;
- gap: 8px;
-}
-
-.empty-state h2,
-.empty-state p {
- margin: 0;
-}
-
-.empty-state-mark {
- display: inline-flex;
- width: 34px;
- height: 34px;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- background: #e0f2fe;
- color: #075985;
- font-weight: 850;
-}
-
-.overview-grid,
-.settings-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 12px;
-}
-
-.metric-card {
- display: grid;
- gap: 6px;
- padding: 14px;
-}
-
-.metric-card span {
- color: #64748b;
- font-size: 13px;
-}
-
-.usage-metrics .metric-card strong {
- color: #0f172a;
- font-size: 28px;
- line-height: 1.15;
-}
-
-.usage-panels {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 12px;
-}
-
-.usage-panel {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
- overflow: auto;
-}
-
-.admin-crud-panel,
-.table-page-layout {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
-}
-
-.table-page-layout {
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
-}
-
-.table-page-header small,
-.panel-header small {
- color: #64748b;
- font-size: 12px;
-}
-
-.table-page-actions,
-.table-actions-inline,
-.table-pagination,
-.table-pagination div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 8px;
-}
-
-.table-pagination {
- justify-content: space-between;
- color: #64748b;
- font-size: 13px;
-}
-
-.data-table-wrap {
- max-width: 100%;
- min-width: 0;
- overflow-x: auto;
- overflow-y: hidden;
- -webkit-overflow-scrolling: touch;
-}
-
-.data-table {
- width: 100%;
- border-collapse: collapse;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- overflow: hidden;
- background: white;
-}
-
-.data-table th,
-.data-table td {
- border-bottom: 1px solid #e2e8f0;
- padding: 10px;
- text-align: left;
-}
-
-.data-table th[data-align="right"],
-.data-table td[data-align="right"] {
- text-align: right;
-}
-
-.crud-table td {
- vertical-align: top;
-}
-
-.crud-table small,
-.provider-admin-page small,
-.access-admin-page small {
- display: block;
- margin-top: 3px;
- color: #64748b;
- font-size: 12px;
-}
-
-.link-button {
- display: grid;
- width: 100%;
- min-width: 0;
- border: 0;
- background: transparent;
- color: #0f172a;
- cursor: pointer;
- padding: 0;
- text-align: left;
-}
-
-.link-button[data-selected="true"] strong {
- color: #0f766e;
-}
-
-.usage-table th,
-.usage-table td {
- white-space: nowrap;
-}
-
-.usage-table code {
- color: #0f766e;
- font-size: 12px;
-}
-
-.admin-billing-panel {
- overflow-x: auto;
-}
-
-.admin-billing-table td {
- vertical-align: top;
-}
-
-.admin-billing-table td > strong,
-.admin-billing-table td > small {
- display: block;
-}
-
-.admin-billing-table td > small {
- margin-top: 3px;
- color: #64748b;
- font-size: 12px;
-}
-
-.admin-action-error {
- margin: 0;
-}
-
-.inline-form-row,
-.inline-edit-row,
-.admin-users-filters,
-.pagination-row {
- display: flex;
- min-width: 0;
- flex-wrap: wrap;
- align-items: center;
- gap: 8px;
-}
-
-.inline-form-row .input,
-.admin-users-filters .input {
- min-width: 180px;
- flex: 1;
-}
-
-.secret-once-box,
-.detail-subpanel {
- display: grid;
- min-width: 0;
- gap: 10px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: #f8fafc;
- padding: 12px;
-}
-
-.secret-once-box code {
- overflow-wrap: anywhere;
- color: #0f766e;
-}
-
-.admin-users-layout,
-.admin-detail-grid {
- display: grid;
- grid-template-columns: minmax(0, 1.5fr) minmax(320px, 0.85fr);
- gap: 12px;
-}
-
-.admin-users-list-panel,
-.admin-user-create-panel,
-.admin-user-detail-panel,
-.admin-users-toolbar {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
-}
-
-.form-grid {
- display: grid;
- min-width: 0;
- gap: 10px;
-}
-
-.form-grid.two-col {
- grid-template-columns: repeat(2, minmax(0, 1fr));
-}
-
-.form-grid label {
- display: grid;
- gap: 6px;
- color: #475569;
- font-size: 13px;
- font-weight: 650;
-}
-
-.span-2 {
- grid-column: 1 / -1;
-}
-
-.admin-billing-table tr[data-selected="true"] td {
- background: #f0fdfa;
-}
-
-.table-action {
- min-width: 64px;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: #f8fafc;
- color: #0f172a;
- cursor: pointer;
- font-size: 12px;
- font-weight: 750;
- padding: 7px 10px;
-}
-
-.table-action:hover:not(:disabled) {
- border-color: #0891b2;
- color: #0c4a6e;
-}
-
-.table-action.danger:hover:not(:disabled) {
- border-color: #ef4444;
- color: #991b1b;
-}
-
-.table-action:disabled {
- cursor: wait;
- opacity: 0.55;
-}
-
-.status-pill {
- display: inline-flex;
- align-items: center;
- border: 1px solid #cbd5e1;
- border-radius: 999px;
- padding: 3px 8px;
- background: #f8fafc;
- color: #334155;
- font-size: 12px;
- font-weight: 700;
-}
-
-.status-pill[data-status="active"] {
- border-color: #99f6e4;
- background: #ccfbf1;
- color: #0f766e;
-}
-
-.status-pill[data-status="disabled"] {
- border-color: #fecaca;
- background: #fee2e2;
- color: #991b1b;
-}
-
-.status-pill[data-status="admin"],
-.status-pill[data-status="completed"],
-.status-pill[data-status="ready"] {
- border-color: #bbf7d0;
- background: #dcfce7;
- color: #166534;
-}
-
-.status-pill[data-status="failed"],
-.status-pill[data-status="blocked"],
-.status-pill[data-status="error"] {
- border-color: #fecaca;
- background: #fee2e2;
- color: #991b1b;
-}
-
-.status-pill[data-status="dry-run"],
-.status-pill[data-status="planned"],
-.status-pill[data-status="pending"] {
- border-color: #bae6fd;
- background: #e0f2fe;
- color: #075985;
-}
-
-.field-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 10px;
- margin: 0;
-}
-
-.field-grid div {
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.field-grid dt,
-.field-grid dd {
- min-width: 0;
- margin: 0;
-}
-
-.field-grid dt {
- color: #64748b;
- font-size: 12px;
- font-weight: 700;
-}
-
-.field-grid dd {
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 13px;
- font-weight: 750;
-}
-
-.form-grid,
-.admin-form {
- display: grid;
- gap: 12px;
-}
-
-.compact-form-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
-}
-
-.form-grid label,
-.admin-form label {
- display: grid;
- gap: 6px;
- color: #475569;
- font-size: 13px;
- font-weight: 700;
-}
-
-.form-grid select,
-.admin-form input,
-.admin-form select,
-.admin-form textarea {
- min-width: 0;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: white;
- color: #0f172a;
- font: inherit;
- padding: 9px 10px;
-}
-
-.admin-form textarea {
- resize: vertical;
- font-family: "SFMono-Regular", Consolas, monospace;
- font-size: 12px;
- line-height: 1.5;
-}
-
-.form-notice {
- margin: 0;
- color: #0f766e;
- font-size: 12px;
-}
-
-.access-user-head,
-.tool-toggle-grid,
-.tuple-list,
-.provider-validation-panel {
- display: grid;
- gap: 10px;
-}
-
-.tool-toggle-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.tool-toggle-row input {
- width: 18px;
- height: 18px;
-}
-
-.tuple-list h3 {
- margin: 0;
- font-size: 14px;
-}
-
-.tuple-list ul {
- display: grid;
- gap: 6px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.tuple-list li {
- display: grid;
- grid-template-columns: minmax(0, 1.1fr) auto minmax(0, 1.3fr);
- gap: 8px;
- align-items: center;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- padding: 8px;
-}
-
-.tuple-list code,
-.provider-admin-page code {
- overflow-wrap: anywhere;
- color: #0f766e;
- font-size: 12px;
-}
-
-.secrets-admin-page code {
- overflow-wrap: anywhere;
- color: #0f766e;
- font-size: 12px;
-}
-
-.secrets-compact-toolbar,
-.secrets-detail-commandbar {
- display: flex;
- min-width: 0;
- flex-wrap: wrap;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: #ffffff;
- padding: 10px 12px;
-}
-
-.secrets-compact-toolbar > div:first-child {
- display: grid;
- min-width: 0;
- gap: 2px;
-}
-
-.secrets-compact-toolbar strong {
- color: #0f172a;
- font-size: 15px;
-}
-
-.secrets-compact-toolbar small {
- color: #64748b;
- font-size: 12px;
-}
-
-.secrets-external-table .data-table {
- min-width: 980px;
-}
-
-.secrets-external-table .data-table th,
-.secrets-external-table .data-table td {
- padding: 6px 8px;
- font-size: 12px;
- line-height: 1.25;
- vertical-align: middle;
-}
-
-.secrets-external-table .data-table th {
- color: #475569;
- font-size: 11px;
- letter-spacing: 0;
-}
-
-.secrets-external-table .crud-table small {
- margin-top: 2px;
- max-width: 280px;
- line-height: 1.2;
-}
-
-.secrets-name-link {
- display: grid;
- min-width: 0;
- gap: 2px;
- color: #0f766e;
- text-decoration: none;
-}
-
-.secrets-name-link:hover strong {
- text-decoration: underline;
-}
-
-.secrets-detail-status-panel {
- padding: 12px;
-}
-
-.secrets-status-lines {
- display: grid;
- min-height: 78px;
- min-width: 0;
- gap: 8px;
- margin: 0;
-}
-
-.secrets-status-lines div {
- display: grid;
- grid-template-columns: 120px minmax(0, 1fr);
- align-items: center;
- min-width: 0;
- gap: 10px;
-}
-
-.secrets-status-lines dt,
-.secrets-status-lines dd {
- margin: 0;
- min-width: 0;
-}
-
-.secrets-status-lines dt {
- color: #64748b;
- font-size: 12px;
- font-weight: 750;
- text-transform: uppercase;
-}
-
-.secrets-status-lines dd {
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 14px;
- font-weight: 750;
-}
-
-.secrets-segmented-tabs {
- display: inline-flex;
- align-items: center;
- width: fit-content;
- max-width: 100%;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- overflow: hidden;
- background: #f8fafc;
-}
-
-.secrets-segmented-tabs button {
- min-width: 116px;
- border: 0;
- border-right: 1px solid #cbd5e1;
- background: transparent;
- color: #334155;
- cursor: pointer;
- font-size: 12px;
- font-weight: 800;
- letter-spacing: 0;
- padding: 9px 14px;
-}
-
-.secrets-segmented-tabs button:last-child {
- border-right: 0;
-}
-
-.secrets-segmented-tabs button[data-active="true"] {
- background: #0f766e;
- color: white;
-}
-
-.secrets-detail-content {
- display: grid;
- min-width: 0;
- gap: 12px;
-}
-
-.secrets-detail-section {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
-}
-
-.secrets-detail-fact-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 8px;
- margin: 0;
-}
-
-.secrets-detail-fact-grid div {
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 8px 9px;
-}
-
-.secrets-detail-fact-grid dt,
-.secrets-detail-fact-grid dd {
- min-width: 0;
- margin: 0;
-}
-
-.secrets-detail-fact-grid dt {
- color: #64748b;
- font-size: 11px;
- font-weight: 750;
-}
-
-.secrets-detail-fact-grid dd {
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 12px;
- font-weight: 750;
-}
-
-.secrets-ref-table {
- display: grid;
- max-width: 100%;
- min-width: 0;
- overflow-x: auto;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
-}
-
-.secrets-ref-table [role="row"] {
- display: grid;
- min-width: 840px;
- grid-template-columns: 140px minmax(220px, 1.4fr) 140px 120px minmax(180px, 1fr);
- border-bottom: 1px solid #e2e8f0;
-}
-
-.secrets-ref-table [role="row"]:last-child {
- border-bottom: 0;
-}
-
-.secrets-ref-table span {
- min-width: 0;
- overflow-wrap: anywhere;
- padding: 8px 9px;
- color: #334155;
- font-size: 12px;
-}
-
-.secrets-ref-head span {
- background: #f8fafc;
- color: #64748b;
- font-size: 11px;
- font-weight: 800;
- text-transform: uppercase;
-}
-
-.secrets-resource-event-list {
- max-height: none;
-}
-
-.secrets-summary-grid,
-.secrets-readiness-grid,
-.secrets-detail-grid {
- display: grid;
- min-width: 0;
- gap: 12px;
-}
-
-.secrets-summary-grid {
- grid-template-columns: repeat(3, minmax(0, 1fr));
-}
-
-.secrets-readiness-grid {
- grid-template-columns: minmax(0, 1fr);
-}
-
-.secrets-detail-grid {
- grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.75fr);
-}
-
-.secrets-target-panel,
-.secrets-contract-panel,
-.secrets-eso-panel,
-.secrets-rollout-panel {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
-}
-
-.secrets-fact-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 10px;
- margin: 0;
-}
-
-.secrets-fact-grid div {
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.secrets-fact-grid dt,
-.secrets-fact-grid dd {
- min-width: 0;
- margin: 0;
-}
-
-.secrets-fact-grid dt {
- color: #64748b;
- font-size: 12px;
- font-weight: 700;
-}
-
-.secrets-fact-grid dd {
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 13px;
- font-weight: 750;
-}
-
-.secrets-subsection {
- display: grid;
- min-width: 0;
- gap: 8px;
-}
-
-.secrets-subsection h3 {
- margin: 0;
- color: #334155;
- font-size: 13px;
-}
-
-.secrets-chip-list {
- display: grid;
- min-width: 0;
- gap: 8px;
-}
-
-.secrets-chip {
- display: grid;
- min-width: 0;
- gap: 3px;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 9px 10px;
-}
-
-.secrets-chip strong,
-.secrets-chip small {
- min-width: 0;
- overflow-wrap: anywhere;
-}
-
-.secrets-chip small {
- color: #64748b;
- font-size: 12px;
-}
-
-.secrets-plan-panel {
- border-color: #bae6fd;
- background: #f8fcff;
-}
-
-.secrets-plan-steps {
- display: grid;
- grid-template-columns: repeat(5, minmax(0, 1fr));
- gap: 8px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.secrets-plan-steps li {
- display: grid;
- min-width: 0;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 7px;
- align-items: center;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 8px 10px;
- color: #334155;
- font-size: 12px;
- font-weight: 750;
-}
-
-.secrets-plan-steps strong {
- display: inline-grid;
- width: 22px;
- height: 22px;
- place-items: center;
- border-radius: 999px;
- background: #0f766e;
- color: white;
- font-size: 11px;
-}
-
-.secrets-plan-form {
- gap: 12px;
-}
-
-.secrets-plan-fieldset {
- display: grid;
- min-width: 0;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 10px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- margin: 0;
- padding: 12px;
-}
-
-.secrets-plan-fieldset legend {
- padding: 0 4px;
- color: #0f766e;
- font-size: 12px;
- font-weight: 800;
-}
-
-.secrets-plan-fieldset input[readonly] {
- background: #f8fafc;
- color: #475569;
-}
-
-.secrets-plan-note {
- margin: 0;
- color: #64748b;
- font-size: 12px;
-}
-
-.secrets-plan-toggle {
- grid-template-columns: auto minmax(0, 1fr);
- align-items: center;
- align-self: end;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: #f8fafc;
- padding: 9px 10px;
-}
-
-.secrets-plan-toggle input {
- width: 16px;
- height: 16px;
- margin: 0;
-}
-
-.secrets-plan-result {
- display: grid;
- min-width: 0;
- gap: 12px;
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 12px;
-}
-
-.secrets-plan-result h3 {
- margin: 0;
- color: #0f172a;
- font-size: 14px;
-}
-
-.secrets-plan-result-grid {
- display: grid;
- min-width: 0;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 12px;
-}
-
-.secrets-plan-checks {
- display: flex;
- min-width: 0;
- flex-wrap: wrap;
- gap: 8px;
-}
-
-.secrets-event-list {
- display: grid;
- max-height: 560px;
- min-width: 0;
- gap: 8px;
- margin: 0;
- overflow: auto;
- padding: 0;
- list-style: none;
-}
-
-.secrets-event-list li {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 10px;
- align-items: start;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.secrets-event-list strong,
-.secrets-event-list p,
-.secrets-event-list small {
- min-width: 0;
- overflow-wrap: anywhere;
-}
-
-.secrets-event-list p {
- margin: 3px 0;
- color: #334155;
- font-size: 13px;
-}
-
-.secrets-event-list small {
- color: #64748b;
- font-size: 12px;
-}
-
-.toast-host {
- position: fixed;
- right: 16px;
- bottom: 16px;
- z-index: 50;
- display: grid;
- gap: 8px;
-}
-
-.toast-item {
- max-width: min(380px, calc(100vw - 32px));
- border: 1px solid #d8e1eb;
- border-radius: 8px;
- background: white;
- padding: 10px 12px;
- box-shadow: 0 12px 30px rgba(15, 23, 42, 0.14);
- text-align: left;
-}
-
-.system-page .data-table td small,
-.provider-admin-page .data-table td small {
- display: block;
- margin-top: 3px;
- color: #64748b;
- font-size: 12px;
-}
-
-.system-summary-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
-}
-
-.system-summary-grid .metric-card {
- display: grid;
- gap: 5px;
- padding: 14px;
-}
-
-.system-summary-grid .metric-card span,
-.rum-bar-row span,
-.skill-tree-list small {
- color: #64748b;
- font-size: 12px;
- font-weight: 700;
-}
-
-.system-summary-grid .metric-card strong {
- min-width: 0;
- overflow-wrap: anywhere;
- color: #0f172a;
- font-size: 20px;
- line-height: 1.15;
-}
-
-.system-summary-grid .metric-card small {
- min-width: 0;
- overflow-wrap: anywhere;
- color: #64748b;
- font-size: 12px;
-}
-
-.system-filter-bar {
- display: grid;
- grid-template-columns: minmax(140px, 220px) minmax(240px, 1fr);
- gap: 10px;
-}
-
-.system-filter-bar label {
- display: grid;
- gap: 5px;
- color: #475569;
- font-size: 12px;
- font-weight: 700;
-}
-
-.system-filter-bar select,
-.system-filter-bar input {
- min-height: 36px;
- min-width: 0;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: white;
- padding: 7px 10px;
-}
-
-.system-row-detail {
- display: -webkit-box;
- max-width: 520px;
- overflow: hidden;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
-}
-
-.system-drilldown {
- display: grid;
- gap: 8px;
-}
-
-.system-drilldown h3,
-.system-drilldown p {
- margin: 0;
-}
-
-.system-drilldown h3 {
- font-size: 13px;
-}
-
-.system-drilldown ul,
-.skill-tree-list {
- display: grid;
- gap: 6px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.system-drilldown li,
-.skill-tree-list li {
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 8px;
-}
-
-.rum-chart-panel {
- display: grid;
- gap: 10px;
- padding: 14px;
-}
-
-.rum-bar-row {
- display: grid;
- grid-template-columns: minmax(100px, 160px) minmax(0, 1fr) 48px;
- align-items: center;
- gap: 10px;
-}
-
-.rum-bar-row div {
- height: 10px;
- overflow: hidden;
- border-radius: 999px;
- background: #e2e8f0;
-}
-
-.rum-bar-row i {
- display: block;
- height: 100%;
- border-radius: inherit;
- background: #0e7490;
-}
-
-.rum-bar-row strong {
- text-align: right;
-}
-
-.performance-window-toolbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- flex-wrap: wrap;
-}
-
-.performance-window-tabs {
- display: inline-flex;
- align-items: center;
- gap: 2px;
- padding: 3px;
- border: 1px solid #cbd5e1;
- background: #f8fafc;
- border-radius: 8px;
-}
-
-.performance-window-tabs button {
- min-width: 56px;
- height: 30px;
- padding: 0 10px;
- border: 0;
- border-radius: 6px;
- background: transparent;
- color: #475569;
- font-size: 0.82rem;
- font-weight: 650;
- cursor: pointer;
-}
-
-.performance-window-tabs button[data-selected="true"] {
- background: #fff;
- color: #0f172a;
- box-shadow: 0 1px 3px rgba(15, 23, 42, 0.14);
-}
-
-.performance-window-toolbar > span {
- color: #64748b;
- font-size: 0.86rem;
- font-weight: 650;
-}
-
-.performance-health-strip {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
-}
-
-.performance-health-card {
- min-height: 112px;
- border-left: 4px solid #64748b;
-}
-
-.performance-health-card.is-ok {
- border-left-color: #0f766e;
-}
-
-.performance-health-card.is-warn {
- border-left-color: #b45309;
-}
-
-.performance-health-card.is-blocked {
- border-left-color: #b91c1c;
-}
-
-.performance-contract-strip {
- display: grid;
- grid-template-columns: repeat(5, minmax(0, 1fr));
- gap: 10px;
- border: 1px solid #dbe3ef;
- border-radius: 8px;
- background: #ffffff;
- padding: 12px;
-}
-
-.performance-contract-item {
- display: grid;
- min-width: 0;
- gap: 4px;
- border-left: 3px solid #0e7490;
- background: #f8fafc;
- padding: 10px;
-}
-
-.performance-contract-item span,
-.performance-contract-item small,
-.performance-row-contract {
- min-width: 0;
- overflow: hidden;
- color: #64748b;
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-contract-item strong {
- min-width: 0;
- overflow: hidden;
- color: #0f172a;
- font-size: 13px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-row-contract {
- display: block;
- margin-top: 4px;
-}
-
-.performance-freshness-panel {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- align-items: center;
- gap: 12px;
- border: 1px solid #dbe3ef;
- border-radius: 8px;
- background: #f8fafc;
- padding: 12px 14px;
-}
-
-.performance-freshness-panel div {
- display: grid;
- gap: 3px;
- min-width: 0;
-}
-
-.performance-freshness-panel strong {
- color: #0f172a;
- font-size: 14px;
-}
-
-.performance-freshness-panel span,
-.performance-chart-card header span,
-.performance-top-row span,
-.performance-chart-legend span {
- color: #64748b;
- font-size: 12px;
-}
-
-.performance-collection-strip {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 10px;
-}
-
-.performance-collection-item {
- display: grid;
- min-width: 0;
- gap: 4px;
- border: 1px solid #dbe3ef;
- border-left: 3px solid #475569;
- border-radius: 8px;
- background: #ffffff;
- padding: 10px;
-}
-
-.performance-collection-item span,
-.performance-collection-item small,
-.performance-collection-diagnostics small {
- min-width: 0;
- overflow: hidden;
- color: #64748b;
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-collection-item strong,
-.performance-collection-diagnostics strong {
- min-width: 0;
- overflow: hidden;
- color: #0f172a;
- font-size: 13px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-collection-diagnostics {
- display: grid;
- gap: 8px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.performance-collection-diagnostics li {
- display: grid;
- grid-template-columns: minmax(120px, 0.28fr) minmax(0, 1fr);
- gap: 10px;
- align-items: center;
- border: 1px solid #dbe3ef;
- border-left: 3px solid #64748b;
- border-radius: 8px;
- background: #f8fafc;
- padding: 9px 10px;
-}
-
-.performance-collection-diagnostics li.is-ok {
- border-left-color: #0f766e;
-}
-
-.performance-collection-diagnostics li.is-warn {
- border-left-color: #b45309;
-}
-
-.performance-collection-diagnostics li.is-blocked {
- border-left-color: #b91c1c;
-}
-
-.performance-diagnostic-panel {
- padding: 18px;
-}
-
-.performance-chart-grid,
-.performance-analytics-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 14px;
-}
-
-.performance-chart-card {
- display: grid;
- min-width: 0;
- gap: 12px;
- border: 1px solid #dbe3ef;
- border-radius: 8px;
- background: #ffffff;
- padding: 14px;
- box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
-}
-
-.performance-chart-card header {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- gap: 12px;
- min-width: 0;
-}
-
-.performance-chart-card header div {
- display: grid;
- gap: 3px;
- min-width: 0;
-}
-
-.performance-chart-card header strong {
- color: #0f172a;
- font-size: 14px;
-}
-
-.performance-chart-card header em {
- flex: 0 0 auto;
- border: 1px solid #cbd5e1;
- border-radius: 999px;
- color: #475569;
- font-size: 12px;
- font-style: normal;
- line-height: 1;
- padding: 5px 8px;
-}
-
-.performance-line-chart {
- width: 100%;
- height: 150px;
- overflow: visible;
-}
-
-.chart-grid-line {
- fill: none;
- stroke: #e2e8f0;
- stroke-width: 1;
-}
-
-.chart-line {
- fill: none;
- stroke: #0f766e;
- stroke-width: 3;
- stroke-linecap: round;
- stroke-linejoin: round;
-}
-
-.chart-point {
- fill: #64748b;
- stroke: #ffffff;
- stroke-width: 2;
-}
-
-.chart-point.is-ok,
-.performance-bar-row i.is-ok,
-.performance-top-row i.is-ok {
- fill: #0f766e;
- background: #0f766e;
-}
-
-.chart-point.is-warn,
-.performance-bar-row i.is-warn,
-.performance-top-row i.is-warn {
- fill: #b45309;
- background: #b45309;
-}
-
-.chart-point.is-blocked,
-.performance-bar-row i.is-blocked,
-.performance-top-row i.is-blocked {
- fill: #b91c1c;
- background: #b91c1c;
-}
-
-.performance-chart-legend {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 8px;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.performance-chart-legend li {
- display: grid;
- min-width: 0;
- gap: 2px;
- border-top: 1px solid #e2e8f0;
- padding-top: 8px;
-}
-
-.performance-chart-legend strong {
- color: #0f172a;
- font-size: 13px;
-}
-
-.performance-bar-list,
-.performance-top-list {
- display: grid;
- gap: 10px;
-}
-
-.performance-bar-row {
- display: grid;
- grid-template-columns: minmax(80px, 128px) minmax(0, 1fr) 48px;
- align-items: center;
- gap: 10px;
-}
-
-.performance-bar-row > span {
- min-width: 0;
- overflow: hidden;
- color: #334155;
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-bar-row div,
-.performance-top-row > div:nth-child(2) {
- height: 9px;
- overflow: hidden;
- border-radius: 999px;
- background: #e2e8f0;
-}
-
-.performance-bar-row i,
-.performance-top-row i {
- display: block;
- height: 100%;
- min-width: 6px;
- border-radius: inherit;
- background: #64748b;
-}
-
-.performance-bar-row strong {
- color: #0f172a;
- font-size: 12px;
- text-align: right;
-}
-
-.performance-top-row {
- display: grid;
- grid-template-columns: minmax(0, 1.4fr) minmax(96px, 0.8fr) minmax(70px, auto);
- align-items: center;
- gap: 10px;
-}
-
-.performance-top-row > div:first-child {
- display: grid;
- min-width: 0;
- gap: 2px;
-}
-
-.performance-top-row strong,
-.performance-top-row span {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.performance-top-row > div:first-child strong {
- color: #0f172a;
- font-size: 12px;
-}
-
-.performance-top-row em {
- color: #0f172a;
- font-size: 12px;
- font-style: normal;
- text-align: right;
-}
-
-.system-split-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 14px;
-}
-
-.hwpod-groups-section,
-.hwpod-raw-panel {
- display: grid;
- min-width: 0;
- gap: 12px;
- padding: 14px;
-}
-
-.hwpod-node-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
- gap: 10px;
-}
-
-.hwpod-node-row {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: 6px 10px;
- min-width: 0;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
- background: #f8fafc;
- padding: 10px;
-}
-
-.hwpod-node-row strong,
-.hwpod-node-row small,
-.hwpod-node-row code {
- min-width: 0;
- overflow-wrap: anywhere;
-}
-
-.hwpod-node-row small,
-.hwpod-node-row code {
- grid-column: 1 / -1;
- color: #475569;
-}
-
-.hwpod-op-list {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
-}
-
-.hwpod-op-list code {
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: #f8fafc;
- padding: 5px 8px;
- font-size: 12px;
-}
-
-.hwpod-blocker {
- color: #7f1d1d;
-}
-
-.performance-wide-panel {
- grid-column: 1 / -1;
-}
-
-.performance-page .table-page-layout {
- overflow: hidden;
-}
-
-.performance-page .data-table-wrap {
- border: 1px solid #d8e1eb;
- border-radius: 8px;
-}
-
-.performance-page .data-table {
- width: max-content;
- min-width: 780px;
- border: 0;
-}
-
-.performance-page .data-table th,
-.performance-page .data-table td {
- white-space: nowrap;
-}
-
-.performance-page .performance-dimensions {
- min-width: 220px;
- white-space: normal;
-}
-
-.performance-dimensions {
- display: block;
- max-width: 360px;
- min-width: 0;
- overflow-wrap: anywhere;
- color: #334155;
- font-size: 12px;
- line-height: 1.4;
-}
-
-.skills-tree-panel,
-.skills-preview-panel {
- display: grid;
- align-content: start;
- gap: 12px;
- padding: 14px;
-}
-
-.skill-tree-list {
- max-height: 420px;
- overflow: auto;
-}
-
-.skill-tree-list li {
- display: grid;
- grid-template-columns: 48px minmax(0, 1fr) auto;
- align-items: center;
- gap: 8px;
-}
-
-.skill-tree-list button {
- min-height: 26px;
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- background: white;
- color: #334155;
- font-size: 11px;
- font-weight: 800;
- text-transform: uppercase;
-}
-
-.skill-tree-list button:disabled {
- color: #94a3b8;
-}
-
-.skill-tree-list span {
- min-width: 0;
- overflow-wrap: anywhere;
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
- font-size: 12px;
-}
-
-.skills-preview-panel .mini-log {
- max-height: 460px;
- min-height: 240px;
- overflow: auto;
- white-space: pre-wrap;
-}
-
@media (max-width: 1180px) {
- .platform-shell {
- grid-template-columns: 76px minmax(0, 1fr);
- }
-
- .platform-sidebar {
- padding: 14px 8px;
- }
-
- .platform-sidebar .brand-lockup div,
- .nav-section h2,
- .nav-label {
- display: none;
- }
-
- .overview-grid,
- .settings-grid,
- .usage-panels,
- .admin-users-layout,
- .admin-detail-grid,
- .system-summary-grid,
- .system-split-grid,
- .performance-health-strip,
- .performance-contract-strip,
- .performance-collection-strip,
- .performance-chart-grid,
- .performance-analytics-grid,
- .secrets-summary-grid,
- .secrets-readiness-grid,
- .secrets-detail-grid,
- .secrets-plan-fieldset,
- .secrets-plan-result-grid {
- grid-template-columns: 1fr;
- }
-
.workbench-route {
min-height: calc(100dvh - 102px);
overflow: auto;
@@ -3881,72 +1515,9 @@
.hwpod-event-scroll {
max-height: 260px;
}
-
- .field-grid,
- .form-grid.two-col,
- .compact-form-grid,
- .secrets-detail-fact-grid,
- .secrets-fact-grid,
- .secrets-plan-steps {
- grid-template-columns: 1fr;
- }
-
- .secrets-status-lines div {
- grid-template-columns: 1fr;
- gap: 4px;
- }
-
- .secrets-segmented-tabs {
- display: flex;
- width: 100%;
- }
-
- .secrets-segmented-tabs button {
- flex: 1;
- min-width: 0;
- }
}
@media (max-width: 720px) {
- .platform-shell {
- height: 100dvh;
- min-height: 100dvh;
- grid-template-columns: minmax(0, 1fr);
- overflow: hidden;
- }
-
- .platform-sidebar {
- display: none;
- }
-
- .platform-main {
- height: 100dvh;
- min-height: 0;
- grid-template-rows: 44px minmax(0, 1fr);
- }
-
- .platform-content {
- min-height: 0;
- padding: 12px;
- overflow: hidden;
- }
-
- .platform-topbar {
- min-width: 0;
- gap: 8px;
- padding: 0 10px;
- }
-
- .topbar-status {
- gap: 6px;
- }
-
- .topbar-status strong {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
.workbench-route,
.workbench-grid,
.workbench-center {
@@ -4039,42 +1610,4 @@
.command-composer textarea {
min-height: 72px;
}
-
- .system-filter-bar,
- .rum-bar-row,
- .performance-freshness-panel,
- .performance-collection-diagnostics li,
- .performance-bar-row,
- .performance-top-row,
- .skill-tree-list li {
- grid-template-columns: 1fr;
- }
-
- .performance-health-card {
- min-height: 92px;
- }
-
- .performance-chart-card header,
- .performance-freshness-panel {
- align-items: stretch;
- }
-
- .performance-chart-card header,
- .performance-freshness-panel,
- .performance-collection-diagnostics li,
- .performance-top-row {
- gap: 8px;
- }
-
- .performance-chart-legend {
- grid-template-columns: 1fr;
- }
-
- .performance-line-chart {
- height: 128px;
- }
-
- .performance-top-row em {
- text-align: left;
- }
}
diff --git a/web/hwlab-cloud-web/tests/workbench-e2e/specs/console-foundation.spec.ts b/web/hwlab-cloud-web/tests/workbench-e2e/specs/console-foundation.spec.ts
new file mode 100644
index 00000000..3fc908e9
--- /dev/null
+++ b/web/hwlab-cloud-web/tests/workbench-e2e/specs/console-foundation.spec.ts
@@ -0,0 +1,86 @@
+// SPEC: PJ2026-010405 云端控制台.
+// Implementation reference: draft-2026-07-13-p0-cloud-console.
+
+import { expect, test } from "../fixtures/test";
+
+const viewports = [
+ { name: "desktop", width: 1920, height: 1080 },
+ { name: "compact", width: 960, height: 600 },
+ { name: "mobile", width: 390, height: 844 }
+] as const;
+
+test("industrial AppShell keeps one bounded scroll owner across target viewports", async ({ page }, testInfo) => {
+ await mockProviderProfiles(page);
+ for (const viewport of viewports) {
+ await page.setViewportSize({ width: viewport.width, height: viewport.height });
+ await page.goto("/admin/provider-profiles");
+ await expect(page.getByRole("heading", { name: "Provider Profiles", exact: true })).toBeVisible();
+ await expect(page.locator(".data-table")).toContainText("codex-api");
+
+ const geometry = await page.evaluate(() => {
+ const shell = document.querySelector(".platform-shell");
+ const content = document.querySelector(".platform-content");
+ const sidebar = document.querySelector(".platform-sidebar");
+ return {
+ documentScrollWidth: Math.round(document.documentElement.scrollWidth),
+ bodyScrollWidth: Math.round(document.body.scrollWidth),
+ shellHeight: Math.round(shell?.getBoundingClientRect().height ?? 0),
+ contentOverflowY: content ? getComputedStyle(content).overflowY : "missing",
+ sidebarDisplay: sidebar ? getComputedStyle(sidebar).display : "missing"
+ };
+ });
+ expect(geometry.documentScrollWidth).toBeLessThanOrEqual(viewport.width);
+ expect(geometry.bodyScrollWidth).toBeLessThanOrEqual(viewport.width);
+ expect(geometry.shellHeight).toBe(viewport.height);
+ expect(geometry.contentOverflowY).toBe("auto");
+ expect(geometry.sidebarDisplay).toBe(viewport.name === "mobile" ? "none" : "flex");
+
+ await page.screenshot({ path: testInfo.outputPath(`console-${viewport.name}.png`) });
+ }
+});
+
+test("Dialog and mobile Drawer trap, restore and unlock focus without motion", async ({ page }, testInfo) => {
+ await mockProviderProfiles(page);
+ await page.emulateMedia({ reducedMotion: "reduce" });
+ await page.setViewportSize({ width: 1920, height: 1080 });
+ await page.goto("/admin/provider-profiles");
+
+ const keyButton = page.getByRole("button", { name: "Key", exact: true }).first();
+ await keyButton.click();
+ const dialog = page.getByRole("dialog", { name: "Provider Credential" });
+ await expect(dialog).toBeVisible();
+ await expect(page.locator("body")).toHaveClass(/console-scroll-locked/u);
+ await expect(dialog.locator("#provider-api-key-input")).toBeVisible();
+ await page.screenshot({ path: testInfo.outputPath("console-overlay-desktop.png") });
+ await page.keyboard.press("Escape");
+ await expect(dialog).toHaveCount(0);
+ await expect(page.locator("body")).not.toHaveClass(/console-scroll-locked/u);
+ await expect(keyButton).toBeFocused();
+
+ await page.setViewportSize({ width: 390, height: 844 });
+ const mobileTrigger = page.getByRole("button", { name: "打开主导航" });
+ await mobileTrigger.click();
+ const drawer = page.getByRole("dialog", { name: "HWLAB 导航" });
+ await expect(drawer).toBeVisible();
+ await expect(drawer.getByRole("navigation", { name: "主导航" })).toBeVisible();
+ await expect(page.locator("body")).toHaveClass(/console-scroll-locked/u);
+ await page.keyboard.press("Escape");
+ await expect(drawer).toHaveCount(0);
+ await expect(mobileTrigger).toBeFocused();
+ await expect(page.locator("body")).not.toHaveClass(/console-scroll-locked/u);
+});
+
+async function mockProviderProfiles(page: import("@playwright/test").Page): Promise {
+ await page.route("**/v1/admin/provider-profiles", async (route) => {
+ await route.fulfill({
+ status: 200,
+ contentType: "application/json",
+ body: JSON.stringify({
+ items: [
+ { profile: "codex-api", configured: true, secretRef: { namespace: "hwlab-v03", name: "gpt-pika", keys: ["auth.json"] }, credentialHashSuffix: "a19f", validationStatus: "completed", valuesPrinted: false },
+ { profile: "deepseek", configured: true, secretRef: { namespace: "hwlab-v03", name: "deepseek", keys: ["api-key"] }, credentialHashSuffix: "b470", validationStatus: "pending", valuesPrinted: false }
+ ]
+ })
+ });
+ });
+}
-
-
-
+
-
-
+
+
-
-
- Workbench 诊断
-Code Agent session、trace、HWPOD 诊断仍走 Cloud Web 同源 API。
-- Provider
- {{ workbench.providerProfile }}
+
+ {{ eyebrow }}
+
+ {{ title }}
+{{ description }}
+
+
+
+
+
+
+
+
+ {{ title }}
+{{ description }}
+
+
+
+ -
+
- {{ item.label }} +
- {{ item.value }} +
+
+