Assessor_2.0/src/styles/legacy-views.css

485 lines
19 KiB
CSS

/* Darstellung der vier Reader-Ansichten (Datensaetze, Kacheln, Raster, Rohdaten).
*
* Vollstaendig auf die Designsprache aus tokens.css umgestellt: keine rohen
* Farbwerte, keine Neomorph-Schatten, Haarlinien statt Tiefe, kleine Radien,
* hohe Dichte. Der frueher noetige Sonderblock fuer den hellen Skin ist
* entfallen - beide Skins entstehen jetzt allein aus den Tokenwerten.
*
* Farbe traegt hier ausschliesslich Bedeutung: die Severity-Hexagone und
* -Plaketten nutzen die Severity-Tokens, Auswahl nutzt --state-selected,
* gemerkte Eintraege nutzen --state-active.
*/
body {
font-family: var(--font);
font-size: var(--ui-body-size);
line-height: 1.45;
font-weight: var(--ui-body-weight);
}
button, input, select, textarea { font-family: inherit; }
.btn, .icon-btn, .select, .input, .tab-btn, .bookmark-btn, .results-btn { font-size: var(--ui-control-size); line-height: 1.35; }
.viewer { overflow: hidden; background: var(--bg); }
.viewer-scroll, .table-scroll {
height: 100%;
min-height: 0;
overflow: auto;
scrollbar-width: thin;
scrollbar-color: var(--line-strong) var(--panel-soft);
}
.viewer-scroll::-webkit-scrollbar, .table-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.viewer-scroll::-webkit-scrollbar-track, .table-scroll::-webkit-scrollbar-track { background: var(--panel-soft); }
.viewer-scroll::-webkit-scrollbar-thumb, .table-scroll::-webkit-scrollbar-thumb { border: 2px solid var(--panel-soft); border-radius: var(--radius-pill); background: var(--line-strong); }
/* Datensaetze: Trefferliste und Detailleser. */
.records-layout {
display: grid;
grid-template-columns: clamp(380px, 24vw, 470px) minmax(0, 1fr);
height: 100%;
min-height: 0;
/* Derselbe Innenabstand wie im Kachelraster. Vorher lagen die beiden Spalten
randlos auf den Kanten von `.viewer`, dadurch war dessen Rundung verdeckt
und die Ansicht wirkte als einzige nicht wie ein Panel. */
padding: var(--panel-inset);
background: var(--bg);
}
.record-list {
min-width: 0;
min-height: 0;
padding: 0;
/* Weder Rahmen noch eigene Flaeche: Liste und Leser teilen sich eine
durchgehende Panelflaeche, getrennt allein durch die Haarlinie. Eine
Trefferliste ist eine Zone, keine Karte. */
border: 0;
border-right: var(--border-hair) solid var(--border-strong);
background: transparent;
overflow-y: auto;
scrollbar-gutter: stable;
scrollbar-width: thin;
scrollbar-color: var(--border-strong) transparent;
}
.record-list::-webkit-scrollbar {
width: 6px;
}
.record-list::-webkit-scrollbar-track {
background: transparent;
margin: 4px 2px 4px 0;
}
.record-list::-webkit-scrollbar-thumb {
background: var(--border-strong);
border-radius: var(--radius-pill);
min-height: 36px;
}
.record-list::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
.record-card {
position: relative;
display: grid;
grid-template-columns: 28px minmax(0, 1fr);
grid-template-rows: auto auto;
column-gap: var(--space-2);
row-gap: var(--legacy-space-2);
width: 100%;
min-height: 74px;
margin: 0;
padding: 11px 14px;
border: 0;
/* Die Auswahlkante ist immer vorhanden, nur unsichtbar. Sonst versetzt die
aktive Zeile ihren Inhalt gegen alle anderen. */
border-left: var(--marker-width) solid transparent;
border-bottom: var(--border-hair) solid var(--line);
border-radius: 0;
color: var(--text);
background: var(--panel-raised);
box-shadow: none;
font: inherit;
text-align: left;
cursor: pointer;
transition: background .12s ease, border-color .12s ease;
}
.record-card:first-child {
border-top-left-radius: var(--radius-sm);
border-top-right-radius: var(--radius-sm);
}
.record-card:last-child {
border-bottom-left-radius: var(--radius-sm);
border-bottom-right-radius: var(--radius-sm);
border-bottom: 0;
}
.record-card::before {
content: '';
grid-column: 1;
grid-row: 1 / 3;
align-self: center;
justify-self: center;
width: 24px;
height: 27px;
clip-path: polygon(50% 0, 94% 24%, 94% 76%, 50% 100%, 6% 76%, 6% 24%);
background: var(--muted);
}
/* Haken im Hexagon. Die Severity-Flaechen sind durchgehend gesaettigt, daher
traegt der Haken die dunkle Tinte, die auch auf dem Aktivton verwendet wird. */
.record-card::after {
content: '';
grid-column: 1;
grid-row: 1 / 3;
align-self: center;
justify-self: center;
width: 7px;
height: 4px;
border-left: 2px solid var(--sev-on);
border-bottom: 2px solid var(--sev-on);
transform: translate(-6.5px, 0.5px) rotate(-45deg);
pointer-events: none;
}
.record-card:hover { border-color: var(--line); background: var(--panel-hover); box-shadow: none; transform: none; }
.record-card.active, .record-card.active:hover {
z-index: 1;
border-color: var(--line);
border-left-color: var(--state-selected-flat-border);
color: var(--state-selected-flat-text);
background: var(--state-selected-flat);
box-shadow: none;
transform: none;
}
.record-card.severity-critical::before { background: var(--critical); }
.record-card.severity-high::before { background: var(--high); }
.record-card.severity-medium::before { background: var(--medium); }
.record-card.severity-low::before { background: var(--low); }
.record-card.severity-info::before { background: var(--info); }
.record-card.is-workspace { outline: 2px solid var(--state-active); outline-offset: -2px; }
.record-title {
grid-column: 2;
grid-row: 1;
align-self: end;
min-width: 0;
color: var(--heading);
font-size: var(--type-h4-size);
font-weight: var(--fw-regular);
line-height: 1.28;
overflow-wrap: anywhere;
}
.record-meta {
min-width: 0;
color: var(--muted);
font-size: var(--ui-control-size);
font-weight: 400;
line-height: 1.3;
}
.record-meta-line {
grid-column: 2;
grid-row: 2;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--legacy-space-2);
min-width: 0;
}
.record-diagnostic-badge {
display: inline-flex;
align-items: center;
min-height: 20px;
padding: 2px var(--legacy-space-2);
border: var(--border-hair) solid var(--line-strong);
border-radius: var(--legacy-radius-sm);
color: var(--text);
background: transparent;
font-size: var(--ui-badge-size);
font-weight: var(--ui-label-weight);
line-height: 1.18;
letter-spacing: var(--ui-label-tracking);
text-transform: uppercase;
}
.record-card.active .record-title { color: var(--state-selected-flat-text); }
.record-card.active .record-meta { color: var(--state-selected-flat-muted); }
.record-card.active .record-diagnostic-badge { border-color: var(--state-selected-flat-muted); color: var(--state-selected-flat-text); }
.action-pill {
display: inline-flex;
width: fit-content;
margin-left: var(--legacy-space-1);
padding: 1px var(--legacy-space-1);
border: var(--border-hair) solid var(--success);
border-radius: var(--legacy-radius-sm);
color: var(--sev-on);
background: var(--success);
font-size: var(--ui-small-size);
line-height: 1.4;
vertical-align: middle;
}
.finding-reader {
min-width: 0;
min-height: 0;
padding: var(--legacy-space-6) 0 var(--space-7);
color: var(--text);
background: var(--bg);
overflow-y: auto;
}
/* Linksbuendig mit festem Abstand zur Trefferliste statt in der Spalte
zentriert - der Text steht damit dort, wo der Blick von der Liste kommt. */
/* Die Begrenzung ist eine Lesebreite, keine Layoutreserve: Fliesstext wie
Remediation und Likelihood of Compromise laeuft sonst ueber 1100 px und
verliert beim Zeilenwechsel den Anschluss. */
.finding-reader > * {
width: min(834px, calc(100% - var(--reader-inset) - var(--legacy-space-6)));
margin-left: var(--reader-inset);
margin-right: auto;
}
.reader-nav { margin-bottom: var(--legacy-space-6); color: var(--muted); font-size: var(--ui-control-size); }
.reader-nav button { color: var(--text); }
.reader-heading { padding-bottom: var(--legacy-space-5); border-color: var(--line); }
/* Der Fundname steht als kompakter Detailtitel eine Stufe ueber dem Inhalt. */
.reader-heading h2 {
min-width: 0;
color: var(--heading);
font-size: var(--type-detail-title-size);
font-weight: var(--ui-strong-weight);
line-height: 1.3;
letter-spacing: 0;
}
.reader-heading h2 .technical-path, .reader-summary h3 .technical-path {
display: block;
box-sizing: border-box;
width: 100%;
margin-top: var(--space-1);
}
.reader-title-hex { width: 26px; height: 30px; }
.finding-badges, .mitre-line { gap: var(--legacy-space-2); margin-top: var(--legacy-space-3); font-size: var(--ui-badge-size); }
.status-badge, .severity-badge, .mitre-badge, .reader-severity {
display: inline-flex;
align-items: center;
min-height: 22px;
height: auto;
padding: 3px var(--legacy-space-2);
border: var(--border-hair) solid var(--line-strong);
border-radius: var(--legacy-radius-sm);
color: var(--text);
background: transparent;
font-size: var(--ui-badge-size);
font-weight: var(--ui-label-weight);
line-height: 1.18;
letter-spacing: var(--ui-label-tracking);
text-transform: uppercase;
white-space: normal;
}
/* Die Plakette traegt exakt den Ton des Hexagons derselben Stufe und dieselbe
dunkle Tinte. Vorher stand hier --text-on-accent (Weiss) auf einem eigens
abgedunkelten Badgeton - zwei Rotwerte fuer dieselbe Aussage. */
.severity-badge.severity-critical, .reader-severity.severity-critical { border-color: var(--critical-badge); color: var(--severity-ink); background: var(--critical-badge); }
.severity-badge.severity-high, .reader-severity.severity-high { border-color: var(--high-badge); color: var(--severity-ink); background: var(--high-badge); }
.severity-badge.severity-medium, .reader-severity.severity-medium { border-color: var(--medium-badge); color: var(--severity-ink); background: var(--medium-badge); }
.severity-badge.severity-low, .reader-severity.severity-low { border-color: var(--low-badge); color: var(--severity-ink); background: var(--low-badge); }
.severity-badge.severity-info, .reader-severity.severity-info { border-color: var(--info-badge); color: var(--severity-ink); background: var(--info-badge); }
.reader-summary, .review-grid, .all-fields { border-color: var(--line); }
/* Die Ueberschrift des Finding-Abschnitts traegt die Pruefbeschreibung der
Regel und ist deshalb ein Satz, keine Bereichsmarke - entsprechend gesetzt. */
.reader-summary h3 { color: var(--heading); font-size: var(--type-h3-size); font-weight: var(--ui-strong-weight); line-height: 1.3; letter-spacing: 0; }
/* Der Finding-Abschnitt ist die Lesefläche des Berichts. Beschriftungen und
Fliesstext stehen deshalb auf der Lesestufe, nicht auf der dichten
Werkzeugtypografie der Leisten, Kacheln und Raster. */
.reader-summary h4 { color: var(--heading); font-size: var(--ui-reading-size); font-weight: var(--ui-label-weight); line-height: 1.25; letter-spacing: var(--ui-label-tracking); text-transform: uppercase; }
.reader-summary p, .reader-summary .rich-text-value {
color: var(--text);
font-size: var(--ui-reading-size);
font-weight: 400;
line-height: 1.55;
}
.dashboard-grid label, .review-grid > label { color: var(--heading); font-size: var(--ui-control-size); font-weight: var(--ui-label-weight); letter-spacing: var(--ui-label-tracking); }
.dashboard-grid input, .dashboard-grid select, .review-grid textarea { border-color: var(--line); background-color: var(--surface-inset); color: var(--text); }
/* Kacheln. */
/* Kacheln sind die einzige bewusst erhabene Flaeche der Anwendung: groessere
Abstaende, weiche Ecken und ein echter Schattenwurf. Alles uebrige bleibt
flach mit Haarlinien. */
.tile-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(0, var(--tile-content-width)));
align-items: stretch;
align-content: start;
justify-content: start;
gap: var(--segment-gap);
min-height: 100%;
padding: var(--segment-inset);
border: var(--border-hair) solid var(--segment-border);
border-radius: var(--segment-radius);
background: var(--segment-surface);
}
.data-tile {
position: relative;
display: grid;
grid-template-columns: 32px minmax(0, 1fr) 30px;
align-items: start;
gap: var(--legacy-space-3);
min-width: 0;
min-height: var(--tile-content-min-height);
padding: var(--legacy-space-4);
border: var(--border-hair) solid var(--tile-border);
border-radius: var(--tile-radius);
color: var(--text);
background: var(--tile-surface);
box-shadow: var(--tile-card-shadow);
cursor: pointer;
overflow: hidden;
text-align: left;
transition: background .12s ease, border-color .12s ease;
}
.data-tile:hover {
border-color: var(--tile-border);
border-radius: var(--tile-radius);
background: var(--tile-surface-hover);
box-shadow: var(--tile-card-shadow);
outline: 0;
}
.data-tile:focus-visible {
border-color: var(--tile-border);
border-radius: var(--tile-radius);
background: var(--tile-surface-hover);
box-shadow: var(--tile-card-shadow);
outline: var(--bw-emphasis) solid var(--focus-ring);
outline-offset: calc(-1 * var(--bw-emphasis));
}
.data-tile-hex {
position: relative;
width: 26px;
height: 30px;
margin-top: 1px;
clip-path: polygon(50% 0, 94% 24%, 94% 76%, 50% 100%, 6% 76%, 6% 24%);
background: var(--muted);
}
.data-tile-hex::after {
content: '';
position: absolute;
left: 2px;
top: 12px;
width: 7px;
height: 4px;
border-left: 2px solid var(--sev-on);
border-bottom: 2px solid var(--sev-on);
transform: rotate(-45deg);
pointer-events: none;
}
.data-tile.severity-critical .data-tile-hex { background: var(--critical); }
.data-tile.severity-high .data-tile-hex { background: var(--high); }
.data-tile.severity-medium .data-tile-hex { background: var(--medium); }
.data-tile.severity-low .data-tile-hex { background: var(--low); }
.data-tile.severity-info .data-tile-hex { background: var(--info); }
.data-tile-content { min-width: 0; }
/* Matrix- und Listentitel teilen die kompakte Inhaltsstufe, damit lange
Scannerbezeichnungen nicht die Kachelstruktur verdraengen. */
.data-tile-content h3 { margin: 0; color: var(--heading); font-size: var(--type-h4-size); font-weight: var(--ui-strong-weight); line-height: 1.35; overflow-wrap: normal; word-break: normal; hyphens: manual; }
/* Registry- und Policy-Pfade enthalten oft keine Leerzeichen. Nur GPO-Titel
duerfen deshalb innerhalb eines langen Pfadsegments umbrechen; normale
Findingtitel behalten ihre wortbasierte Typografie. */
.data-tile[data-tool="group-policy"] .data-tile-content h3 {
max-width: 100%;
white-space: normal;
overflow-wrap: anywhere;
word-break: normal;
}
/* Die Groesse gilt dem Outcome-Text ("IOE Found"), der sonst die 14 px des
Rumpfes erbte und damit groesser stand als dieselbe Aussage in der
Trefferliste. Die Plaketten daneben tragen ihre eigene Groesse. */
.data-tile-badges { display: flex; flex-wrap: wrap; gap: var(--legacy-space-2); margin-top: var(--legacy-space-4); font-size: var(--ui-control-size); }
/* Die regulaere Work-Kachel folgt einer festen semantischen Badge-Matrix:
Status, Kategorien, Severity/Weight und Score. Graph-Micro-Cards behalten
ihre eigene kompakte Flex-Anordnung. */
.tile-grid > .data-tile .data-tile-badges {
display: grid;
grid-template-columns: max-content max-content;
align-items: start;
justify-content: start;
}
.tile-grid > .data-tile .data-tile-badges > * { max-width: 100%; overflow-wrap: normal; word-break: normal; }
.tile-grid > .data-tile [data-badge-role="status"],
.tile-grid > .data-tile [data-badge-role="category"],
.tile-grid > .data-tile [data-badge-role="score"] { grid-column: 1 / -1; justify-self: start; }
.data-tile-actions { display: grid; gap: var(--legacy-space-2); align-content: start; }
.tile-bookmark-btn, .tile-results-btn {
display: grid;
place-items: center;
width: 28px;
height: 28px;
padding: 0;
border: var(--border-hair) solid var(--line);
border-radius: var(--legacy-radius-sm);
color: var(--text);
background: var(--panel-raised);
font-size: var(--ui-control-size);
font-weight: var(--ui-label-weight);
cursor: pointer;
}
/* Merken und geoeffnete Ergebnisse sind Werkzeugzustaende und tragen den
Aktivton, nicht den Markenakzent. */
.tile-bookmark-btn[aria-pressed="true"] { border-color: var(--state-active); color: var(--state-active-text); background: var(--state-active); }
.tile-results-btn, .tile-results-btn:hover { border-color: var(--border-results-action); color: var(--text-results-action); background: var(--surface-results-action); }
.tile-results-btn.is-open, .tile-results-btn.is-open:hover { border-color: var(--result-color); color: var(--button-accent-text); background: var(--result-color); }
.data-tile.is-bookmarked { outline: 2px solid var(--state-active); outline-offset: -2px; }
/* Raster. `.table-scroll` ist hier zugleich Scrollflaeche und Panelcontainer
und traegt deshalb selbst den Innenabstand - anders als `.viewer-scroll`,
das seinen Container (`.tile-grid`, `.raw-view`) darin fuehrt. */
.table-scroll { padding: var(--panel-inset); }
/* Die Tabelle nimmt die Breite ihres Inhalts an und scrollt waagerecht in
`.table-scroll`, statt sich in die Panelbreite zu quetschen. Zuvor erzwang
`table { width: 100% }` aus base.css bei rund dreissig Spalten Spalten von
wenigen Pixeln. */
.view-table table { width: max-content; min-width: 100%; border-color: var(--line); background: var(--panel); color: var(--text); font-size: var(--type-table-body-size); }
.view-table th, .view-table td {
min-width: var(--table-col-min-w);
max-width: min(440px, 46vw);
padding: var(--legacy-space-1) var(--legacy-space-2);
border-color: var(--line);
white-space: normal;
/* `overflow-wrap: anywhere` geht in die Mindestbreite einer Spalte ein und
erlaubt damit den Umbruch nach jedem einzelnen Zeichen. `break-word`
bricht ueberlange Werte genauso, bestimmt die Spaltenbreite aber nicht. */
overflow-wrap: break-word;
}
.view-table th {
color: var(--muted);
background: var(--panel-soft);
font-size: var(--type-table-head-size);
font-weight: var(--ui-label-weight);
line-height: 1.2;
letter-spacing: var(--ui-label-tracking);
text-transform: uppercase;
}
.view-table td { color: var(--text); background: var(--panel); font-size: var(--type-table-body-size); font-weight: 400; line-height: 1.35; }
/* Zeilenwechsel als ruhige Lesehilfe, in beiden Skins aus denselben Tokens. */
.view-table tbody tr:nth-child(even) td { background: var(--panel-soft); }
.view-table tbody tr:hover td { color: var(--heading); background: var(--panel-hover); }
.view-table .row-index { width: 54px; min-width: 54px; font-variant-numeric: tabular-nums; }
/* Rohdaten. */
.raw-view {
min-height: 100%;
margin: 0;
padding: var(--panel-inset);
color: var(--text);
background: var(--panel);
font-family: var(--font-ui);
font-size: var(--type-table-body-size);
font-weight: var(--fw-regular);
line-height: 1.5;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
/* Auf schmalen Fenstern waere der feste Leseabstand verschenkte Breite. */
@media (max-width: 1050px) {
:root { --reader-inset: var(--legacy-space-6); }
.records-layout { grid-template-columns: minmax(300px, 42%) minmax(0, 1fr); }
}
@media (max-width: 760px) {
:root { --reader-inset: var(--legacy-space-4); }
.records-layout { grid-template-columns: 1fr; }
.record-list { max-height: 320px; border-right: 0; border-bottom: var(--border-hair) solid var(--line); }
.tile-grid { grid-template-columns: 1fr; padding: var(--panel-inset); }
}
@media (prefers-reduced-motion: reduce) {
.data-tile, .record-card { transition: none; }
.record-card:hover { transform: none; }
}