From 980b882706537f41e729c3d4992d8a2cdc0b7c23 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:45:59 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EB=B9=84=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EC=9A=94=EC=86=8C=EC=9D=98=20=ED=88=B4=ED=8C=81=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 3 + index.html | 6 +- patch.diff | 34 ++ styles.css | 3 +- styles.css.orig | 1112 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1154 insertions(+), 4 deletions(-) create mode 100644 patch.diff create mode 100644 styles.css.orig diff --git a/.jules/palette.md b/.jules/palette.md index 0bbf5248..9256c5ed 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -115,3 +115,6 @@ ## $(date +%Y-%m-%d) - Prevent accidental data loss in inline editors **Learning:** Forms that take a long time to fill out (like a WBS editor) are prone to accidental closure by users pressing `Escape` or clicking cancel. This causes immediate data loss without any warning, resulting in frustration. **Action:** When working on editors that can be dismissed, track whether the user has modified any fields compared to their initial state. If there are changes, intercept the close action and present a confirmation dialog (`window.confirm`) to ensure they really want to discard their edits. Bypass this for intentional saves or explicit data overrides. +## 2026-08-20 - Make Tooltips on Non-Interactive Elements Accessible +**Learning:** Tooltips (title) on static elements like summary cards are inaccessible to keyboard and screen reader users. +**Action:** When adding tooltips to non-interactive elements, make them focusable with tabindex="0", provide semantic meaning with a role like role="note", and ensure there is a clear :focus-visible style. diff --git a/index.html b/index.html index d24b2a88..cd622bfd 100644 --- a/index.html +++ b/index.html @@ -29,18 +29,18 @@

ScopeWeave Planner

