filegrc 0.16.22 → 0.16.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/collection-review.js +1 -9
- package/src/program-readiness.js +3 -0
- package/src/web.js +57 -17
package/package.json
CHANGED
package/src/collection-review.js
CHANGED
|
@@ -433,15 +433,7 @@ async function requireControlReviewReady(loaded, resourceType, programId) {
|
|
|
433
433
|
if (resourceType !== "control") return;
|
|
434
434
|
const { assessProgramReadiness } = await import("./program-readiness.js");
|
|
435
435
|
const readiness = await assessProgramReadiness(loaded, { programId });
|
|
436
|
-
|
|
437
|
-
.find(({ id }) => id === "controls")
|
|
438
|
-
?.items.filter(({ id }) => (
|
|
439
|
-
id !== "collection-review-control"
|
|
440
|
-
&& !id.startsWith("document-activation-")
|
|
441
|
-
&& !id.startsWith("training-activation-")
|
|
442
|
-
&& !id.startsWith("policy-activation-")
|
|
443
|
-
)) || [];
|
|
444
|
-
if (!earlierItems.length || earlierItems.some(({ status }) => status !== "complete")) {
|
|
436
|
+
if (!readiness.controlReviewReady) {
|
|
445
437
|
throw new Error("Complete the Step 3 implementation work before recording the Control collection review. Program content activation follows this review.");
|
|
446
438
|
}
|
|
447
439
|
}
|
package/src/program-readiness.js
CHANGED
|
@@ -203,6 +203,7 @@ export async function assessProgramReadiness(input, options = {}) {
|
|
|
203
203
|
asOfTime
|
|
204
204
|
);
|
|
205
205
|
const controlOversight = collectionReviews.find(({ resourceType }) => resourceType === "control");
|
|
206
|
+
const controlReviewPrerequisiteIds = controlStage.items.map(({ id }) => id);
|
|
206
207
|
const oversightEligible = Boolean(controlOversight && controlOversightEligible(controlStage.items));
|
|
207
208
|
if (oversightEligible) {
|
|
208
209
|
controlStage.items.push(collectionReviewReadinessItem(controlOversight));
|
|
@@ -331,6 +332,8 @@ export async function assessProgramReadiness(input, options = {}) {
|
|
|
331
332
|
canStartCandidatePeriod,
|
|
332
333
|
suggestedCandidatePeriodStart: canStartCandidatePeriod ? asOf : null,
|
|
333
334
|
policyActivations,
|
|
335
|
+
controlReviewReady: oversightEligible,
|
|
336
|
+
controlReviewPrerequisiteIds,
|
|
334
337
|
documentActivations: governedContent.documentActivations,
|
|
335
338
|
trainingActivations: governedContent.trainingActivations,
|
|
336
339
|
policyLibraryProposals: [
|
package/src/web.js
CHANGED
|
@@ -1263,7 +1263,10 @@ function collectionReviewPanel(type, force = false) {
|
|
|
1263
1263
|
const proposalBlocker = !current && assessment.incompleteRecordProposals?.length
|
|
1264
1264
|
? "Complete " + assessment.incompleteRecordProposals.length + " record " + (assessment.incompleteRecordProposals.length === 1 ? "proposal" : "proposals") + " before the collection review."
|
|
1265
1265
|
: null;
|
|
1266
|
-
const
|
|
1266
|
+
const controlBlocker = type === "control" && !state.programReadiness?.controlReviewReady
|
|
1267
|
+
? "Complete the Control implementation checks listed in Step 3 before this review."
|
|
1268
|
+
: null;
|
|
1269
|
+
const reviewBlocker = scheduleBlocker || proposalBlocker || controlBlocker;
|
|
1267
1270
|
const needsFirstRecord = collectionNeedsFirstRecord(type);
|
|
1268
1271
|
const reviewerNames = (assessment.review?.reviewedByIds || [])
|
|
1269
1272
|
.map((id) => state.resources.find(({ record }) => record.id === id)?.record.title || id);
|
|
@@ -1322,27 +1325,29 @@ function collectionReviewVisible(type) {
|
|
|
1322
1325
|
}
|
|
1323
1326
|
|
|
1324
1327
|
function renderFinishStepThree() {
|
|
1325
|
-
const
|
|
1328
|
+
const readiness = state.programReadiness;
|
|
1329
|
+
const stage = readiness?.stages?.find(({ id }) => id === "controls");
|
|
1326
1330
|
const items = stage?.items || [];
|
|
1327
1331
|
const oversightItem = items.find(({ id }) => id === "collection-review-control");
|
|
1328
1332
|
const oversight = state.collectionReviews?.control;
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
const implementationItems = items.filter(({ id }) => (
|
|
1335
|
-
id !== "collection-review-control"
|
|
1336
|
-
&& !id.startsWith("document-activation-")
|
|
1337
|
-
&& !id.startsWith("training-activation-")
|
|
1338
|
-
&& !id.startsWith("policy-activation-")
|
|
1339
|
-
));
|
|
1340
|
-
const next = implementationItems.find(({ status }) => status !== "complete");
|
|
1341
|
-
if (!oversightItem) {
|
|
1333
|
+
const prerequisiteIds = new Set(readiness?.controlReviewPrerequisiteIds || []);
|
|
1334
|
+
const blockers = items.filter(({ id, status }) => prerequisiteIds.has(id) && status !== "complete");
|
|
1335
|
+
const activationItems = items.filter(({ id }) => id !== "collection-review-control" && !prerequisiteIds.has(id));
|
|
1336
|
+
if (!readiness?.controlReviewReady || !oversightItem) {
|
|
1337
|
+
const next = blockers[0];
|
|
1342
1338
|
const href = next?.id?.startsWith("source-family-")
|
|
1343
1339
|
? "#/evidence-sources"
|
|
1344
1340
|
: next ? workflowItemHref({ ...next, state: next.status }) || "#/resources/control" : "#/resources/control";
|
|
1345
|
-
|
|
1341
|
+
const blockerRows = blockers.map((item) => {
|
|
1342
|
+
const target = item.id.startsWith("source-family-") ? "#/evidence-sources"
|
|
1343
|
+
: workflowItemHref({ ...item, state: item.status }) || "#/resources/control";
|
|
1344
|
+
const resolution = item.nextSteps?.length ? item.nextSteps.join(" ")
|
|
1345
|
+
: item.id.startsWith("source-family-")
|
|
1346
|
+
? item.message + " Open Evidence Sources to assign a matching active source, access owners, and extraction instructions for every listed Control."
|
|
1347
|
+
: item.message;
|
|
1348
|
+
return '<li><a href="' + esc(target) + '"><strong>' + esc(item.title) + '</strong></a><p>' + esc(resolution) + '</p></li>';
|
|
1349
|
+
}).join("");
|
|
1350
|
+
return '<section class="finish-step panel blocked"><div><p class="kicker">Finish Step 3</p><h2>Complete implementation first</h2><p>' + esc(blockers.length ? blockers.length + " implementation " + pluralize("blocker", blockers.length) + " remain before the Control collection review." : "Finish the Step 3 work areas before the final review becomes available.") + '</p>' + (blockerRows ? '<details class="control-review-blockers"><summary>Review every blocker and its resolution</summary><ol>' + blockerRows + '</ol></details>' : "") + '</div><a class="button primary" href="' + esc(href) + '">Continue implementation</a></section>';
|
|
1346
1351
|
}
|
|
1347
1352
|
if (!oversight?.complete) {
|
|
1348
1353
|
return '<section class="finish-step-heading"><p class="kicker">Finish Step 3</p><h2>Review the implemented Control collection</h2><p>One eligible reviewer confirms the implemented Controls as a batch. Management activates the approved program content after this review.</p></section>' + collectionReviewPanel("control", true);
|
|
@@ -1868,7 +1873,12 @@ function stagePageCard(stage, destination, index) {
|
|
|
1868
1873
|
return '<a href="' + href + '"><span class="workflow-finding-status ' + esc(item.state) + '">' + esc(item.implementationState ? controlLaunchLabel(item.implementationState).split(":")[0] : properCase(item.state)) + '</span><span><strong>' + esc(item.title) + '</strong><small>' + esc(stagePageItemDetail(item)) + '</small></span></a>';
|
|
1869
1874
|
}).join("") + (items.length > 3 ? '<small class="stage-page-tasks-more">+' + (items.length - 3) + ' more on this page</small>' : "") + '</div>'
|
|
1870
1875
|
: "";
|
|
1871
|
-
|
|
1876
|
+
const proposals = stage.id === "controls" && destination.type === "obligation"
|
|
1877
|
+
? stepThreeObligationProposals().length : 0;
|
|
1878
|
+
const proposalNote = proposals
|
|
1879
|
+
? '<p class="stage-page-proposals">' + proposals + ' proposed ' + pluralize("schedule", proposals) + ' to review. These proposals do not each block Control implementation.</p>'
|
|
1880
|
+
: "";
|
|
1881
|
+
return '<article class="stage-page-card ' + (complete ? "complete" : "") + '"><div class="stage-page-card-head"><div><small>' + esc(stepLabel) + '</small><h3>' + esc(destination.label) + '</h3></div><div class="stage-page-card-actions">' + completionState + '<a class="stage-page-open" href="' + destination.href + '" aria-label="Open ' + esc(destination.label) + '"><span>Open ›</span></a></div></div><p>' + esc(summary) + '</p>' + taskPreview + proposalNote + '</article>';
|
|
1872
1882
|
}
|
|
1873
1883
|
|
|
1874
1884
|
function stagePageItemDetail(item) {
|
|
@@ -1957,6 +1967,19 @@ function derivedStagePageState(stage, destination) {
|
|
|
1957
1967
|
}
|
|
1958
1968
|
|
|
1959
1969
|
function stagePageItems(stage, destination) {
|
|
1970
|
+
if (stage.id === "controls" && destination.type === "obligation") {
|
|
1971
|
+
return (state.programReadiness?.stages?.find(({ id }) => id === "controls")?.items || [])
|
|
1972
|
+
.filter(({ id, checks }) => id.startsWith("control-") && checks?.workQueue === false)
|
|
1973
|
+
.map((item) => ({
|
|
1974
|
+
...item,
|
|
1975
|
+
key: item.id + "-work-queue",
|
|
1976
|
+
state: "ready",
|
|
1977
|
+
implementationState: null,
|
|
1978
|
+
title: "Enable a work schedule for " + item.title,
|
|
1979
|
+
message: "Review the linked Obligation proposals and enable a rule that matches this Control's operation pattern before marking it Implemented.",
|
|
1980
|
+
subject: { type: "control", id: item.resourceId }
|
|
1981
|
+
}));
|
|
1982
|
+
}
|
|
1960
1983
|
const activeStates = new Set(["blocked", "due", "later", "open", "overdue", "ready", "scheduled", "upcoming", "waiting-external"]);
|
|
1961
1984
|
const items = [
|
|
1962
1985
|
...(state.workflow?.findings || []),
|
|
@@ -2000,6 +2023,22 @@ function stagePageItems(stage, destination) {
|
|
|
2000
2023
|
));
|
|
2001
2024
|
}
|
|
2002
2025
|
|
|
2026
|
+
function stepThreeObligationProposals() {
|
|
2027
|
+
const selectedControlIds = new Set(state.programReadiness?.scope?.controlIds || []);
|
|
2028
|
+
const proposedIds = new Set(state.resources.filter(({ record }) => (
|
|
2029
|
+
record.type === "obligation"
|
|
2030
|
+
&& record.status === "proposed"
|
|
2031
|
+
&& (record.controlIds || []).some((id) => selectedControlIds.has(id))
|
|
2032
|
+
))
|
|
2033
|
+
.map(({ record }) => record.id));
|
|
2034
|
+
return (state.workflow?.findings || []).filter((item) => (
|
|
2035
|
+
item.stage === "controls"
|
|
2036
|
+
&& item.subject?.type === "obligation"
|
|
2037
|
+
&& proposedIds.has(item.subject.id)
|
|
2038
|
+
&& item.key?.endsWith(".finalize")
|
|
2039
|
+
));
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2003
2042
|
function workflowUiStage(stageId) {
|
|
2004
2043
|
return ["operate", "operation"].includes(stageId) ? "run" : stageId;
|
|
2005
2044
|
}
|
|
@@ -6618,6 +6657,7 @@ function esc(value) { return String(value ?? "").replace(/[&<>"']/g, (character)
|
|
|
6618
6657
|
|
|
6619
6658
|
export const APP_STYLES = String.raw`
|
|
6620
6659
|
.finish-step{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:24px;padding:20px 22px}.finish-step h2,.finish-step-heading h2{margin:5px 0 7px;font:500 24px Georgia,serif}.finish-step p:not(.kicker),.finish-step-heading p:not(.kicker){margin:0;color:var(--muted);font-size:12px;line-height:1.55}.finish-step.blocked{border-color:#d8bd78}.finish-step.complete{border-color:#b9dac6}.finish-step-heading{margin-top:28px;padding:20px 22px;background:var(--accent-soft);border:1px solid #cbd3ff;border-radius:11px}
|
|
6660
|
+
.finish-step.blocked>div{min-width:0;flex:1}.control-review-blockers{margin-top:13px}.control-review-blockers summary{cursor:pointer;color:var(--accent);font-size:11px;font-weight:700}.control-review-blockers ol{max-height:360px;overflow:auto;margin:10px 0 0;padding:0 14px 0 28px;border:1px solid var(--line);border-radius:8px;background:var(--surface-soft)}.control-review-blockers li{padding:11px 0;font-size:11px}.control-review-blockers li+li{border-top:1px solid var(--line)}.control-review-blockers li a{color:var(--accent)}.control-review-blockers li p{margin-top:4px!important}.stage-page-proposals{margin-top:auto!important;padding-top:12px;border-top:1px solid var(--line)}
|
|
6621
6661
|
:root{--ink:#151827;--muted:#5d6475;--line:#dfe3ef;--paper:#f6f7fb;--panel:#fff;--accent:#0000a5;--accent-soft:#eef1ff;--accent-light:#8aa1ff;--focus:#0000e0;--amber:#8a5200;--red:#a13a31;--sidebar:linear-gradient(135deg,#000070 0%,#000035 60%);--primary-gradient:linear-gradient(135deg,#000070 0%,#000035 60%);--surface-soft:#f2f4fa;--surface-muted:#eceff7;--field:#fff;--field-readonly:#eef0f6;--code-bg:#10162b;--code-ink:#e8ebff;--shadow:0 8px 28px rgba(0,0,53,.08);color-scheme:light dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--ink);background:var(--paper);font-synthesis:none}
|
|
6622
6662
|
*{box-sizing:border-box}body{margin:0;min-width:320px;background:var(--paper)}button,input,select,textarea{font:inherit}a{color:inherit}@keyframes spinner-rotate{to{transform:rotate(360deg)}}.spinner{display:inline-block;flex:0 0 auto;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spinner-rotate .7s linear infinite}.spinner-large{width:30px;height:30px;border-width:3px}.loading,.detail-loading,.muted.is-loading,.save-status.is-loading,.onboarding-save-status.is-loading,.button.is-loading{display:flex;align-items:center;gap:9px}.loading{min-height:100vh;justify-content:center;color:var(--muted)}.state-loading{display:flex;align-items:flex-start;gap:16px}.state-loading>.spinner{margin-top:5px;color:var(--accent)}.state-loading h2{margin:5px 0 8px}.state-loading p:last-child{margin:0;color:var(--muted)}.skip-link{position:fixed;left:1rem;top:-4rem;z-index:100;padding:.7rem 1rem;background:#fff}.skip-link:focus{top:1rem}.loading,.fatal{padding:3rem}.shell{display:grid;grid-template-columns:248px 1fr;min-height:100vh}.sidebar{position:fixed;inset:0 auto 0 0;width:248px;background:var(--sidebar);color:#eef1ff;padding:25px 18px 18px;overflow:auto;z-index:20}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;margin:0 7px 27px}.brand .mark{display:block;width:39px;height:39px;border-radius:10px}.brand strong,.brand small{display:block}.brand strong{color:#fff;font-size:18px}.brand small{font-size:13.2px;color:#c5cae2;margin-top:2px}.nav-home,.nav-items a{display:flex;justify-content:space-between;align-items:center;text-decoration:none;border-radius:7px;padding:8px 10px;font-size:15.6px;color:#d5d9ed}.nav-home{margin-bottom:9px}.nav-home:hover,.nav-items a:hover,.nav-home.current,.nav-items a.current{background:#202066;color:#fff}.nav-heading{width:100%;border:0;background:none;color:#b4bbdc;text-transform:uppercase;letter-spacing:.11em;font-size:12px;font-weight:750;display:flex;align-items:center;justify-content:space-between;padding:13px 10px 5px;cursor:pointer}.chevron{display:grid;place-items:center;width:14px;height:22px;font-size:0;line-height:1;transform:none}.chevron:before{content:"";width:6px;height:6px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);transform-origin:center;transition:transform .15s}.nav-items{display:none}.nav-group.open .nav-items{display:block}.nav-items small{font-size:12px;color:#b8bed7}.side-foot{position:sticky;bottom:-18px;margin:25px -18px -18px;padding:17px 25px;background:#000024;border-top:1px solid #34345f;color:#cbd0e5;font-size:13.2px;display:flex;align-items:center;gap:8px}.status-dot{width:8px;height:8px;border-radius:50%;background:#9aa39f;display:inline-block;flex:0 0 auto}.status-dot.good,.badge.good{background:#6abf8c}.status-dot.warn,.badge.warn{background:#e9a445}.status-dot.bad,.badge.bad{background:#dc6c5d}.status-dot.neutral{background:#9aabff}.workspace{grid-column:2;min-width:0}.topbar{height:86px;background:rgba(255,255,255,.88);backdrop-filter:blur(10px);border-bottom:1px solid var(--line);padding:0 32px;display:flex;align-items:center;gap:23px;position:sticky;top:0;z-index:10}.topbar>div:first-of-type{min-width:190px}.topbar h1{font-size:20.4px;line-height:1.1;margin:3px 0 0}.eyebrow,.kicker{color:var(--accent);text-transform:uppercase;letter-spacing:.12em;font-weight:760;font-size:10.8px;margin:0}.search{height:39px;max-width:240px;flex:1;margin-left:auto;display:flex;align-items:center;gap:9px;background:#f2f4fa;border:1px solid #dfe3ef;border-radius:8px;padding:0 10px;color:#5d6475}.search input{border:0;outline:0;background:none;min-width:0;flex:1;font-size:15.6px}.search kbd{background:#fff;border:1px solid #dfe3ef;border-radius:4px;padding:1px 5px;font-size:12px}.mobile-sidebar-search{display:none}.repo-chip{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:8px;padding:10px 12px;color:var(--muted);font-size:13.2px;white-space:nowrap;text-decoration:none}.mobile-nav{display:none}.page{padding:30px 34px 70px;max-width:1510px;margin:auto}.hero{color:#f8f9ff;background:linear-gradient(120deg,#000070,#000035);border-radius:13px;padding:28px 31px;display:flex;justify-content:space-between;align-items:end;min-height:158px;box-shadow:var(--shadow);position:relative;overflow:hidden}.hero:after{content:"";position:absolute;width:270px;height:270px;border:55px solid rgba(138,161,255,.1);border-radius:50%;right:-80px;top:-145px}.hero .kicker{color:#cbd3ff}.hero h2{font-family:Georgia,serif;font-weight:500;font-size:33.6px;margin:10px 0 8px;letter-spacing:-.02em}.hero p:not(.kicker){margin:0;color:#dde1f4;font-size:15.6px;max-width:650px}.hero-meta{display:flex;gap:15px;position:relative;z-index:1}.hero-meta span{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:#e6e8f7;border-left:1px solid #6874ab;padding-left:15px}.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:14px 0}.metric{background:#fff;border:1px solid var(--line);border-radius:10px;padding:16px 18px;box-shadow:0 2px 8px rgba(21,40,33,.025)}.metric-label{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);display:flex;align-items:center;gap:7px}.metric>strong{display:block;font-family:Georgia,serif;font-size:30px;font-weight:500;margin:8px 0 2px}.metric>small{font-size:12px;color:#697184}.dashboard-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.panel{background:#fff;border:1px solid var(--line);border-radius:11px;padding:21px;min-width:0;box-shadow:0 2px 8px rgba(21,40,33,.025)}.span-2{grid-column:span 2}.panel-head{display:flex;align-items:start;justify-content:space-between;gap:15px;margin-bottom:18px}.panel-head h3{font-size:16.8px;margin:4px 0 0}.panel-head>a{font-size:13.2px;color:var(--accent);font-weight:700}.audit-progress{display:grid;grid-template-columns:105px 1fr;gap:11px 20px;align-items:end}.progress-number strong{font-family:Georgia,serif;font-size:36px;font-weight:500;display:block}.progress-number span{font-size:12px;color:var(--muted)}.progress{height:9px;background:#eceff7;border-radius:9px;overflow:hidden}.progress span{display:block;height:100%;background:linear-gradient(90deg,#0000a5,var(--accent-light));border-radius:9px}.progress-meta{grid-column:2;display:flex;justify-content:space-between;font-size:10.8px;text-transform:uppercase;letter-spacing:.08em;color:#5d6475}.due-list{display:grid}.due-list a{display:grid;grid-template-columns:60px 1fr;text-decoration:none;border-top:1px solid #e8ebf3;padding:10px 0;align-items:center}.due-list a:first-child{border:0;padding-top:0}.due-list time{font-size:12px;color:var(--accent);font-weight:750}.due-list strong,.due-list small{display:block}.due-list strong{font-size:13.2px}.due-list small{font-size:10.8px;color:var(--muted);margin-top:3px}.resource-bars{display:grid;gap:11px}.resource-bars a{display:grid;grid-template-columns:105px 1fr 20px;gap:9px;align-items:center;text-decoration:none;font-size:12px}.resource-bars i{height:5px;background:#e8ebf3;border-radius:5px;overflow:hidden}.resource-bars b{display:block;height:100%;background:#6676dd;border-radius:5px}.resource-bars strong{text-align:right}.catalog{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}.catalog a{display:flex;justify-content:space-between;text-decoration:none;padding:9px 11px;background:#f2f4fa;border-radius:6px;font-size:12px}.catalog a:hover{background:var(--accent-soft)}.page-intro{display:flex;justify-content:space-between;align-items:end;margin-bottom:25px}.page-intro h2,.detail-head h2{font-family:Georgia,serif;font-size:37.2px;font-weight:500;margin:7px 0}.page-intro p:not(.kicker){color:var(--muted);max-width:700px;font-size:15.6px;margin:0}.button{border:1px solid #d0d5e3;background:#fff;border-radius:7px;padding:9px 13px;cursor:pointer;font-size:14.4px;font-weight:650}.button.primary{background:var(--accent);border-color:var(--accent);color:#fff}.button.danger{color:var(--red)}.list-tools{display:flex;align-items:center;gap:10px;margin-bottom:12px}.list-tools label{flex:1}.list-tools input,.list-tools select{width:100%;border:1px solid var(--line);border-radius:7px;background:#fff;padding:10px 12px;font-size:14.4px}.list-tools select{width:auto}.list-tools>span{color:var(--muted);font-size:12px}.record-table-wrap{background:#fff;border:1px solid var(--line);border-radius:10px;overflow:auto}.record-table{width:100%;border-collapse:collapse;font-size:13.2px}.record-table th{background:#f2f4fa;text-align:left;text-transform:uppercase;letter-spacing:.08em;color:#75817b;font-size:10.8px;padding:11px 14px;border-bottom:1px solid var(--line)}.record-table td{padding:13px 14px;border-bottom:1px solid #e8ebf3;vertical-align:top}.record-table tr:last-child td{border-bottom:0}.record-table code{font-size:10.8px;color:#5d6475}.record-title{display:block;color:var(--ink);font-weight:700;text-decoration:none}.record-table td>small{display:block;color:#6a7181;margin-top:3px}.record-table td[data-label="Description"]{min-width:260px;max-width:520px;color:var(--muted);line-height:1.45}.badge,.tag,.type-pill{display:inline-block;border-radius:99px;background:#eceff7;padding:3px 7px;font-size:10.8px;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}.tag{text-transform:none;margin:1px}.badge.status-active,.badge.status-approved,.badge.status-complete,.badge.status-passed,.badge.status-accepted{background:#ddefe5;color:#176143}.badge.status-open,.badge.status-high,.badge.status-critical,.badge.status-failed{background:#f5ded9;color:#8d352c}.badge.status-draft,.badge.status-planned,.badge.status-in-progress,.badge.status-medium{background:#f7e9cf;color:#855717}.breadcrumbs{display:flex;gap:8px;color:var(--muted);font-size:13.2px;margin-bottom:20px}.detail-head{display:flex;justify-content:space-between;align-items:end;margin-bottom:22px}.detail-head h2{margin-bottom:4px}.detail-head>div>code{font-size:12px;color:var(--muted)}.actions{display:flex;gap:7px}.detail-grid{display:grid;grid-template-columns:minmax(0,2fr) minmax(270px,1fr);gap:14px}.detail-grid aside{display:grid;gap:14px;align-content:start}.detail-main{padding:29px}.content-label{color:#75817b;text-transform:uppercase;letter-spacing:.08em;font-size:10.8px;border-bottom:1px solid var(--line);padding-bottom:13px;margin-bottom:23px}.markdown{max-width:790px}.markdown h1{font-family:Georgia,serif;font-size:34.8px;font-weight:500}.markdown h2{font-family:Georgia,serif;font-size:27.6px;font-weight:500;margin-top:1.8em}.markdown h3{font-size:18px;margin-top:1.7em}.markdown p,.markdown li{font-size:15.6px;line-height:1.65;color:#272c3b}.markdown code{background:#eef0f6;border-radius:3px;padding:1px 4px}.markdown pre{padding:15px;background:#10162b;color:#e8ebff;border-radius:7px;overflow:auto}.markdown blockquote{border-left:3px solid var(--accent-light);padding:4px 15px;color:var(--muted);margin-left:0}.table-wrap{overflow:auto}.markdown table{border-collapse:collapse;width:100%;font-size:13.2px}.markdown th,.markdown td{border:1px solid var(--line);padding:8px;text-align:left}.metadata{margin:0}.metadata>div{display:grid;grid-template-columns:105px 1fr;gap:10px;border-top:1px solid #e8ebf3;padding:10px 0}.metadata>div:first-child{border-top:0;padding-top:0}.metadata dt{font-size:10.8px;text-transform:uppercase;letter-spacing:.06em;color:#5d6475}.metadata dd{margin:0;font-size:13.2px;min-width:0}.compact-json{white-space:pre-wrap;font-size:10.8px}.git-panel>code{font-size:10.8px;word-break:break-all}.git-panel p{font-size:12px;color:var(--muted)}.relation{color:var(--accent);text-decoration:none}.history{display:grid}.history>div{display:grid;grid-template-columns:60px 1fr;gap:8px;padding:8px 0;border-top:1px solid #e8ebf3}.history>div:first-child{border-top:0}.history code{font-size:10.8px;color:var(--accent)}.history strong,.history small{display:block}.history strong{font-size:12px}.history small{font-size:10.8px;color:var(--muted);margin-top:2px}.empty{padding:25px;color:#697184;text-align:center;font-size:13.2px;background:#f4f5fa;border-radius:7px}.changes{padding-left:18px}.changes li{margin:8px 0}.diagnostics>div{display:grid;grid-template-columns:58px minmax(120px,180px) minmax(0,1fr);gap:10px;align-items:start;border-top:1px solid var(--line);padding:10px 0}.diagnostics p{margin:0;font-size:13.2px;overflow-wrap:anywhere}.diagnostics code{font-size:10.8px;overflow-wrap:anywhere}.editor,.search-results{width:min(760px,calc(100vw - 30px));border:0;border-radius:12px;padding:0;box-shadow:0 25px 80px rgba(0,0,24,.28)}dialog::backdrop{background:rgba(0,0,24,.55)}.editor form,.search-results{padding:23px}.dialog-head{display:flex;justify-content:space-between;align-items:start}.dialog-head h2{font-family:Georgia,serif;font-weight:500;margin:5px 0 0}.icon-button{border:0;background:#eceff7;width:32px;height:32px;border-radius:50%;font-size:26.4px;cursor:pointer}.editor form>p{font-size:13.2px;color:var(--muted)}.editor textarea{width:100%;height:440px;border:1px solid var(--line);border-radius:7px;background:#10162b;color:#e8ebff;padding:15px;font:13.2px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;tab-size:2px}.dialog-actions{display:flex;justify-content:end;gap:8px;margin-top:14px}.dialog-error{color:var(--red);font-size:13.2px;min-height:18px;margin-top:7px}.result-list{display:grid;margin-top:17px;max-height:60vh;overflow:auto}.result-list a{display:block;text-decoration:none;padding:11px;border-top:1px solid var(--line)}.result-list strong,.result-list small{display:block}.result-list small{color:var(--muted);margin-top:3px}.muted{color:#737a8b}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
|
|
6623
6663
|
.topbar-readiness{display:grid;grid-template-columns:minmax(0,1fr);gap:3px;flex:0 1 220px;min-width:155px;padding:5px 8px;border:1px solid transparent;border-radius:8px;color:var(--ink);text-decoration:none}.topbar-readiness:hover{border-color:var(--accent-light);background:var(--accent-soft)}.topbar-readiness-copy{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px;align-items:center}.topbar-readiness-copy>span{overflow:hidden;color:var(--muted);font-size:9.6px;font-weight:700;text-overflow:ellipsis;text-transform:uppercase;letter-spacing:.08em;white-space:nowrap}.topbar-readiness-copy>strong{font-size:10.8px;line-height:1}.topbar-readiness>.progress{width:100%;height:5px}.topbar-status{display:flex;flex:1 1 auto;min-width:0;align-items:center;justify-content:flex-end;gap:8px;margin-left:auto}.program-select select{max-width:180px;border:1px solid var(--line);border-radius:8px;padding:9px 28px 9px 10px;background:var(--surface);color:var(--ink);font:inherit}.topbar-status .topbar-search{flex:0 1 240px;width:240px;min-width:140px;margin-left:0}.repo-chip,.validation-chip{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:8px;padding:10px 12px;color:var(--muted);font-size:13.2px;white-space:nowrap;text-decoration:none}.repo-chip:hover,.validation-chip:hover{color:var(--ink);border-color:var(--accent-light)}
|