Hoists 13 generic CSS components (sections 13-25 in tier3-supplement) from
ms-ai-architect inline CSS to shared/ so all 5 plugin consumers get the same
vocabulary and visual signature.
Shared additions:
- .eyebrow utility, .page__* page-shell (header/title/eyebrow/lede/meta)
- .key-stats grid + .key-stat + severity modifiers (large tabular-nums values)
- .verdict-pill-lg 5-band extension (critical/high/medium/low/positive/n-a)
- .tab-list / .tab / .tab-panel generic tab-component
- .top-risks / .top-risk[data-severity] severity-ordered risk list
- .recommendation-card[data-severity] emphasized advisory callout
- .card__head/title/desc/id/meta/hint/actions/pill subcomponents
- .card--severity-{level} 4px left-border modifier
- Form patterns (.field-row, .field-label, .field-help, .multi-select,
.checkbox-row, .required-mark)
- .stack-lg/.stack-md/.stack-sm vertical rhythm utilities
- .pyramide-tier-detail expandable details below pyramide
- .scenario-card-grid + .scenario-card[data-status="winner"] grid pattern
- .app-shell / .app-shell--wide / .app-shell--narrow page wrappers
Total: 567 new lines in tier3-supplement.css, 107 new selectors. Purely
additive — no existing selector changed or removed. v0.2 -> v0.3.
DS CHANGELOG.md updated with full v0.3 entry.
ms-ai-architect playground:
- Re-synced vendored DS to v0.3 (force flag — overwrites stale v0.2 vendor)
- Deleted 8 inline DUPLICATE definitions (.app-shell* + form patterns) now
served by shared DS
- Inline <style> block: 210 -> 202 lines (start of multi-session refactor;
remaining PARALLEL classes migrate in Session 2)
Tests: 215 + 201 + 70 + 7 = 493 PASS. No regressions.
Plugin user-facing docs (README, CLAUDE.md, marketplace landing) update in
Session 3 (Phase 9) when full v1.11.0 ships. This commit is internal
foundation work — DS CHANGELOG already documents the shared changes.
Session 1 of 3 in v1.11.0 design-system 100%-adoption refactor.
Plan: /Users/ktg/.claude/plans/jeg-skal-pr-ve-effervescent-token.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1454 lines
54 KiB
CSS
1454 lines
54 KiB
CSS
/* =============================================================================
|
|
components-tier3-supplement.css
|
|
Tier 3 supplement — 12 components added after Tier 3 main set.
|
|
Pinned rules:
|
|
- No big pink fills for text. Use surface bg + colored border + dark body text.
|
|
- severity-critical (#A40E26) ≠ state-failed (#7D1A1A). Don't conflate.
|
|
- Light + dark theme via existing tokens only.
|
|
============================================================================= */
|
|
|
|
/* =========================================================================
|
|
1. Sankey / Toxic-Flow Chain (.tfa-flow)
|
|
3-step: Input → Access → Exfil with mitigation shields breaking the chain.
|
|
========================================================================= */
|
|
.tfa-flow {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto 1fr auto 1fr;
|
|
gap: 0;
|
|
align-items: stretch;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--space-5);
|
|
position: relative;
|
|
}
|
|
.tfa-flow__verdict {
|
|
position: absolute;
|
|
top: -12px; right: var(--space-5);
|
|
padding: 4px 10px;
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-bold);
|
|
letter-spacing: 0.06em;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--color-severity-critical);
|
|
color: #fff;
|
|
}
|
|
.tfa-flow__verdict[data-verdict="ALLOW"] { background: var(--color-state-success); }
|
|
.tfa-flow__verdict[data-verdict="WARN"] { background: var(--color-severity-medium); color: #fff; }
|
|
.tfa-flow__verdict[data-verdict="BLOCK"] { background: var(--color-severity-critical); }
|
|
|
|
.tfa-leg {
|
|
display: flex; flex-direction: column; gap: 6px;
|
|
padding: var(--space-3);
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-left-width: 4px;
|
|
border-radius: var(--radius-md);
|
|
cursor: pointer;
|
|
transition: background var(--duration-fast) var(--ease-default);
|
|
text-align: left;
|
|
}
|
|
.tfa-leg:hover { background: var(--color-bg-soft); }
|
|
.tfa-leg:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
.tfa-leg[data-severity="medium"] { border-left-color: var(--color-severity-medium); }
|
|
.tfa-leg[data-severity="high"] { border-left-color: var(--color-severity-high); }
|
|
.tfa-leg[data-severity="critical"] { border-left-color: var(--color-severity-critical); }
|
|
|
|
.tfa-leg__label {
|
|
font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
|
|
color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold);
|
|
}
|
|
.tfa-leg__name { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
|
|
.tfa-leg__source { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary); }
|
|
.tfa-leg__status {
|
|
margin-top: auto;
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-medium);
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
}
|
|
.tfa-leg__status[data-mit="unmitigated"] { color: var(--color-severity-critical); }
|
|
.tfa-leg__status[data-mit="partially_mitigated"] { color: var(--color-severity-medium); }
|
|
.tfa-leg__status[data-mit="mitigated"] { color: var(--color-state-success); }
|
|
|
|
/* Arrow connectors. Width grows with severity */
|
|
.tfa-arrow {
|
|
display: flex; align-items: center; justify-content: center;
|
|
position: relative;
|
|
min-width: 56px;
|
|
padding: 0 4px;
|
|
}
|
|
.tfa-arrow__line {
|
|
height: 4px;
|
|
width: 100%;
|
|
background: var(--color-border-moderate);
|
|
position: relative;
|
|
}
|
|
.tfa-arrow[data-severity="medium"] .tfa-arrow__line { background: var(--color-severity-medium); height: 6px; }
|
|
.tfa-arrow[data-severity="high"] .tfa-arrow__line { background: var(--color-severity-high); height: 8px; }
|
|
.tfa-arrow[data-severity="critical"] .tfa-arrow__line { background: var(--color-severity-critical); height: 10px; }
|
|
.tfa-arrow__line::after {
|
|
content: ""; position: absolute; right: -1px; top: 50%;
|
|
width: 0; height: 0;
|
|
border-left: 10px solid currentColor;
|
|
border-top: 8px solid transparent;
|
|
border-bottom: 8px solid transparent;
|
|
transform: translateY(-50%);
|
|
color: inherit;
|
|
}
|
|
.tfa-arrow[data-severity="medium"] .tfa-arrow__line { color: var(--color-severity-medium); }
|
|
.tfa-arrow[data-severity="high"] .tfa-arrow__line { color: var(--color-severity-high); }
|
|
.tfa-arrow[data-severity="critical"] .tfa-arrow__line { color: var(--color-severity-critical); }
|
|
|
|
.tfa-arrow__shield {
|
|
position: absolute;
|
|
top: 50%; left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 32px; height: 32px;
|
|
background: var(--color-state-success);
|
|
color: #fff;
|
|
border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
border: 3px solid var(--color-surface);
|
|
font-size: 16px;
|
|
}
|
|
.tfa-arrow--mitigated .tfa-arrow__line {
|
|
background: repeating-linear-gradient(90deg, var(--color-state-success) 0 4px, transparent 4px 8px);
|
|
}
|
|
|
|
@media (max-width: 720px) {
|
|
.tfa-flow {
|
|
grid-template-columns: 1fr;
|
|
grid-template-rows: auto auto auto auto auto;
|
|
}
|
|
.tfa-arrow { min-height: 48px; min-width: auto; }
|
|
.tfa-arrow__line { width: 4px; height: 100%; }
|
|
.tfa-arrow[data-severity="medium"] .tfa-arrow__line { width: 6px; height: 100%; }
|
|
.tfa-arrow[data-severity="high"] .tfa-arrow__line { width: 8px; height: 100%; }
|
|
.tfa-arrow[data-severity="critical"] .tfa-arrow__line { width: 10px; height: 100%; }
|
|
.tfa-arrow__line::after {
|
|
right: 50%; top: auto; bottom: -1px; transform: translateX(50%);
|
|
border-left: 8px solid transparent;
|
|
border-right: 8px solid transparent;
|
|
border-top: 10px solid currentColor;
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
/* =========================================================================
|
|
2. Fleet-Overview (.fleet-grid, .fleet-tile)
|
|
========================================================================= */
|
|
.fleet-toolbar {
|
|
display: flex; gap: var(--space-3); flex-wrap: wrap;
|
|
align-items: center;
|
|
padding: var(--space-3) var(--space-4);
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
margin-bottom: var(--space-3);
|
|
}
|
|
.fleet-toolbar__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); }
|
|
.fleet-toolbar__spacer { flex: 1; }
|
|
.fleet-toolbar__count { font-size: var(--font-size-sm); color: var(--color-text-secondary); }
|
|
|
|
.fleet-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: var(--space-3);
|
|
}
|
|
@media (max-width: 980px) { .fleet-grid { grid-template-columns: repeat(2, 1fr); } }
|
|
@media (max-width: 540px) { .fleet-grid { grid-template-columns: 1fr; } }
|
|
|
|
.fleet-tile {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3);
|
|
display: grid;
|
|
grid-template-rows: auto auto auto auto;
|
|
gap: 6px;
|
|
cursor: pointer;
|
|
transition: border-color var(--duration-fast), transform var(--duration-fast);
|
|
}
|
|
.fleet-tile:hover { border-color: var(--color-primary-300); transform: translateY(-1px); }
|
|
.fleet-tile:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
|
|
.fleet-tile__row { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
|
|
.fleet-tile__name {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
color: var(--color-text-primary);
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
flex: 1;
|
|
}
|
|
.fleet-tile__grade {
|
|
width: 28px; height: 28px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-weight: var(--font-weight-bold);
|
|
font-size: 13px;
|
|
border-radius: var(--radius-sm);
|
|
color: #fff;
|
|
flex-shrink: 0;
|
|
}
|
|
.fleet-tile__grade[data-grade="A"] { background: var(--color-state-success); }
|
|
.fleet-tile__grade[data-grade="B"] { background: #4D8E2F; }
|
|
.fleet-tile__grade[data-grade="C"] { background: var(--color-severity-medium); }
|
|
.fleet-tile__grade[data-grade="D"] { background: var(--color-severity-high); }
|
|
.fleet-tile__grade[data-grade="E"] { background: var(--color-severity-critical); }
|
|
.fleet-tile__grade[data-grade="F"] { background: var(--color-severity-extreme); }
|
|
|
|
.fleet-tile__meter {
|
|
height: 6px; border-radius: 3px;
|
|
background: var(--color-bg-soft);
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
.fleet-tile__meter-fill { height: 100%; border-radius: 3px; }
|
|
.fleet-tile__meter-fill[data-band="1"] { background: var(--color-state-success); }
|
|
.fleet-tile__meter-fill[data-band="2"] { background: var(--color-severity-medium); }
|
|
.fleet-tile__meter-fill[data-band="3"] { background: var(--color-severity-high); }
|
|
.fleet-tile__meter-fill[data-band="4"] { background: var(--color-severity-critical); }
|
|
|
|
.fleet-tile__chip {
|
|
display: inline-flex; align-items: center;
|
|
font-size: 11px;
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--color-bg-soft);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border-subtle);
|
|
width: fit-content;
|
|
}
|
|
.fleet-tile__meta {
|
|
display: flex; justify-content: space-between;
|
|
font-size: 11px; color: var(--color-text-tertiary);
|
|
font-family: var(--font-family-mono);
|
|
}
|
|
.fleet-tile__trend--better { color: var(--color-state-success); }
|
|
.fleet-tile__trend--worse { color: var(--color-severity-critical); }
|
|
.fleet-tile__trend--stable { color: var(--color-text-tertiary); }
|
|
|
|
/* =========================================================================
|
|
3. Kanban Keep / Review / Remove (.kanban-board)
|
|
========================================================================= */
|
|
.kanban-board {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: var(--space-4);
|
|
}
|
|
@media (max-width: 820px) { .kanban-board { grid-template-columns: 1fr; } }
|
|
|
|
.kanban-col {
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3);
|
|
display: flex; flex-direction: column; gap: var(--space-3);
|
|
min-height: 320px;
|
|
}
|
|
.kanban-col__head {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding-bottom: var(--space-2);
|
|
border-bottom: 2px solid var(--color-border-subtle);
|
|
}
|
|
.kanban-col[data-bucket="keep"] .kanban-col__head { border-bottom-color: var(--color-state-success); }
|
|
.kanban-col[data-bucket="review"] .kanban-col__head { border-bottom-color: var(--color-state-warning); }
|
|
.kanban-col[data-bucket="remove"] .kanban-col__head { border-bottom-color: var(--color-severity-critical); }
|
|
|
|
.kanban-col__title { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
|
|
.kanban-col__count {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
background: var(--color-surface);
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-pill);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border-subtle);
|
|
}
|
|
|
|
.kanban-card {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3);
|
|
cursor: grab;
|
|
display: flex; flex-direction: column; gap: 6px;
|
|
transition: box-shadow var(--duration-fast);
|
|
}
|
|
.kanban-card:hover { box-shadow: var(--shadow-md); }
|
|
.kanban-card[data-verdict="BLOCK"] { border-color: var(--color-severity-critical); border-left-width: 4px; }
|
|
.kanban-card[data-verdict="trusted"] { border-left: 4px solid var(--color-state-success); }
|
|
.kanban-card[data-verdict="unknown"] { border-left: 4px solid var(--color-state-warning); }
|
|
|
|
.kanban-card__name { font-family: var(--font-family-mono); font-size: 13px; color: var(--color-text-primary); word-break: break-all; }
|
|
.kanban-card__meta { font-size: 11px; color: var(--color-text-tertiary); }
|
|
.kanban-card__reason { font-size: 12px; color: var(--color-text-secondary); }
|
|
|
|
.kanban-col__empty {
|
|
margin: auto;
|
|
text-align: center;
|
|
color: var(--color-text-tertiary);
|
|
font-size: var(--font-size-sm);
|
|
padding: var(--space-4);
|
|
}
|
|
.kanban-col__empty button { margin-top: var(--space-2); }
|
|
|
|
.kanban-actions { display: flex; gap: 4px; margin-top: 4px; }
|
|
.kanban-actions button {
|
|
flex: 1; font-size: 11px; padding: 4px 6px;
|
|
background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-sm); color: var(--color-text-secondary);
|
|
cursor: pointer; font-family: inherit;
|
|
}
|
|
.kanban-actions button:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); }
|
|
|
|
/* =========================================================================
|
|
4. Maturity-Ladder (.mat-ladder)
|
|
========================================================================= */
|
|
.mat-ladder {
|
|
display: flex; flex-direction: column;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4);
|
|
gap: 0;
|
|
}
|
|
.mat-step {
|
|
display: grid;
|
|
grid-template-columns: 56px 1fr;
|
|
gap: var(--space-4);
|
|
padding: var(--space-3) 0;
|
|
position: relative;
|
|
}
|
|
.mat-step + .mat-step { border-top: 1px dashed var(--color-border-subtle); }
|
|
|
|
.mat-step__icon {
|
|
width: 44px; height: 44px;
|
|
border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: var(--color-surface);
|
|
border: 2px solid var(--color-border-moderate);
|
|
color: var(--color-text-tertiary);
|
|
font-weight: var(--font-weight-semibold);
|
|
font-size: 15px;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
.mat-step[data-state="completed"] .mat-step__icon {
|
|
background: var(--color-state-success);
|
|
border-color: var(--color-state-success);
|
|
color: #fff;
|
|
}
|
|
.mat-step[data-state="current"] .mat-step__icon {
|
|
border-color: var(--color-primary-500);
|
|
color: var(--color-primary-700);
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
/* progress ring around current step */
|
|
.mat-step__ring {
|
|
position: absolute;
|
|
inset: -4px;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
}
|
|
.mat-step__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
|
|
.mat-step__ring circle { fill: none; stroke-width: 3; }
|
|
.mat-step__ring .ring-bg { stroke: var(--color-border-subtle); }
|
|
.mat-step__ring .ring-fill { stroke: var(--color-primary-500); }
|
|
|
|
.mat-step__name {
|
|
font-size: var(--font-size-md);
|
|
font-weight: var(--font-weight-semibold);
|
|
color: var(--color-text-primary);
|
|
display: flex; align-items: center; gap: 8px;
|
|
}
|
|
.mat-step[data-state="completed"] .mat-step__name { color: var(--color-text-secondary); }
|
|
.mat-step[data-state="future"] .mat-step__name { color: var(--color-text-tertiary); }
|
|
|
|
.mat-step__pill {
|
|
font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill);
|
|
text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--font-weight-semibold);
|
|
}
|
|
.mat-step__pill--current { background: var(--color-primary-100); color: var(--color-primary-700); }
|
|
.mat-step__pill--complete { background: transparent; color: var(--color-state-success); border: 1px solid currentColor; }
|
|
|
|
.mat-step__desc {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--color-text-secondary);
|
|
margin-top: 2px;
|
|
max-width: 60ch;
|
|
}
|
|
|
|
.mat-step__progress {
|
|
margin-top: 6px;
|
|
display: flex; align-items: center; gap: 8px;
|
|
font-size: 12px; color: var(--color-text-tertiary);
|
|
}
|
|
.mat-step__progress-bar {
|
|
flex: 1; height: 4px;
|
|
background: var(--color-bg-soft);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
max-width: 200px;
|
|
}
|
|
.mat-step__progress-fill { height: 100%; background: var(--color-primary-500); border-radius: 2px; }
|
|
|
|
/* =========================================================================
|
|
5. Classify-and-Transform / 5-Bucket-Sorter (.cls-sorter)
|
|
========================================================================= */
|
|
.cls-sorter { display: flex; flex-direction: column; gap: var(--space-4); }
|
|
|
|
.cls-input {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3);
|
|
}
|
|
.cls-input textarea {
|
|
width: 100%; min-height: 100px;
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-sm);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-sm);
|
|
padding: var(--space-2) var(--space-3);
|
|
background: var(--color-bg);
|
|
color: var(--color-text-primary);
|
|
resize: vertical;
|
|
}
|
|
.cls-input textarea:focus { outline: none; box-shadow: var(--shadow-focus); border-color: var(--color-border-focus); }
|
|
|
|
.cls-buckets {
|
|
display: grid;
|
|
grid-template-columns: repeat(5, 1fr);
|
|
gap: var(--space-3);
|
|
}
|
|
@media (max-width: 1100px) { .cls-buckets { grid-template-columns: repeat(3, 1fr); } }
|
|
@media (max-width: 720px) { .cls-buckets { grid-template-columns: repeat(2, 1fr); } }
|
|
@media (max-width: 460px) { .cls-buckets { grid-template-columns: 1fr; } }
|
|
|
|
.cls-bucket {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-top-width: 4px;
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3);
|
|
display: flex; flex-direction: column; gap: var(--space-2);
|
|
min-height: 200px;
|
|
}
|
|
.cls-bucket[data-egnethet="lav"] { border-top-color: var(--color-text-tertiary); }
|
|
.cls-bucket[data-egnethet="medium"] { border-top-color: var(--color-state-info); }
|
|
.cls-bucket[data-egnethet="hoy"] { border-top-color: var(--color-state-success); }
|
|
|
|
.cls-bucket__head {
|
|
display: flex; flex-direction: column; gap: 2px;
|
|
padding-bottom: var(--space-2);
|
|
border-bottom: 1px solid var(--color-border-subtle);
|
|
}
|
|
.cls-bucket__title { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
|
|
.cls-bucket__egnethet {
|
|
font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
|
|
color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold);
|
|
}
|
|
.cls-bucket[data-egnethet="lav"] .cls-bucket__egnethet { color: var(--color-text-tertiary); }
|
|
.cls-bucket[data-egnethet="medium"] .cls-bucket__egnethet { color: var(--color-state-info); }
|
|
.cls-bucket[data-egnethet="hoy"] .cls-bucket__egnethet { color: var(--color-state-success); }
|
|
|
|
.cls-item {
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-sm);
|
|
padding: 6px 8px;
|
|
font-size: 12px;
|
|
color: var(--color-text-primary);
|
|
cursor: grab;
|
|
display: flex; flex-direction: column; gap: 2px;
|
|
}
|
|
.cls-item__action {
|
|
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
|
|
color: var(--color-text-tertiary); font-weight: var(--font-weight-medium);
|
|
}
|
|
.cls-bucket__action {
|
|
margin-top: auto;
|
|
padding-top: var(--space-2);
|
|
border-top: 1px dashed var(--color-border-subtle);
|
|
}
|
|
.cls-bucket__empty {
|
|
font-size: 12px; color: var(--color-text-tertiary);
|
|
font-style: italic;
|
|
text-align: center;
|
|
padding: var(--space-3);
|
|
}
|
|
|
|
/* =========================================================================
|
|
6. Cycle Position Ribbon (.cycle-ribbon)
|
|
========================================================================= */
|
|
.cycle-ribbon {
|
|
position: relative;
|
|
background: var(--color-surface);
|
|
border-bottom: 1px solid var(--color-border-subtle);
|
|
padding: 8px var(--space-5);
|
|
display: flex; align-items: center; gap: var(--space-4);
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
}
|
|
.cycle-ribbon::before {
|
|
content: ""; position: absolute; inset: 0;
|
|
background: var(--color-state-info);
|
|
opacity: 0.06;
|
|
width: var(--cycle-progress, 0%);
|
|
transition: width var(--duration-normal);
|
|
}
|
|
.cycle-ribbon[data-phase="planning"] { border-bottom-color: var(--color-state-info); }
|
|
.cycle-ribbon[data-phase="planning"]::before { background: var(--color-state-info); }
|
|
.cycle-ribbon[data-phase="execution"] { border-bottom-color: var(--color-state-success); }
|
|
.cycle-ribbon[data-phase="execution"]::before { background: var(--color-state-success); }
|
|
.cycle-ribbon[data-phase="retrospective_prep"] { border-bottom-color: var(--color-severity-medium); }
|
|
.cycle-ribbon[data-phase="retrospective_prep"]::before { background: var(--color-severity-medium); }
|
|
|
|
.cycle-ribbon > * { position: relative; z-index: 1; }
|
|
.cycle-ribbon__id { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); white-space: nowrap; flex-shrink: 0; }
|
|
.cycle-ribbon__week { color: var(--color-text-secondary); font-family: var(--font-family-mono); white-space: nowrap; flex-shrink: 0; }
|
|
.cycle-ribbon__phase {
|
|
font-size: 11px; padding: 2px 8px;
|
|
border-radius: var(--radius-pill);
|
|
text-transform: uppercase; letter-spacing: 0.06em;
|
|
font-weight: var(--font-weight-semibold);
|
|
white-space: nowrap; flex-shrink: 0;
|
|
}
|
|
.cycle-ribbon[data-phase="planning"] .cycle-ribbon__phase { background: var(--color-primary-100); color: var(--color-primary-700); }
|
|
.cycle-ribbon[data-phase="execution"] .cycle-ribbon__phase { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); }
|
|
.cycle-ribbon[data-phase="retrospective_prep"] .cycle-ribbon__phase { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); }
|
|
.cycle-ribbon__msg { color: var(--color-text-secondary); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.cycle-ribbon__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); }
|
|
.cycle-ribbon[aria-expanded="true"] .cycle-ribbon__chev { transform: rotate(180deg); }
|
|
|
|
.cycle-ribbon__panel {
|
|
background: var(--color-bg-soft);
|
|
border-bottom: 1px solid var(--color-border-subtle);
|
|
padding: var(--space-4) var(--space-5);
|
|
display: none;
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
.cycle-ribbon__panel[data-open="true"] { display: block; }
|
|
|
|
@media (max-width: 720px) {
|
|
.cycle-ribbon__msg { display: none; }
|
|
}
|
|
|
|
/* =========================================================================
|
|
7. Persistent-Antipattern Badge (.pap-badge)
|
|
========================================================================= */
|
|
.pap-badge {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 4px 10px;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-severity-critical);
|
|
border-radius: var(--radius-pill);
|
|
font-size: 12px;
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--color-severity-critical);
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
.pap-badge::before {
|
|
content: "";
|
|
width: 8px; height: 8px;
|
|
border-radius: 50%;
|
|
background: var(--color-severity-critical);
|
|
animation: pap-pulse 2.4s var(--ease-default) infinite;
|
|
}
|
|
@keyframes pap-pulse {
|
|
0%, 100% { opacity: 1; transform: scale(1); }
|
|
50% { opacity: 0.45; transform: scale(0.7); }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.pap-badge::before { animation: none; opacity: 1; }
|
|
}
|
|
.pap-badge__count { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); }
|
|
|
|
.pap-detail {
|
|
margin-top: var(--space-3);
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-severity-critical);
|
|
border-left-width: 4px;
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4);
|
|
display: none;
|
|
}
|
|
.pap-detail[data-open="true"] { display: block; }
|
|
.pap-detail h4 { margin: 0 0 4px; color: var(--color-severity-critical); font-size: var(--font-size-md); }
|
|
.pap-detail__cycles { display: flex; gap: 4px; flex-wrap: wrap; margin: var(--space-2) 0; }
|
|
.pap-detail__cycle {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
padding: 2px 6px;
|
|
background: var(--color-bg-soft);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--color-text-secondary);
|
|
}
|
|
.pap-detail__rec {
|
|
background: var(--color-bg-soft);
|
|
border-radius: var(--radius-sm);
|
|
padding: var(--space-2) var(--space-3);
|
|
margin-top: var(--space-2);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--color-text-primary);
|
|
}
|
|
|
|
/* one-shot variant */
|
|
.pap-badge--oneshot {
|
|
border-style: dashed;
|
|
border-color: var(--color-severity-medium);
|
|
color: var(--color-severity-medium);
|
|
}
|
|
.pap-badge--oneshot::before { display: none; }
|
|
|
|
/* =========================================================================
|
|
8. Suppressed-Signals Panel (.suppressed)
|
|
========================================================================= */
|
|
.suppressed {
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
}
|
|
.suppressed__head {
|
|
width: 100%;
|
|
display: flex; align-items: center; gap: var(--space-3);
|
|
padding: var(--space-3) var(--space-4);
|
|
background: transparent;
|
|
border: 0;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
text-align: left;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
.suppressed__head:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); }
|
|
.suppressed__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
.suppressed__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); }
|
|
.suppressed[aria-expanded="true"] .suppressed__chev { transform: rotate(90deg); }
|
|
.suppressed__label { font-size: var(--font-size-sm); }
|
|
.suppressed__count {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
background: var(--color-surface);
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-pill);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border-subtle);
|
|
margin-left: auto;
|
|
}
|
|
|
|
.suppressed__body {
|
|
display: none;
|
|
padding: 0 var(--space-4) var(--space-4);
|
|
}
|
|
.suppressed[aria-expanded="true"] .suppressed__body { display: block; }
|
|
|
|
.suppressed-group {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-sm);
|
|
padding: var(--space-3);
|
|
}
|
|
.suppressed-group + .suppressed-group { margin-top: var(--space-2); }
|
|
.suppressed-group__head {
|
|
display: flex; justify-content: space-between; align-items: center; gap: 8px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.suppressed-group__reason { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); }
|
|
.suppressed-group__count { font-size: 11px; color: var(--color-text-tertiary); }
|
|
.suppressed-group__desc { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0 0 6px; }
|
|
.suppressed-group__examples {
|
|
display: flex; gap: 4px; flex-wrap: wrap;
|
|
}
|
|
.suppressed-group__example {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
background: var(--color-bg-soft);
|
|
padding: 2px 6px;
|
|
border-radius: var(--radius-sm);
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
/* =========================================================================
|
|
9. ExpansionCard (Aksel) (.expansion)
|
|
========================================================================= */
|
|
.expansion {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
}
|
|
.expansion + .expansion { margin-top: var(--space-2); }
|
|
.expansion__head {
|
|
width: 100%;
|
|
display: flex; align-items: flex-start; gap: var(--space-3);
|
|
padding: var(--space-3) var(--space-4);
|
|
background: transparent;
|
|
border: 0;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
text-align: left;
|
|
}
|
|
.expansion__head:hover { background: var(--color-bg-soft); }
|
|
.expansion__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
.expansion__title { flex: 1; }
|
|
.expansion__title-main { font-size: var(--font-size-md); color: var(--color-text-primary); font-weight: var(--font-weight-medium); }
|
|
.expansion__title-sub { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-top: 2px; }
|
|
.expansion__chev {
|
|
color: var(--color-text-tertiary);
|
|
transition: transform var(--duration-normal) var(--ease-default);
|
|
flex-shrink: 0;
|
|
margin-top: 2px;
|
|
}
|
|
.expansion[aria-expanded="true"] .expansion__chev { transform: rotate(180deg); }
|
|
|
|
.expansion__body {
|
|
display: grid;
|
|
grid-template-rows: 0fr;
|
|
transition: grid-template-rows var(--duration-normal) var(--ease-default);
|
|
}
|
|
.expansion[aria-expanded="true"] .expansion__body { grid-template-rows: 1fr; }
|
|
.expansion__body-inner { overflow: hidden; }
|
|
.expansion__body-inner > div {
|
|
padding: 0 var(--space-4) var(--space-4);
|
|
border-top: 1px solid var(--color-border-subtle);
|
|
padding-top: var(--space-3);
|
|
margin-top: -1px;
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.expansion__body { transition: none; }
|
|
}
|
|
|
|
/* =========================================================================
|
|
10. ReadMore (Aksel) (.read-more)
|
|
========================================================================= */
|
|
.read-more {
|
|
display: inline;
|
|
}
|
|
.read-more__trigger {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
background: transparent;
|
|
border: 0;
|
|
color: var(--color-text-link);
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
font-weight: var(--font-weight-medium);
|
|
cursor: pointer;
|
|
padding: 0;
|
|
text-decoration: underline;
|
|
text-decoration-thickness: 1px;
|
|
text-underline-offset: 3px;
|
|
}
|
|
.read-more__trigger:hover { color: var(--color-text-link-hover); }
|
|
.read-more__trigger:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: 2px; }
|
|
.read-more__chev { transition: transform var(--duration-fast); }
|
|
.read-more[aria-expanded="true"] .read-more__chev { transform: rotate(180deg); }
|
|
.read-more__body { display: none; margin-top: var(--space-2); }
|
|
.read-more[aria-expanded="true"] .read-more__body { display: block; }
|
|
|
|
/* =========================================================================
|
|
11. FormProgress (Aksel multi-step skjema) (.form-progress)
|
|
========================================================================= */
|
|
.form-progress {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4);
|
|
display: flex; flex-direction: column; gap: var(--space-3);
|
|
width: 280px;
|
|
position: sticky;
|
|
top: var(--space-4);
|
|
}
|
|
.form-progress__autosave {
|
|
display: flex; align-items: center; gap: 6px;
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
padding-bottom: var(--space-2);
|
|
border-bottom: 1px solid var(--color-border-subtle);
|
|
}
|
|
.form-progress__autosave-dot {
|
|
width: 6px; height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--color-state-success);
|
|
}
|
|
.form-progress__steps { display: flex; flex-direction: column; gap: 2px; }
|
|
.fp-step {
|
|
display: grid;
|
|
grid-template-columns: 28px 1fr;
|
|
gap: var(--space-2);
|
|
align-items: start;
|
|
padding: 8px;
|
|
border-radius: var(--radius-sm);
|
|
text-align: left;
|
|
background: transparent;
|
|
border: 0;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
position: relative;
|
|
}
|
|
.fp-step:hover { background: var(--color-bg-soft); }
|
|
.fp-step:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
.fp-step[disabled] { cursor: not-allowed; opacity: 0.5; }
|
|
|
|
.fp-step__num {
|
|
width: 22px; height: 22px;
|
|
border-radius: 50%;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: var(--color-surface);
|
|
border: 1.5px solid var(--color-border-moderate);
|
|
color: var(--color-text-tertiary);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
}
|
|
.fp-step[data-state="done"] .fp-step__num {
|
|
background: var(--color-state-success);
|
|
border-color: var(--color-state-success);
|
|
color: #fff;
|
|
}
|
|
.fp-step[data-state="in-progress"] .fp-step__num {
|
|
border-color: var(--color-primary-500);
|
|
color: var(--color-primary-700);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
.fp-step__name { font-size: var(--font-size-sm); color: var(--color-text-primary); font-weight: var(--font-weight-medium); }
|
|
.fp-step[data-state="done"] .fp-step__name { color: var(--color-text-secondary); font-weight: var(--font-weight-regular); }
|
|
.fp-step[data-state="in-progress"] .fp-step__name { color: var(--color-primary-700); font-weight: var(--font-weight-semibold); }
|
|
|
|
.fp-step__progress {
|
|
margin-top: 4px;
|
|
font-size: 11px;
|
|
color: var(--color-text-tertiary);
|
|
display: flex; align-items: center; gap: 6px;
|
|
}
|
|
.fp-step__bar {
|
|
flex: 1; height: 3px;
|
|
background: var(--color-bg-soft);
|
|
border-radius: 2px; overflow: hidden;
|
|
max-width: 80px;
|
|
}
|
|
.fp-step__bar-fill { height: 100%; background: var(--color-primary-500); }
|
|
|
|
.form-progress__remaining {
|
|
padding-top: var(--space-2);
|
|
border-top: 1px solid var(--color-border-subtle);
|
|
font-size: 12px; color: var(--color-text-tertiary);
|
|
display: flex; justify-content: space-between;
|
|
}
|
|
|
|
/* =========================================================================
|
|
12. Aspirational vs Committed Visual (.okr-mode)
|
|
Modifier added to OKR Objective cards
|
|
========================================================================= */
|
|
.okr-mode {
|
|
position: relative;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-4);
|
|
}
|
|
.okr-mode__gauge {
|
|
position: relative;
|
|
width: 88px; height: 88px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.okr-mode__gauge svg { position: absolute; inset: 0; transform: rotate(-90deg); width: 100%; height: 100%; }
|
|
.okr-mode__gauge circle.gauge-bg { fill: none; stroke: var(--color-border-subtle); stroke-width: 6; }
|
|
.okr-mode__gauge circle.gauge-fill { fill: none; stroke: var(--color-state-success); stroke-width: 6; stroke-linecap: round; }
|
|
.okr-mode__gauge .gauge-value { font-family: var(--font-family-mono); font-size: 22px; font-weight: var(--font-weight-bold); color: var(--color-text-primary); position: relative; z-index: 1; }
|
|
|
|
/* aspirational variant — dashed stroke */
|
|
.okr-mode[data-mode="aspirational"] .okr-mode__gauge circle.gauge-fill {
|
|
stroke: var(--color-scope-okr);
|
|
stroke-dasharray: 6 4;
|
|
}
|
|
.okr-mode__badge {
|
|
position: absolute;
|
|
top: var(--space-2); right: var(--space-2);
|
|
font-size: 10px; font-weight: var(--font-weight-bold); letter-spacing: 0.08em;
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
.okr-mode[data-mode="aspirational"] .okr-mode__badge {
|
|
background: transparent;
|
|
color: var(--color-scope-okr);
|
|
border: 1px dashed var(--color-scope-okr);
|
|
}
|
|
.okr-mode[data-mode="committed"] .okr-mode__badge {
|
|
background: var(--color-primary-700);
|
|
color: #fff;
|
|
}
|
|
.okr-mode__row { display: flex; gap: var(--space-4); align-items: center; }
|
|
.okr-mode__objective { font-size: var(--font-size-md); color: var(--color-text-primary); flex: 1; }
|
|
.okr-mode__hint { font-size: 12px; color: var(--color-text-tertiary); margin-top: 4px; }
|
|
|
|
/* =============================================================================
|
|
v0.3 ADDITIONS — playground/report-page foundation primitives.
|
|
Originally defined inline in plugin playgrounds (ms-ai-architect v1.10).
|
|
Hoisted here so all 5 plugin consumers share the same vocabulary.
|
|
============================================================================= */
|
|
|
|
/* =========================================================================
|
|
13. Eyebrow utility (.eyebrow)
|
|
Uppercase mini-label above section titles. Mono, generous tracking.
|
|
========================================================================= */
|
|
.eyebrow {
|
|
display: inline-block;
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--color-scope-architect, var(--color-text-link));
|
|
margin: 0 0 var(--space-2);
|
|
}
|
|
|
|
/* =========================================================================
|
|
14. Page-shell (.page__*)
|
|
Standard report-page header used by renderPageShell() in playgrounds.
|
|
eyebrow → h1 → optional lede → optional meta + verdict slot side-by-side.
|
|
========================================================================= */
|
|
.page__header {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto;
|
|
gap: var(--space-5);
|
|
align-items: start;
|
|
padding-block: var(--space-3) var(--space-4);
|
|
margin-bottom: var(--space-5);
|
|
border-bottom: 1px solid var(--color-border-subtle);
|
|
}
|
|
.page__header-main { min-width: 0; }
|
|
.page__header-aside {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
gap: var(--space-2);
|
|
}
|
|
.page__eyebrow {
|
|
display: inline-block;
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--color-scope-architect, var(--color-text-link));
|
|
margin: 0 0 var(--space-2);
|
|
}
|
|
.page__title {
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-3xl);
|
|
font-weight: var(--font-weight-bold);
|
|
letter-spacing: -0.02em;
|
|
line-height: 1.15;
|
|
color: var(--color-text-primary);
|
|
margin: 0 0 var(--space-2);
|
|
}
|
|
.page__lede {
|
|
font-size: var(--font-size-md);
|
|
line-height: 1.55;
|
|
color: var(--color-text-secondary);
|
|
max-width: 70ch;
|
|
margin: 0 0 var(--space-2);
|
|
}
|
|
.page__meta {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
display: flex;
|
|
gap: var(--space-3);
|
|
flex-wrap: wrap;
|
|
}
|
|
@media (max-width: 720px) {
|
|
.page__header { grid-template-columns: 1fr; }
|
|
.page__header-aside { align-items: flex-start; }
|
|
}
|
|
|
|
/* =========================================================================
|
|
15. Key-stats grid (.key-stats / .key-stat)
|
|
2-5 column responsive grid of large-number metrics. Uses tabular-nums for
|
|
visual alignment. Severity modifiers tint the value color.
|
|
========================================================================= */
|
|
.key-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
gap: var(--space-4);
|
|
padding: var(--space-4) var(--space-5);
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-lg);
|
|
margin-block: var(--space-4);
|
|
}
|
|
.key-stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
min-width: 0;
|
|
}
|
|
.key-stat__label {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
.key-stat__value {
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-2xl);
|
|
font-weight: var(--font-weight-bold);
|
|
letter-spacing: -0.02em;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--color-text-primary);
|
|
line-height: 1.1;
|
|
word-break: break-word;
|
|
}
|
|
.key-stat__hint {
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
margin-top: 2px;
|
|
}
|
|
.key-stat--critical .key-stat__value { color: var(--color-severity-critical); }
|
|
.key-stat--high .key-stat__value { color: var(--color-severity-high); }
|
|
.key-stat--medium .key-stat__value { color: var(--color-severity-medium); }
|
|
.key-stat--low .key-stat__value { color: var(--color-severity-low); }
|
|
.key-stat--positive .key-stat__value { color: var(--color-state-success); }
|
|
.key-stat--info .key-stat__value { color: var(--color-state-info); }
|
|
|
|
/* =========================================================================
|
|
16. Verdict-pill 5-band extension
|
|
Extends existing .verdict-pill-lg (Tier 2) to all 5 severity bands +
|
|
neutral n-a. Backward compatible — existing block/warning/allow keys
|
|
remain unchanged.
|
|
========================================================================= */
|
|
.verdict-pill-lg[data-verdict="critical"],
|
|
.verdict-pill-lg[data-verdict="extreme"] { background: var(--color-severity-critical); color: #fff; }
|
|
.verdict-pill-lg[data-verdict="high"] { background: var(--color-severity-high); color: #fff; }
|
|
.verdict-pill-lg[data-verdict="medium"] { background: var(--color-severity-medium); color: var(--color-severity-medium-on); }
|
|
.verdict-pill-lg[data-verdict="low"] { background: var(--color-severity-low); color: #fff; }
|
|
.verdict-pill-lg[data-verdict="positive"] { background: var(--color-state-success); color: #fff; }
|
|
.verdict-pill-lg[data-verdict="n-a"],
|
|
.verdict-pill-lg[data-verdict="info"],
|
|
.verdict-pill-lg[data-verdict="neutral"] {
|
|
background: var(--color-surface-sunken);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border-moderate);
|
|
}
|
|
|
|
/* =========================================================================
|
|
17. Tab-component (.tab-list / .tab / .tab-panel)
|
|
Generic tabbed interface. ARIA-paritet: role="tablist", role="tab",
|
|
aria-current="true" for active. tab-panel is hidden via [hidden] attr.
|
|
========================================================================= */
|
|
.tab-list {
|
|
display: flex;
|
|
gap: var(--space-1);
|
|
flex-wrap: wrap;
|
|
padding: 4px;
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
.tab {
|
|
appearance: none;
|
|
border: 1px solid transparent;
|
|
background: transparent;
|
|
color: var(--color-text-secondary);
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: var(--font-weight-medium);
|
|
padding: 6px var(--space-3);
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
transition: background var(--duration-fast), color var(--duration-fast);
|
|
}
|
|
.tab:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); }
|
|
.tab[aria-current="true"] {
|
|
background: var(--color-surface);
|
|
color: var(--color-text-primary);
|
|
border-color: var(--color-border-subtle);
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
.tab:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
|
|
.tab__count {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 22px;
|
|
padding: 0 6px;
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
background: var(--color-surface-sunken);
|
|
color: var(--color-text-tertiary);
|
|
border-radius: 999px;
|
|
}
|
|
.tab[aria-current="true"] .tab__count {
|
|
background: var(--color-bg-soft);
|
|
color: var(--color-text-primary);
|
|
}
|
|
.tab-panel { padding-block: var(--space-3); }
|
|
.tab-panel[hidden] { display: none; }
|
|
|
|
/* =========================================================================
|
|
18. Top-risks (.top-risks / .top-risk)
|
|
Severity-ordered list of top risk items used by ROS/security renderers.
|
|
Each row: rank dot - description - score column. Severity drives left-border.
|
|
========================================================================= */
|
|
.top-risks {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
margin-block: var(--space-4);
|
|
}
|
|
.top-risks__heading {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--color-text-tertiary);
|
|
margin: 0 0 var(--space-1);
|
|
}
|
|
.top-risk {
|
|
display: grid;
|
|
grid-template-columns: 32px 1fr auto;
|
|
gap: var(--space-3);
|
|
align-items: center;
|
|
padding: var(--space-3) var(--space-4);
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-left: 4px solid var(--color-border-moderate);
|
|
border-radius: var(--radius-md);
|
|
}
|
|
.top-risk[data-severity="critical"] { border-left-color: var(--color-severity-critical); }
|
|
.top-risk[data-severity="high"] { border-left-color: var(--color-severity-high); }
|
|
.top-risk[data-severity="medium"] { border-left-color: var(--color-severity-medium); }
|
|
.top-risk[data-severity="low"] { border-left-color: var(--color-severity-low); }
|
|
.top-risk__rank {
|
|
font-family: var(--font-family-mono);
|
|
font-size: var(--font-size-md);
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--color-text-tertiary);
|
|
text-align: center;
|
|
}
|
|
.top-risk__desc {
|
|
font-size: var(--font-size-md);
|
|
line-height: 1.4;
|
|
color: var(--color-text-primary);
|
|
min-width: 0;
|
|
}
|
|
.top-risk__score {
|
|
font-family: var(--font-family-mono);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: var(--font-weight-bold);
|
|
font-variant-numeric: tabular-nums;
|
|
padding: 4px 10px;
|
|
border-radius: var(--radius-sm);
|
|
background: var(--color-bg-soft);
|
|
color: var(--color-text-primary);
|
|
white-space: nowrap;
|
|
}
|
|
.top-risk[data-severity="critical"] .top-risk__score { background: var(--color-severity-critical-soft); color: var(--color-severity-critical-on); }
|
|
.top-risk[data-severity="high"] .top-risk__score { background: var(--color-severity-high-soft); color: var(--color-severity-high-on); }
|
|
.top-risk[data-severity="medium"] .top-risk__score { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); }
|
|
.top-risk[data-severity="low"] .top-risk__score { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); }
|
|
|
|
/* =========================================================================
|
|
19. Recommendation-card (.recommendation-card)
|
|
Emphasized advisory callout. Severity-tinted background + bold label.
|
|
Used by security/ROS recommendations and architecture-review next-actions.
|
|
========================================================================= */
|
|
.recommendation-card {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
gap: var(--space-3);
|
|
align-items: start;
|
|
padding: var(--space-4) var(--space-5);
|
|
background: var(--color-bg-soft);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-left: 4px solid var(--color-state-info);
|
|
border-radius: var(--radius-md);
|
|
margin-block: var(--space-3);
|
|
}
|
|
.recommendation-card__label {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-bold);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
padding: 4px 10px;
|
|
border-radius: var(--radius-sm);
|
|
background: var(--color-state-info);
|
|
color: #fff;
|
|
white-space: nowrap;
|
|
}
|
|
.recommendation-card__body {
|
|
font-size: var(--font-size-md);
|
|
line-height: 1.55;
|
|
color: var(--color-text-primary);
|
|
}
|
|
.recommendation-card[data-severity="critical"] { border-left-color: var(--color-severity-critical); }
|
|
.recommendation-card[data-severity="critical"] .recommendation-card__label { background: var(--color-severity-critical); }
|
|
.recommendation-card[data-severity="high"] { border-left-color: var(--color-severity-high); }
|
|
.recommendation-card[data-severity="high"] .recommendation-card__label { background: var(--color-severity-high); }
|
|
.recommendation-card[data-severity="medium"] { border-left-color: var(--color-severity-medium); }
|
|
.recommendation-card[data-severity="medium"] .recommendation-card__label { background: var(--color-severity-medium); color: var(--color-severity-medium-on); }
|
|
.recommendation-card[data-severity="low"] { border-left-color: var(--color-severity-low); }
|
|
.recommendation-card[data-severity="low"] .recommendation-card__label { background: var(--color-severity-low); }
|
|
.recommendation-card[data-severity="positive"] { border-left-color: var(--color-state-success); }
|
|
.recommendation-card[data-severity="positive"] .recommendation-card__label { background: var(--color-state-success); }
|
|
|
|
/* =========================================================================
|
|
20. Card subcomponents (.card__*)
|
|
Composable subcomponents extending the existing .card primitive (base.css).
|
|
Use as: <article class="card"><div class="card__head">...</div>...</article>
|
|
========================================================================= */
|
|
.card__head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: var(--space-3);
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
.card__title {
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-lg);
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: -0.01em;
|
|
color: var(--color-text-primary);
|
|
margin: 0;
|
|
line-height: 1.3;
|
|
}
|
|
.card__desc {
|
|
font-size: var(--font-size-sm);
|
|
line-height: 1.5;
|
|
color: var(--color-text-secondary);
|
|
margin: 0 0 var(--space-2);
|
|
}
|
|
.card__id {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
background: var(--color-surface-sunken);
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-sm);
|
|
display: inline-block;
|
|
}
|
|
.card__meta {
|
|
display: flex;
|
|
gap: var(--space-2);
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
margin-top: var(--space-2);
|
|
}
|
|
.card__hint {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
margin-top: var(--space-1);
|
|
}
|
|
.card__actions {
|
|
display: flex;
|
|
gap: var(--space-2);
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
margin-top: var(--space-3);
|
|
}
|
|
.card__pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 2px 8px;
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-semibold);
|
|
letter-spacing: 0.04em;
|
|
text-transform: uppercase;
|
|
background: var(--color-surface-sunken);
|
|
color: var(--color-text-secondary);
|
|
border-radius: 999px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Severity left-border modifier on cards */
|
|
.card--severity-critical { border-left: 4px solid var(--color-severity-critical); }
|
|
.card--severity-high { border-left: 4px solid var(--color-severity-high); }
|
|
.card--severity-medium { border-left: 4px solid var(--color-severity-medium); }
|
|
.card--severity-low { border-left: 4px solid var(--color-severity-low); }
|
|
.card--severity-positive { border-left: 4px solid var(--color-state-success); }
|
|
.card--severity-info { border-left: 4px solid var(--color-state-info); }
|
|
|
|
/* =========================================================================
|
|
21. Form patterns (.field-row / .field-label / .field-help / etc)
|
|
Standard form-field building blocks. Mirrors Aksel/Digdir conventions.
|
|
========================================================================= */
|
|
.field-row {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
.field-row + .field-row { margin-top: var(--space-3); }
|
|
.field-label {
|
|
font-size: var(--font-size-sm);
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--color-text-primary);
|
|
}
|
|
.field-help {
|
|
font-size: var(--font-size-xs);
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
.required-mark {
|
|
color: var(--color-severity-critical);
|
|
margin-left: 2px;
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
.multi-select {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
border: 0;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
.checkbox-row {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
cursor: pointer;
|
|
font-size: var(--font-size-sm);
|
|
padding: 4px 0;
|
|
color: var(--color-text-primary);
|
|
}
|
|
.checkbox-row input { margin: 0; }
|
|
.checkbox-row:hover { color: var(--color-text-link); }
|
|
|
|
/* =========================================================================
|
|
22. Section-spacing utility (.stack-lg / .stack-md / .stack-sm)
|
|
Consistent vertical rhythm between major sections.
|
|
========================================================================= */
|
|
.stack-lg > * + * { margin-top: var(--space-8); }
|
|
.stack-md > * + * { margin-top: var(--space-5); }
|
|
.stack-sm > * + * { margin-top: var(--space-3); }
|
|
|
|
/* =========================================================================
|
|
23. Pyramide-tier-detail (.pyramide-tier-detail)
|
|
Expandable details below a .pyramide visualization. Used by AI Act
|
|
classification renderer to describe each tier's obligations.
|
|
========================================================================= */
|
|
.pyramide-tier-detail {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-3) var(--space-4);
|
|
margin-top: var(--space-2);
|
|
}
|
|
.pyramide-tier-detail summary {
|
|
cursor: pointer;
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-md);
|
|
font-weight: var(--font-weight-semibold);
|
|
color: var(--color-text-primary);
|
|
list-style: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
.pyramide-tier-detail summary::-webkit-details-marker { display: none; }
|
|
.pyramide-tier-detail summary::before {
|
|
content: "\25B8";
|
|
font-size: 11px;
|
|
color: var(--color-text-tertiary);
|
|
transition: transform var(--duration-fast);
|
|
display: inline-block;
|
|
}
|
|
.pyramide-tier-detail[open] summary::before { transform: rotate(90deg); }
|
|
.pyramide-tier-detail__body {
|
|
font-size: var(--font-size-sm);
|
|
line-height: 1.55;
|
|
color: var(--color-text-secondary);
|
|
margin-top: var(--space-2);
|
|
padding-left: var(--space-3);
|
|
}
|
|
|
|
/* =========================================================================
|
|
24. Scenario-card-grid (.scenario-card-grid / .scenario-card)
|
|
Grid of scenario/option cards used by license, compare renderers.
|
|
Each card: header (title + count) -> optional source line -> optional body.
|
|
========================================================================= */
|
|
.scenario-card-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
gap: var(--space-3);
|
|
margin-block: var(--space-3);
|
|
}
|
|
.scenario-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
padding: var(--space-4);
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border-subtle);
|
|
border-radius: var(--radius-md);
|
|
transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
|
|
}
|
|
.scenario-card:hover { border-color: var(--color-border-moderate); box-shadow: var(--shadow-sm); }
|
|
.scenario-card__head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: var(--space-2);
|
|
}
|
|
.scenario-card__title {
|
|
font-family: var(--font-family-sans);
|
|
font-size: var(--font-size-md);
|
|
font-weight: var(--font-weight-semibold);
|
|
color: var(--color-text-primary);
|
|
margin: 0;
|
|
line-height: 1.3;
|
|
}
|
|
.scenario-card__count {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 24px;
|
|
padding: 2px 8px;
|
|
font-family: var(--font-family-mono);
|
|
font-size: 11px;
|
|
font-weight: var(--font-weight-bold);
|
|
background: var(--color-bg-soft);
|
|
color: var(--color-text-secondary);
|
|
border-radius: 999px;
|
|
}
|
|
.scenario-card__source {
|
|
font-family: var(--font-family-mono);
|
|
font-size: 12px;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
.scenario-card[data-status="winner"] {
|
|
border-color: var(--color-state-success);
|
|
background: var(--color-severity-low-soft);
|
|
}
|
|
.scenario-card[data-status="winner"] .scenario-card__count {
|
|
background: var(--color-state-success);
|
|
color: #fff;
|
|
}
|
|
|
|
/* =========================================================================
|
|
25. App-shell utility (.app-shell)
|
|
Centered max-width page wrapper. Hoisted from playgrounds - every plugin
|
|
playground uses the same shell pattern.
|
|
========================================================================= */
|
|
.app-shell {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: var(--space-6) var(--space-5);
|
|
}
|
|
.app-shell--wide { max-width: 1400px; }
|
|
.app-shell--narrow { max-width: 880px; }
|