기준일 -
+
전체일수 0일
-
+
계획진척률(누적) 0.00%
-
+
실적진척률(누적) 0.00%
diff --git a/patch.diff b/patch.diff new file mode 100644 index 00000000..3dcf0f91 --- /dev/null +++ b/patch.diff @@ -0,0 +1,34 @@ +--- index.html ++++ index.html +@@ -31,7 +31,7 @@ + +-
++
+ 전체일수 + 0일 +
+
+ +
+-
++
+ 계획진척률(누적) + 0.00% +
+-
++
+ 실적진척률(누적) + 0.00% +
+--- styles.css ++++ styles.css +@@ -361,7 +361,8 @@ + .secondary-button:focus-visible, + input:focus-visible, + select:focus-visible, +-.gantt-bar:focus-visible { ++.gantt-bar:focus-visible, ++.meta-value-card:focus-visible { + outline: 3px solid rgba(37, 99, 235, 0.5); + outline-offset: 2px; + } diff --git a/styles.css b/styles.css index 9d715f00..6d5300ca 100644 --- a/styles.css +++ b/styles.css @@ -360,7 +360,8 @@ button { .secondary-button:focus-visible, input:focus-visible, select:focus-visible, -.gantt-bar:focus-visible { +.gantt-bar:focus-visible, +.meta-value-card:focus-visible { outline: 3px solid rgba(37, 99, 235, 0.5); outline-offset: 2px; } diff --git a/styles.css.orig b/styles.css.orig new file mode 100644 index 00000000..e5b4011c --- /dev/null +++ b/styles.css.orig @@ -0,0 +1,1112 @@ +:root { + --bg: #f8fafc; + --surface: #ffffff; + --surface-muted: #f8fafc; + --surface-depth-3: #f1f5f9; + --surface-header: rgba(255, 255, 255, 0.9); + --border: #e2e8f0; + --border-strong: #cbd5e1; + --text: #0f172a; + --text-muted: #64748b; + --blue-soft: #f0fdfa; + --blue-hover: #e0f2fe; + --danger: #dc2626; + --status-before: #475569; + --status-active: #059669; + --status-done: #0f172a; + --status-delay: #ea580c; + --gantt-plan: #334155; + --gantt-actual: #10b981; + + --shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.04); + --shadow: 0 4px 6px -1px rgba(15, 23, 42, 0.08), 0 2px 4px -2px rgba(15, 23, 42, 0.04); + --shadow-md: 0 10px 15px -3px rgba(15, 23, 42, 0.08), 0 4px 6px -4px rgba(15, 23, 42, 0.04); + --shadow-lg: 0 20px 25px -5px rgba(15, 23, 42, 0.1), 0 8px 10px -6px rgba(15, 23, 42, 0.04); + + --radius: 16px; + --radius-sm: 10px; + --radius-badge: 20px; + --transition: 250ms cubic-bezier(0.16, 1, 0.3, 1); + --font: "Pretendard", "Inter", -apple-system, "BlinkMacSystemFont", "Segoe UI", roboto, "Helvetica Neue", arial, sans-serif; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + background: var(--bg); + color: var(--text); + font-family: var(--font); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + line-height: 1.5; +} + +button, +input, +select { + font: inherit; +} + +button { + cursor: pointer; +} + +.app-shell { + --table-empty-page-gutter: 98px; /* 2 * 48px shell padding + 2px table-section border */ + display: flex; + min-height: 100vh; + flex-direction: column; + gap: 32px; + padding: 40px 48px; + max-width: 2000px; + margin: 0 auto; +} + +.top-panel, +.table-section, +.modal-panel { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow); +} + +.top-panel { + padding: 32px; + display: flex; + flex-direction: column; + gap: 28px; +} + +.title-row { + display: flex; + align-items: flex-end; + justify-content: space-between; +} + +.title-row h1 { + margin: 8px 0 0; + font-size: 2rem; + font-weight: 800; + letter-spacing: -0.03em; + color: var(--text); +} + +.eyebrow { + margin: 0; + color: #2563eb; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.meta-grid { + display: grid; + gap: 20px; +} + +.meta-grid-primary { + grid-template-columns: minmax(320px, 2fr) repeat(2, minmax(200px, 1fr)); +} + +.meta-grid-secondary { + grid-template-columns: repeat(2, minmax(220px, 1fr)) minmax(320px, 1.5fr); +} + +.meta-field, +.meta-value-card, +.sync-panel { + display: flex; + min-height: 100px; + flex-direction: column; + justify-content: center; + gap: 10px; + border-radius: var(--radius-sm); + background: #f8fafc; + padding: 20px 24px; + border: 1px solid transparent; + transition: var(--transition); +} + +.meta-field:hover, +.sync-panel:hover { + background: #ffffff; + border-color: var(--border); + box-shadow: var(--shadow-sm); +} + +.meta-field input { + width: 100%; + border: 1px solid var(--border-strong); + border-radius: 8px; + padding: 10px 14px; + font-size: 0.95rem; + transition: var(--transition); + background: #ffffff; +} + +.meta-field input:focus { + border-color: #2563eb; + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15); + outline: none; +} + +.meta-label, +.meta-field span, +.sync-panel span { + font-size: 0.8125rem; + font-weight: 600; + color: var(--text-muted); +} + +.meta-value-card strong { + font-size: 1.75rem; + font-weight: 800; + color: var(--text); + letter-spacing: -0.02em; +} + +.accent-card { + color: #fff; + border: none; +} + +.accent-card .meta-label { + color: rgba(255, 255, 255, 0.9); +} + +.accent-card strong { + color: #ffffff; +} + +.plan-card { + background: linear-gradient(135deg, #1e40af, #3b82f6); + box-shadow: 0 4px 14px 0 rgba(37, 99, 235, 0.25); +} + +.actual-card { + background: linear-gradient(135deg, #047857, #10b981); + box-shadow: 0 4px 14px 0 rgba(16, 185, 129, 0.25); +} + +.sync-panel { + align-items: flex-start; + justify-content: space-between; +} + +.table-section { + overflow: hidden; + display: flex; + flex-direction: column; + min-width: 0; +} + +.table-scroll { + overflow: auto; + contain: paint; + width: 100%; + max-width: 100%; + min-width: 0; +} + +.wbs-table { + width: 100%; + min-width: 2000px; + border-collapse: separate; + border-spacing: 0; +} + +.wbs-table thead th { + position: sticky; + top: 0; + z-index: 2; + border-bottom: 1px solid var(--border); + background: var(--surface-header); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + padding: 18px 16px; + font-size: 0.8125rem; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.05em; + text-align: left; + white-space: nowrap; +} + +.wbs-table tbody td { + border-bottom: 1px solid var(--border); + padding: 14px 16px; + vertical-align: middle; + font-size: 0.9375rem; + color: var(--text); + transition: background var(--transition); +} + +.task-row { + cursor: pointer; +} + +.task-row.depth-1 td { background: #ffffff; } +.task-row.depth-2 td { background: #f8fafc; } +.task-row.depth-3 td { background: #f1f5f9; } + +.task-row.striped-even td { + background-image: linear-gradient(rgba(0, 0, 0, 0.015), rgba(0, 0, 0, 0.015)); +} + +.task-row:hover td, +.task-row:focus-within td { + background-color: var(--blue-hover) !important; + background-image: none; +} + +.task-row.drop-target td { + position: relative; +} +.task-row.drop-target td::after { + content: ''; + position: absolute; + left: 0; right: 0; + height: 2px; + background: #2563eb; + z-index: 3; +} +.task-row.drop-target[data-drop-position="before"] td::after { top: -1px; } +.task-row.drop-target[data-drop-position="after"] td::after { bottom: -1px; } + +.task-row.dragging { + opacity: 0.4; + background: #f1f5f9; +} + +.col-actions { + min-width: 180px; +} + +.action-stack { + display: flex; + align-items: center; + gap: 8px; +} + +.drag-handle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 32px; + color: var(--border-strong); + cursor: grab; + font-size: 1.1rem; + font-weight: bold; + letter-spacing: -2px; + transition: color var(--transition); + user-select: none; +} + +.drag-handle:hover { + color: var(--text-muted); +} + +.drag-handle:active { + cursor: grabbing; +} + +.toggle-button, +.icon-button { + width: 32px; + height: 32px; + border: 1px solid var(--border); + border-radius: 8px; + background: #ffffff; + color: var(--text-muted); + transition: all var(--transition); + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 1px 2px 0 rgba(0,0,0,0.02); +} + +.icon-button:hover:not(:disabled):not([aria-disabled="true"]), +.toggle-button:hover:not(:disabled):not([aria-disabled="true"]) { + background: #f8fafc; + border-color: var(--border-strong); + color: var(--text); + transform: translateY(-1px); + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.05); +} + +.icon-button:disabled, +.icon-button[aria-disabled="true"], +.toggle-button:disabled, +.toggle-button[aria-disabled="true"] { + opacity: 0.5; + cursor: not-allowed; +} + +.icon-button:focus-visible, +.toggle-button:focus-visible { + border-color: #2563eb; + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15); + outline: none; +} + +.primary-button:focus-visible, +.secondary-button:focus-visible, +input:focus-visible, +select:focus-visible, +.gantt-bar:focus-visible { + outline: 3px solid rgba(37, 99, 235, 0.5); + outline-offset: 2px; +} + +.toggle-placeholder { + display: inline-flex; + width: 32px; + height: 32px; +} + +.tree-value { + display: inline-flex; + align-items: center; + min-height: 32px; + gap: 10px; + font-weight: 500; +} + +.indent-1 { padding-left: 0; } +.indent-2 { padding-left: 28px; } +.indent-3 { padding-left: 56px; } + +.owner-badge, +.status-badge, +.warning-badge { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 28px; + border-radius: var(--radius-badge); + padding: 0 12px; + font-size: 0.75rem; + font-weight: 700; + white-space: nowrap; + letter-spacing: 0.02em; +} + +.owner-badge { + color: #ffffff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} + +.status-badge.before { background: #f1f5f9; color: var(--status-before); } +.status-badge.active { background: #d1fae5; color: #047857; } +.status-badge.done { background: #e2e8f0; color: var(--status-done); } +.status-badge.delay { background: #ffedd5; color: #b45309; } + +.warning-badge { + background: #fef2f2; + color: #b91c1c; + border: 1px solid #fecaca; +} + +.metric-text { + font-variant-numeric: tabular-nums; + white-space: nowrap; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-weight: 500; +} + +.empty-cell { + color: var(--text-muted); +} + +.editor-row td { + background: #f8fafc; + padding: 0; + border-bottom: 2px solid #2563eb; +} + +.editor-panel { + padding: 24px; + background: #ffffff; + box-shadow: inset 0 2px 6px 0 rgba(0, 0, 0, 0.02); +} + +.editor-grid { + display: grid; + grid-template-columns: repeat(4, minmax(200px, 1fr)); + gap: 20px; +} + +.editor-field { + display: flex; + flex-direction: column; + gap: 8px; +} + +.editor-field span { + color: var(--text-muted); + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.editor-field .required-indicator { + color: var(--danger); +} + +.editor-field input:focus, +.editor-field select:focus, +select[data-inline-progress]:focus { + border-color: #2563eb; + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15); + outline: none; +} + +.editor-actions { + margin-top: 24px; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px; +} + +.validation-message { + min-height: 24px; + color: var(--danger); + font-size: 0.875rem; + font-weight: 500; + display: flex; + align-items: center; +} + +.primary-button, +.secondary-button { + min-height: 44px; + border: 1px solid transparent; + border-radius: var(--radius-sm); + padding: 0 20px; + font-weight: 600; + font-size: 0.9375rem; + transition: all var(--transition); + display: inline-flex; + align-items: center; + justify-content: center; +} + +.primary-button { + background: #2563eb; + color: #ffffff; + box-shadow: 0 1px 2px 0 rgba(37, 99, 235, 0.3); +} + +.primary-button:hover:not(:disabled):not([aria-disabled="true"]) { + background: #1d4ed8; + box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.4); + transform: translateY(-1px); +} + +.primary-button:active:not(:disabled):not([aria-disabled="true"]) { + transform: translateY(0); +} + +.primary-button:disabled, +.primary-button[aria-disabled="true"], +.secondary-button:disabled, +.secondary-button[aria-disabled="true"] { + opacity: 0.5; + cursor: not-allowed; +} + +.secondary-button { + background: #ffffff; + border-color: var(--border-strong); + color: var(--text); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +} + +.secondary-button:hover:not(:disabled):not([aria-disabled="true"]) { + background: #f8fafc; + border-color: #64748b; + transform: translateY(-1px); +} + +.secondary-button:active:not(:disabled):not([aria-disabled="true"]) { + transform: translateY(0); +} + +.bottom-action-bar { + position: sticky; + bottom: 32px; + z-index: 4; + display: flex; + flex-wrap: wrap; + gap: 16px; + padding: 20px 32px; + border-radius: var(--radius); + background: rgba(255, 255, 255, 0.85); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid var(--border); + box-shadow: var(--shadow-md); + margin-top: auto; +} + +.toast { + position: fixed; + right: 32px; + bottom: 120px; + z-index: 50; + min-width: 280px; + max-width: 400px; + transform: translateY(20px); + border-radius: var(--radius-sm); + background: #0f172a; + color: #ffffff; + padding: 16px 20px; + font-size: 0.9375rem; + font-weight: 500; + box-shadow: var(--shadow-lg); + opacity: 0; + transition: opacity var(--transition), transform var(--transition); + pointer-events: none; +} + +.toast.show { + opacity: 1; + transform: translateY(0); +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border: 0; +} + +.skip-link:focus-visible { + position: absolute; + top: 16px; + left: 16px; + z-index: 9999; + width: auto; + height: auto; + padding: 12px 24px; + margin: 0; + overflow: visible; + clip-path: none; + background: var(--surface); + color: var(--text); + font-weight: 600; + border-radius: var(--radius-sm); + border: 2px solid #2563eb; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 0 0 3px rgba(37, 99, 235, 0.15); + text-decoration: none; +} + +#main-content:focus { + outline: none; +} + +.modal.hidden { + display: none; +} + +.modal { + position: fixed; + inset: 0; + z-index: 60; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-backdrop { + position: absolute; + inset: 0; + background: rgba(15, 23, 42, 0.5); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); +} + +.modal-panel { + position: relative; + z-index: 1; + width: min(96vw, 1600px); + max-height: 90vh; + display: flex; + flex-direction: column; + background: #ffffff; + border-radius: var(--radius); + box-shadow: 0 25px 50px -12px rgba(15, 23, 42, 0.25); +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--border); + padding: 24px 32px; + background: #f8fafc; + border-radius: var(--radius) var(--radius) 0 0; +} + +.modal-header h2 { + margin: 0 0 6px; + font-size: 1.5rem; + font-weight: 800; + letter-spacing: -0.02em; +} + +.modal-header p { + margin: 0; + color: var(--text-muted); + font-size: 0.9375rem; +} + +.gantt-content { + overflow: auto; + padding: 32px; +} + +.gantt-shell { + display: grid; + grid-template-columns: max-content max-content; + gap: 0; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + overflow-x: auto; + overflow-y: hidden; + min-width: 0; + -webkit-overflow-scrolling: touch; + background: #ffffff; + box-shadow: var(--shadow-sm); +} + +.gantt-meta, +.gantt-chart { + min-width: 0; +} + +.gantt-meta table { + width: 100%; + border-collapse: collapse; +} + +.gantt-chart table { + width: max-content; + table-layout: fixed; + border-collapse: collapse; +} + +.gantt-meta th, +.gantt-meta td, +.gantt-chart th, +.gantt-chart td { + border-bottom: 1px solid var(--border); + background: #ffffff; + white-space: nowrap; +} + +.gantt-meta th, +.gantt-meta td { + padding: 12px 16px; + font-size: 0.875rem; +} + +.gantt-chart th, +.gantt-chart td { + min-width: 36px; + width: 36px; + max-width: 36px; + box-sizing: border-box; + padding: 4px 0; +} + +.gantt-meta thead th, +.gantt-chart thead th { + background: var(--surface-header); + position: sticky; + top: 0; + z-index: 2; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 0.75rem; + border-bottom: 1px solid var(--border-strong); +} + +.gantt-week-header { + text-align: center; + color: var(--text); + font-weight: 700; +} + +.gantt-chart .gantt-day-cell { + text-align: center; + font-family: ui-monospace, monospace; +} + +.gantt-day-cell.weekend-gap { + background: #f1f5f9; +} + +.gantt-day-track { + position: relative; + min-height: 32px; +} + +.gantt-day-track::before { + content: ''; + position: absolute; + inset: 6px 2px; + border-radius: 6px; + background: rgba(148, 163, 184, 0.08); +} + +.gantt-bar { + position: absolute; + top: 6px; + bottom: 6px; + border-radius: 6px; + transition: all var(--transition); +} + +.gantt-bar:hover { + transform: scaleY(1.1); + filter: brightness(1.1); +} + +.gantt-bar.plan { background: var(--gantt-plan); box-shadow: 0 2px 4px rgba(15, 23, 42, 0.15); } +.gantt-bar.actual { background: var(--gantt-actual); box-shadow: 0 2px 4px rgba(16, 185, 129, 0.2); } + +.table-empty, +.gantt-empty { + padding: 60px; + text-align: center; + color: var(--text-muted); + font-size: 1rem; + font-weight: 500; +} + +.empty-state-cell { + padding: 0 !important; +} + +.empty-state-cell > .table-empty { + width: min(100%, calc(100vw - var(--table-empty-page-gutter))); +} + +@media (max-width: 1400px) { + .meta-grid-primary, + .meta-grid-secondary, + .editor-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 801px) and (max-height: 960px) { + .bottom-action-bar { + position: static; + } +} + +@media (max-width: 800px) { + .app-shell { + --table-empty-page-gutter: 34px; /* 2 * 16px shell padding + 2px table-section border */ + padding: 16px; + gap: 16px; + } + + .meta-grid-primary, + .meta-grid-secondary, + .editor-grid { + grid-template-columns: 1fr; + } + + .wbs-table { + min-width: 1300px; + } + + .priority-desktop { + display: none; + } + + .bottom-action-bar { + position: static; + border-radius: var(--radius-sm); + padding: 16px; + } + + .empty-state-cell > .table-empty { + padding: 48px 24px; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + + .icon-button:hover, + .toggle-button:hover, + .primary-button:hover, + .secondary-button:hover, + .gantt-bar:hover, + .meta-field:hover, + .sync-panel:hover { + transform: none !important; + filter: none !important; + } +} + +.empty-icon { + font-size: 3rem; + margin-bottom: 16px; + opacity: 0.8; +} + +.empty-title { + margin: 0 0 8px; + font-size: 1.25rem; + font-weight: 700; + color: var(--text); +} + +.empty-desc { + margin: 0; + line-height: 1.5; +} + +/* Cloud sync auth UI (SaaS overlay) */ +.title-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; +} +.cloud-auth { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + justify-content: flex-end; +} +.cloud-select { + font: inherit; + font-size: 14px; + padding: 8px 12px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface); + color: var(--text); + max-width: 220px; +} +.cloud-panel { + max-width: 420px; + width: 100%; +} +.cloud-form { + display: flex; + flex-direction: column; + gap: 14px; + padding: 8px 4px 4px; +} +.cloud-actions { + display: flex; + gap: 10px; + margin-top: 4px; +} +.cloud-actions .primary-button { + flex: 1; +} +.cloud-error { + color: var(--danger); + font-size: 13px; + min-height: 18px; + margin: 0; +} +.cloud-name-field.hidden { + display: none; +} + +/* EVM / S-curve analytics panel (schedule-control moat) */ +.evm-panel { + margin-top: 12px; + padding: 16px 18px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + box-shadow: var(--shadow-sm); +} +.evm-metrics { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 20px; +} +.evm-metric { + display: flex; + flex-direction: column; + gap: 2px; +} +.evm-label { + font-size: 12px; + color: var(--text-muted); +} +.evm-value { + font-size: 18px; + font-weight: 700; + color: var(--text); +} +.evm-metric.evm-active .evm-value { color: var(--status-active); } +.evm-metric.evm-delay .evm-value { color: var(--status-delay); } +.evm-metric.evm-before .evm-value { color: var(--text-muted); } +.evm-badge { + margin-left: auto; + padding: 5px 12px; + border-radius: var(--radius-badge); + font-size: 13px; + font-weight: 700; + color: #ffffff; +} +.evm-badge.evm-active { background: var(--status-active); } +.evm-badge.evm-delay { background: var(--status-delay); } +.evm-badge.evm-before { background: var(--status-before); } +.evm-scurve-wrap { margin-top: 14px; } +.evm-scurve { + width: 100%; + height: 120px; + display: block; +} +.evm-grid { stroke: var(--border); stroke-width: 1; } +.evm-plan-line { fill: none; stroke: var(--gantt-plan); stroke-width: 2; } +.evm-today { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; } +.evm-ev-dot { fill: var(--gantt-actual); } +.evm-ev-dot.evm-delay { fill: var(--status-delay); } +.evm-caption { + margin: 6px 0 0; + font-size: 12px; + color: var(--text-muted); +} + +/* Team / RBAC panel */ +.team-list { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 8px; } +.team-list li { display: flex; align-items: center; gap: 8px; } +.team-who { flex: 1; font-size: 14px; color: var(--text); overflow: hidden; text-overflow: ellipsis; } +.team-role-tag { font-size: 12px; font-weight: 700; color: var(--status-active); padding: 4px 10px; } +.team-remove { padding: 6px 10px; font-size: 13px; } +.team-invite { display: flex; gap: 8px; align-items: center; margin-top: 8px; } +.team-invite input { flex: 1; font: inherit; font-size: 14px; padding: 8px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); } +.team-pending { font-size: 12px; color: var(--text-muted); margin: 8px 0 0; } + +/* Billing / plan indicator */ +.billing-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; margin-bottom: 14px; background: var(--surface-depth-3); border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; color: var(--text); } +.billing-upgrade { padding: 6px 14px; font-size: 13px; } + +/* CPM critical path */ +.cpm-summary { margin: 12px 0 0; font-size: 13px; font-weight: 600; color: var(--status-delay); } +.cpm-summary.cpm-warn { color: var(--danger); } +tbody tr.cpm-critical > td:first-child { box-shadow: inset 3px 0 0 0 var(--status-delay); } +tbody tr.cpm-critical { background: rgba(234, 88, 12, 0.04); } + +/* API token section */ +.token-section { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); } +.token-heading { margin: 0 0 10px; font-size: 15px; font-weight: 700; color: var(--text); } +.token-secret { margin: 10px 0 0; padding: 8px 10px; font-size: 12px; word-break: break-all; color: var(--status-active); background: var(--surface-depth-3); border-radius: var(--radius-sm); } +.token-secret:empty { display: none; } + +/* Audit log list */ +.audit-list { list-style: none; margin: 0; padding: 0; max-height: 180px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; } +.audit-list li { font-size: 12.5px; color: var(--text-muted); padding: 5px 0; border-bottom: 1px solid var(--depth); font-variant-numeric: tabular-nums; } + +/* Resource workload table (analytics panel) */ +.workload-wrap { overflow-x: auto; margin-top: 4px; } +.workload-table { border-collapse: collapse; font-size: 12px; } +.workload-table th, .workload-table td { border: 1px solid var(--border, #e2e8f0); padding: 4px 10px; text-align: left; } +.workload-table th { background: var(--depth, #f1f5f9); font-weight: 700; } +.workload-behind { color: #ea580c; font-weight: 700; } + +.pm-analysis { + margin-top: 14px; + padding-top: 12px; + border-top: 1px solid var(--border); +} + +.pm-title, +.pm-summary { + margin: 0 0 8px; + font-size: 13px; + font-weight: 700; +} + +.pm-summary { + color: var(--text-muted); + font-weight: 600; +} + +.pm-metrics { + margin-bottom: 8px; +} + +.pm-section-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 6px; + margin: 0; + padding: 0; + list-style: none; +} + +.pm-section-list li { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 6px 8px; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 12px; + background: #ffffff; +} + +.pm-section-list strong { + white-space: nowrap; +} + +.pm-present strong { + color: var(--status-active); +} + +.pm-missing strong { + color: var(--status-delay); +} + +.pm-recommendations { + margin: 10px 0 0; + padding-left: 20px; + color: var(--text-muted); + font-size: 12px; +} + +.pm-recommendations li + li { + margin-top: 4px; +}