/* ========================================================================== ASSESSOR Komponenten-Referenz -------------------------------------------------------------------------- Projektkopie von .claude/skills/assessor-ui/assets/components.css. Aenderungen gehoeren zuerst in die Skill-Datei, dann hierher. Verbindliche Implementierung. Diese Datei wird erweitert, nicht ueberschrieben. Keine Regel ausserhalb der Layer. Kein !important. Keine Seitenselektoren (kein `.page-datahub .btn { ... }`). Layer-Reihenfolge zwingend: @layer tokens, base, shell, components, utilities; ========================================================================== */ @layer components { /* ========================================================================== 1. BUTTONS Hierarchie: pro Ansicht genau EIN Primary. Alles andere Secondary/Ghost. Destructive nur fuer irreversible Datenaktionen. ========================================================================== */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); height: var(--control-h); padding: 2px 8px; border: 1px solid var(--button-border); border-radius: 0; color: var(--button-text); background: var(--button-bg); font: var(--fw-medium) var(--fs-base) / 1.15 var(--font-ui); white-space: nowrap; cursor: pointer; transition: background-color var(--dur-fast) var(--ease); } .btn:focus-visible { outline: 1px solid var(--focus-ring); outline-offset: 1px; } .btn[disabled] { color: var(--text-disabled); background: var(--surface-panel); border-color: var(--button-border); cursor: not-allowed; opacity: 0.5; } .btn--primary, .btn.primary { background: var(--button-marked-bg); color: var(--button-marked-text); border-color: var(--button-border); font-weight: 600; } .btn--primary:hover, .btn.primary:hover { background: var(--button-marked-bg-hover); border-color: var(--button-border); } .btn--primary:active, .btn.primary:active { background: var(--band-surface-active); border-color: var(--button-border); } .btn--secondary, .btn.secondary { background: var(--button-bg); color: var(--button-text); border-color: var(--button-border); } .btn--secondary:hover, .btn.secondary:hover { background: var(--button-bg-hover); border-color: var(--button-border); } .btn--secondary:active, .btn.secondary:active { background: var(--surface-active); border-color: var(--button-border); } .btn--ghost { background: transparent; color: var(--text-secondary); border-color: var(--button-border); } .btn--ghost:hover { background: var(--button-bg-hover); color: var(--text-primary); border-color: var(--button-border); } .btn--destructive, .btn.danger { background: var(--button-bg); color: var(--button-text); border-color: var(--button-border); } .btn--destructive:hover, .btn.danger:hover { background: var(--sev-critical); color: var(--sev-on); border-color: var(--button-border); } .btn--sm { height: var(--control-h-sm); padding: 1px 6px; font-size: var(--fs-sm); } /* Icon-Button: quadratisch, nur Icon, immer mit aria-label */ .icon-btn { display: inline-flex; align-items: center; justify-content: center; width: var(--icon-btn); height: var(--icon-btn); padding: 0; background: var(--button-bg); color: var(--button-text); border: 1px solid var(--button-border); border-radius: 0; cursor: pointer; } .icon-btn:hover { background: var(--button-bg-hover); color: var(--button-text); border-color: var(--button-border); } .icon-btn:focus-visible { outline: 1px solid var(--focus-ring); outline-offset: 1px; } .icon-btn[aria-pressed="true"], .icon-btn.active { background: var(--button-marked-bg); color: var(--button-marked-text); border-color: var(--button-border); } /* ========================================================================== 2. EINGABEN ========================================================================== */ .field { display: flex; flex-direction: column; gap: var(--space-1); } .field__label { font: var(--fw-medium) var(--fs-micro) / 1.2 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); } .input, .select, .textarea { width: 100%; height: var(--control-h); padding: 0 var(--space-2); background: var(--surface-input); color: var(--text-primary); border: var(--bw-hairline) solid var(--border-default); border-radius: var(--radius-sm); font: var(--fw-regular) var(--fs-base) / 1 var(--font-ui); } .textarea { height: auto; min-height: calc(var(--control-h) * 2); max-height: calc(var(--control-h) * 4); padding: var(--space-2); line-height: var(--lh-ui); resize: vertical; } .input::placeholder, .textarea::placeholder { color: var(--text-muted); } .input:hover, .select:hover, .textarea:hover { border-color: var(--border-strong); } .input:focus-visible, .select:focus-visible, .textarea:focus-visible { border-color: var(--accent); outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: -1px; } .input[aria-invalid="true"] { border-color: var(--sev-critical); } /* Technische Werte: DN, Timestamps, Hashes, IDs, Scores */ .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; } /* Segmented Control: 2 bis 5 sich ausschliessende Optionen */ .segmented { display: inline-flex; padding: 2px; background: var(--surface-input); border: var(--bw-hairline) solid var(--border-default); border-radius: var(--radius-sm); } .segmented__item { height: calc(var(--control-h) - 6px); padding: 0 var(--space-3); background: transparent; color: var(--text-secondary); border: 0; border-radius: var(--radius-xs); font: var(--fw-medium) var(--fs-sm) / 1 var(--font-ui); cursor: pointer; } .segmented__item[aria-selected="true"] { background: var(--accent); color: var(--accent-on); } .segmented__item:focus-visible { outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: 1px; } /* ========================================================================== 3. COMMAND BAND Signaturelement. Enthaelt Filter- und Scope-Controls. Regel: ALLE Controls im Band tragen die Band-Optik. Kein Mischbetrieb. ========================================================================== */ .band { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-height: var(--band-row-h); padding: var(--space-1) var(--space-3); background: var(--surface-app); border-bottom: var(--bw-hairline) solid var(--border-subtle); } .band__control { height: calc(var(--band-row-h) - 8px); padding: 0 var(--space-2); background: var(--band-surface); color: var(--band-text); border: var(--bw-hairline) solid var(--band-border); border-radius: var(--radius-sm); font: var(--fw-medium) var(--fs-sm) / 1 var(--font-ui); cursor: pointer; } .band__control:hover { background: var(--band-surface-hover); } .band__control:focus-visible { outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: 1px; } /* Freitextfilter: neutral, damit die Bandfarbe nicht als Eingabeaufforderung wirkt */ .band__search { flex: 1 1 240px; height: calc(var(--band-row-h) - 8px); padding: 0 var(--space-2); background: var(--surface-input); color: var(--text-primary); border: var(--bw-hairline) solid var(--border-default); border-radius: var(--radius-sm); font: var(--fw-regular) var(--fs-sm) / 1 var(--font-ui); } /* Aktiver Filter mit Treffermenge */ .band__control[data-active="true"]::after { content: " \00B7 " attr(data-count); font-variant-numeric: tabular-nums; } /* ========================================================================== 4. ZUSTANDSDARSTELLUNG Drei formal unterscheidbare Familien. Form traegt Bedeutung, nicht nur Farbe. ========================================================================== */ /* 4.1 Severity: gefuellt, rechteckig, Versalien. Nur hier gefuellte Farbe. */ .sev { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; background: var(--sev-unknown); color: var(--sev-on); border-radius: var(--radius-xs); font: var(--fw-semibold) var(--fs-micro) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; } .sev[data-sev="critical"] { background: var(--sev-critical); } .sev[data-sev="high"] { background: var(--sev-high); } .sev[data-sev="medium"] { background: var(--sev-medium); } .sev[data-sev="low"] { background: var(--sev-low); } .sev[data-sev="info"] { background: var(--sev-info); } /* Severity-Kante: zweites, nicht farbabhaengiges Signal an Zeile/Tile/Card */ .sev-edge { box-shadow: inset 3px 0 0 0 var(--sev-unknown); } .sev-edge[data-sev="critical"] { box-shadow: inset 3px 0 0 0 var(--sev-critical); } .sev-edge[data-sev="high"] { box-shadow: inset 3px 0 0 0 var(--sev-high); } .sev-edge[data-sev="medium"] { box-shadow: inset 3px 0 0 0 var(--sev-medium); } .sev-edge[data-sev="low"] { box-shadow: inset 3px 0 0 0 var(--sev-low); } .sev-edge[data-sev="info"] { box-shadow: inset 3px 0 0 0 var(--sev-info); } /* 4.2 Meta-Badge: neutral gefuellt. Kategorie, Tool, IOE, Weight, Score, MITRE. */ .badge { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; background: var(--surface-panel-raised); color: var(--text-secondary); border: var(--bw-hairline) solid var(--border-default); border-radius: var(--radius-xs); font: var(--fw-medium) var(--fs-micro) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; white-space: nowrap; } .badge--numeric { font-family: var(--font-mono); letter-spacing: 0; text-transform: none; } /* 4.2b Value-Display (Ableton Live DAW Aesthetic - Bild 1): Rein informative Wertanzeigen */ .value-display-group { display: inline-flex; align-items: center; gap: var(--space-2); padding: 3px 8px; border: var(--bw-hairline) solid var(--border-default); border-radius: 0; background: var(--surface-panel-raised); } .value-display-item { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-secondary); font: var(--fw-medium) var(--fs-sm) / 1 var(--font-ui); } .value-display-label { color: var(--text-secondary); font-size: var(--fs-sm); font-weight: var(--fw-medium); } .value-display-box, .value-box { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 22px; padding: 1px 6px; border: var(--bw-hairline) solid var(--border-default); border-radius: 0; background: var(--surface-input); color: var(--text-primary); font-family: var(--font-ui); font-size: var(--fs-base); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; line-height: 1; text-align: center; } /* 4.3 Workflow-Chip: Outline plus Punkt. Nie gefuellt. */ .chip { display: inline-flex; align-items: center; gap: 6px; height: 20px; padding: 0 var(--space-2); background: transparent; color: var(--text-secondary); border: var(--bw-hairline) solid var(--border-default); border-radius: var(--radius-xs); font: var(--fw-medium) var(--fs-micro) / 1 var(--font-ui); } .chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--state-open); } .chip[data-state="progress"]::before { background: var(--state-progress); } .chip[data-state="done"]::before { background: var(--state-done); } .chip[data-state="blocked"]::before { background: var(--state-blocked); } .chip[data-state="accepted"] { border-style: dashed; } .chip[data-state="accepted"]::before { background: var(--state-accepted); } /* 4.4 Outcome: Text plus Glyph. Niemals gefuellt, niemals gruen. */ .outcome { display: inline-flex; align-items: center; gap: 6px; color: var(--outcome-idle); font: var(--fw-medium) var(--fs-sm) / 1 var(--font-ui); } .outcome::before { content: "\2013"; } .outcome[data-outcome="fail"] { color: var(--outcome-fail); } .outcome[data-outcome="fail"]::before { content: "\25CF"; } .outcome[data-outcome="pass"] { color: var(--outcome-pass); } .outcome[data-outcome="pass"]::before { content: "\25CB"; } .outcome[data-outcome="warning"] { color: var(--outcome-warning); } .outcome[data-outcome="warning"]::before { content: "\25D0"; } .outcome[data-outcome="execution_error"] { color: var(--outcome-error); } .outcome[data-outcome="execution_error"]::before { content: "\2715"; } /* 4.5 Bookmark: Iconfuellung plus rechte Kante. Getrennt von Severity. */ .is-bookmarked { box-shadow: inset -3px 0 0 0 var(--state-bookmark); } .is-bookmarked.sev-edge[data-sev="critical"] { box-shadow: inset 3px 0 0 0 var(--sev-critical), inset -3px 0 0 0 var(--state-bookmark); } .is-bookmarked.sev-edge[data-sev="high"] { box-shadow: inset 3px 0 0 0 var(--sev-high), inset -3px 0 0 0 var(--state-bookmark); } .is-bookmarked.sev-edge[data-sev="medium"] { box-shadow: inset 3px 0 0 0 var(--sev-medium), inset -3px 0 0 0 var(--state-bookmark); } .is-bookmarked.sev-edge[data-sev="low"] { box-shadow: inset 3px 0 0 0 var(--sev-low), inset -3px 0 0 0 var(--state-bookmark); } .is-bookmarked.sev-edge[data-sev="info"] { box-shadow: inset 3px 0 0 0 var(--sev-info), inset -3px 0 0 0 var(--state-bookmark); } /* 4.6 Datenvollstaendigkeit */ .is-incomplete { border-style: dashed; } /* ========================================================================== 5. LISTENZEILE (Master-Liste) ========================================================================== */ .row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-2); min-height: calc(var(--row-h) * 2); padding: var(--space-2) var(--space-3); background: var(--surface-panel); border: var(--bw-hairline) solid var(--border-subtle); border-radius: var(--radius-sm); cursor: pointer; } .row + .row { margin-top: var(--space-1); } .row:hover { background: var(--surface-hover); border-color: var(--border-default); } .row[aria-selected="true"] { background: var(--surface-selected); border-color: var(--selection-border); border-width: var(--bw-emphasis); padding: calc(var(--space-2) - 1px) calc(var(--space-3) - 1px); } .row:focus-visible { outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: -1px; } .row__title { font: var(--fw-semibold) var(--fs-md) / var(--lh-ui) var(--font-ui); color: var(--text-primary); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .row__meta { margin-top: 2px; font: var(--fw-regular) var(--fs-sm) / 1.3 var(--font-ui); color: var(--text-secondary); } /* ========================================================================== 6. TILE (Kachelansicht) Feste Hoehe. Kein ragged bottom. Aktionen ausschliesslich in der Fusszeile. ========================================================================== */ .tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(0, var(--tile-content-width))); justify-content: start; gap: var(--segment-gap); padding: var(--segment-inset); border: var(--bw-hairline) solid var(--segment-border); border-radius: var(--segment-radius); background: var(--segment-surface); } .tile { display: grid; grid-template-rows: auto 1fr auto; min-width: 0; height: var(--tile-h); padding: var(--space-2) var(--space-3); background: var(--tile-surface); border: var(--bw-hairline) solid var(--tile-border); border-radius: var(--tile-radius); box-shadow: var(--tile-card-shadow); cursor: pointer; overflow: hidden; } .tile:hover { background: var(--tile-surface-hover); border-color: var(--border-strong); } .tile[aria-selected="true"] { background: var(--tile-surface-hover); border-color: var(--tile-selected-border); border-width: var(--bw-emphasis); padding: calc(var(--space-2) - 1px) calc(var(--space-3) - 1px); } .tile:focus-visible { outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: -1px; } .tile__title { font: var(--fw-semibold) var(--fs-md) / var(--lh-ui) var(--font-ui); color: var(--text-primary); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .tile__badges { display: flex; flex-wrap: nowrap; gap: var(--space-1); align-items: center; align-self: center; overflow: hidden; } .tile__footer { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding-top: var(--space-1); border-top: var(--bw-hairline) solid var(--border-subtle); } /* ========================================================================== 7. TABELLE Kopf und Koerper teilen dieselbe Groessenklasse. Keine verschachtelten Tabellen. Keine Tabelle in einer Karte. ========================================================================== */ .table { width: 100%; border-collapse: collapse; } .table thead th { position: sticky; top: 0; z-index: 1; height: var(--row-h); padding: 0 var(--space-2); background: var(--surface-panel-raised); color: var(--text-muted); border-bottom: var(--bw-hairline) solid var(--border-default); font: var(--fw-medium) var(--fs-micro) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; text-align: left; white-space: nowrap; } .table tbody td { height: var(--row-h); padding: 0 var(--space-2); background: var(--surface-panel); color: var(--text-primary); border-bottom: var(--bw-hairline) solid var(--border-subtle); font: var(--fw-regular) var(--fs-sm) / var(--lh-ui) var(--font-ui); text-align: left; /* Text linksbuendig, immer */ } .table td.is-numeric, .table th.is-numeric { text-align: right; font-variant-numeric: tabular-nums; } .table tbody tr:hover td { background: var(--surface-hover); } .table tbody tr[aria-selected="true"] td { background: var(--surface-selected); box-shadow: inset 0 0 0 1px var(--selection-border); } .table tbody tr:focus-visible { outline: var(--bw-emphasis) solid var(--focus-ring); outline-offset: -2px; } /* ========================================================================== 8. FACET RAIL (nur Archetyp Datentabelle) ========================================================================== */ .facets { width: var(--facetrail-w); flex: 0 0 var(--facetrail-w); overflow-y: auto; background: var(--surface-panel-raised); border-right: var(--bw-hairline) solid var(--border-subtle); padding: var(--space-2); } .facets__group + .facets__group { margin-top: var(--space-3); } .facets__legend { font: var(--fw-medium) var(--fs-micro) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); padding: 0 var(--space-1) var(--space-1); } .facets__item { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-2); height: var(--control-h-sm); padding: 0 var(--space-1); border-radius: var(--radius-xs); font: var(--fw-regular) var(--fs-sm) / 1 var(--font-ui); color: var(--text-secondary); cursor: pointer; } .facets__item:hover { background: var(--surface-hover); color: var(--text-primary); } .facets__count { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text-muted); } /* ========================================================================== 9. INSPECTOR (persistentes Detailpanel) ========================================================================== */ .inspector { width: var(--inspector-w); flex: 0 0 var(--inspector-w); display: flex; flex-direction: column; background: var(--surface-panel-raised); border-left: var(--bw-hairline) solid var(--border-subtle); overflow-y: auto; } .inspector__header { position: sticky; top: 0; z-index: 1; padding: var(--space-3); background: var(--surface-panel-raised); border-bottom: var(--bw-hairline) solid var(--border-subtle); } .inspector__title { font: var(--fw-semibold) var(--fs-lg) / var(--lh-ui) var(--font-ui); color: var(--text-primary); } .inspector__section { padding: var(--space-3); border-bottom: var(--bw-hairline) solid var(--border-subtle); } .inspector__legend { font: var(--fw-medium) var(--fs-micro) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); margin-bottom: var(--space-2); } .inspector__prose { font: var(--fw-regular) var(--fs-base) / var(--lh-prose) var(--font-ui); color: var(--text-secondary); } .inspector__prose strong { color: var(--text-primary); font-weight: var(--fw-semibold); } /* Key-Value-Liste */ .kv { display: grid; grid-template-columns: 128px 1fr; gap: var(--space-1) var(--space-3); } .kv dt { font: var(--fw-medium) var(--fs-micro) / var(--lh-ui) var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); } .kv dd { font: var(--fw-regular) var(--fs-sm) / var(--lh-ui) var(--font-ui); color: var(--text-primary); margin: 0; } /* ========================================================================== 10. OVERLAYS Titelleisten sind IMMER neutral. Keine akzentfarbene Titelleiste. ========================================================================== */ .overlay-titlebar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); height: var(--topbar-h); padding: 0 var(--space-2) 0 var(--space-3); background: var(--surface-shell); border-bottom: var(--bw-hairline) solid var(--border-default); cursor: move; } .overlay-titlebar__title { font: var(--fw-semibold) var(--fs-sm) / 1 var(--font-ui); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-primary); } /* Floating Window: nicht modal, verschiebbar, groessenveraenderlich */ .floatwin { position: fixed; display: flex; flex-direction: column; min-width: 480px; min-height: 320px; max-width: 90vw; max-height: 80vh; background: var(--surface-overlay); border: var(--bw-hairline) solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-overlay); resize: both; overflow: hidden; } .floatwin__body { flex: 1; overflow: auto; } /* Dialog: blockierend, nur fuer Entscheidungen */ .dialog { width: min(560px, 92vw); background: var(--surface-overlay); border: var(--bw-hairline) solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-overlay); padding: 0; } .dialog::backdrop { background: var(--surface-scrim); } .dialog__body { padding: var(--space-4); font: var(--fw-regular) var(--fs-base) / var(--lh-prose) var(--font-ui); color: var(--text-secondary); } .dialog__footer { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-3) var(--space-4); border-top: var(--bw-hairline) solid var(--border-subtle); } /* Drawer: zusaetzlicher Kontext bei begrenzter Breite */ .drawer { position: fixed; inset: var(--topbar-h) 0 var(--statusbar-h) auto; width: min(var(--inspector-w), 92vw); background: var(--surface-overlay); border-left: var(--bw-hairline) solid var(--border-strong); box-shadow: var(--shadow-overlay); } /* Popover: kurze lokale Auswahl */ .popover { background: var(--surface-overlay); border: var(--bw-hairline) solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--shadow-popover); padding: var(--space-1); min-width: 180px; } /* ========================================================================== 11. EMPTY STATE Kompakt, linksbuendig, mit genau einer Aktion. Keine Illustration, keine zentrierte Hero-Flaeche. ========================================================================== */ .empty { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); max-width: 480px; padding: var(--space-4); border: var(--bw-hairline) dashed var(--border-default); border-radius: var(--radius-sm); } .empty__title { font: var(--fw-semibold) var(--fs-md) / var(--lh-ui) var(--font-ui); color: var(--text-primary); } .empty__text { font: var(--fw-regular) var(--fs-sm) / var(--lh-prose) var(--font-ui); color: var(--text-secondary); } }