950 lines
19 KiB
CSS
950 lines
19 KiB
CSS
/* Buero-Visualisierung (Phase 2, statische Szene). Bewusst ohne UI-Framework, siehe
|
|
Visualization.md Abschnitt 5. Farbschema hell/freundlich (F9: "Zeichentrick"-Anmutung). */
|
|
|
|
:root {
|
|
--color-floor: #eef2f7;
|
|
--color-wall: #cfe0f0;
|
|
--color-wall-side: #bcd3ea;
|
|
--color-door: #8fb8dd;
|
|
--color-board-frame: #94622f;
|
|
--color-note: #fde68a;
|
|
--color-note-border: #d9b34f;
|
|
--color-note-stack-badge: #d97706;
|
|
--color-recording-badge: #dc2626;
|
|
--color-monitor-frame: #2b2f38;
|
|
--color-monitor-screen: #10131a;
|
|
--color-monitor-placeholder: #1a2436;
|
|
--color-desk-table: #b98a54;
|
|
--color-desk-chair: #6b7280;
|
|
--color-desk-screen-idle: #3a3f4b;
|
|
--color-text: #1f2937;
|
|
--color-text-inverse: #f8fafc;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Die Szene soll immer vollstaendig sichtbar sein - auch im normalen Fenstermodus,
|
|
ohne Scrollen. Dazu spannt der body eine Flex-Spalte ueber die Viewport-Hoehe auf:
|
|
Header nimmt seine natuerliche Hoehe, #office-scene bekommt den Rest, und das SVG
|
|
skaliert sich per aspect-ratio in diesen Rest hinein (siehe unten). */
|
|
html {
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: "Segoe UI", Verdana, Arial, sans-serif;
|
|
background: #dbe7f3;
|
|
color: var(--color-text);
|
|
/* height (nicht min-height): Nur eine definite Hoehe laesst die prozentualen
|
|
max-height-Angaben weiter unten aufloesen. dvh rechnet mobile Browserleisten
|
|
mit, vh ist der Fallback fuer aeltere Engines. */
|
|
height: 100vh;
|
|
height: 100dvh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
header.office-header {
|
|
flex: 0 0 auto;
|
|
padding: 12px 24px;
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
}
|
|
|
|
header.office-header h1 {
|
|
margin: 0;
|
|
font-size: 1.4rem;
|
|
}
|
|
|
|
/* Rein kosmetischer Countdown bis zum naechsten Codeberg-Sync (Issue #12), rechtsbuendig
|
|
anstelle des frueheren erklaerenden Fliesstexts. Tabular-nums verhindert Wackeln der
|
|
Breite, wenn sich die Ziffernzahl aendert (z.B. 9s -> 10s). */
|
|
.reload-countdown {
|
|
color: #475569;
|
|
font-size: 0.9rem;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Warnbanner, wenn die API nicht erreichbar ist und die Szene auf Demo-Daten zurueckfaellt
|
|
(siehe setApiBanner() in js/office-render.js). */
|
|
.api-banner {
|
|
flex: 0 0 auto;
|
|
padding: 10px 24px;
|
|
background: #dc2626;
|
|
color: #ffffff;
|
|
font-weight: 700;
|
|
text-align: center;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
/* Muss nach der Regel oben stehen: ohne diese Zeile wuerde das hidden-Attribut vom
|
|
flex-Wert ueberstimmt und der Banner waere dauerhaft sichtbar. */
|
|
.api-banner[hidden] {
|
|
display: none;
|
|
}
|
|
|
|
/* Reine Vorwarnung (Anmeldung laeuft demnaechst ab, der Agent arbeitet noch): gelb statt rot,
|
|
damit das Rot dem tatsaechlichen Stillstand vorbehalten bleibt. Dunkle Schrift, weil Weiss
|
|
auf Gelb kaum zu lesen ist. */
|
|
.api-banner.api-banner-warning {
|
|
background: #facc15;
|
|
color: #422006;
|
|
}
|
|
|
|
#office-scene {
|
|
flex: 1 1 auto;
|
|
/* min-height: 0 hebt die Flex-Default-Mindesthoehe (min-content) auf - sonst kann
|
|
das Kind den Container nicht unterschreiten und die Szene laeuft aus dem Bild. */
|
|
min-height: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0 16px 16px;
|
|
}
|
|
|
|
/* Das SVG soll sich an der jeweils knapperen Achse ausrichten. Welche das ist, haengt
|
|
vom Seitenverhaeltnis des Fensters ab - daher die beiden Media-Queries unten. Die
|
|
max-*-Grenzen sind das Sicherheitsnetz fuer den Grenzbereich (die Header-Hoehe geht
|
|
in das Verhaeltnis der Szenenflaeche ein, in die Media-Query aber nicht): Dort wird
|
|
die Elementbox notfalls leicht gestaucht - der Szeneninhalt bleibt dank
|
|
preserveAspectRatio unverzerrt und vollstaendig sichtbar. */
|
|
.office-svg {
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
aspect-ratio: 1920 / 1080;
|
|
display: block;
|
|
border-radius: 12px;
|
|
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25);
|
|
}
|
|
|
|
/* Fenster breiter als 16:9 -> die Hoehe ist der Engpass. */
|
|
@media (min-aspect-ratio: 16 / 9) {
|
|
.office-svg {
|
|
height: 100%;
|
|
width: auto;
|
|
}
|
|
}
|
|
|
|
/* Fenster schmaler als 16:9 -> die Breite ist der Engpass. */
|
|
@media (max-aspect-ratio: 16 / 9) {
|
|
.office-svg {
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
}
|
|
|
|
@media (max-height: 640px) {
|
|
header.office-header {
|
|
padding: 8px 16px;
|
|
}
|
|
|
|
header.office-header h1 {
|
|
font-size: 1.1rem;
|
|
}
|
|
}
|
|
|
|
.floor {
|
|
fill: var(--color-floor);
|
|
}
|
|
|
|
.wall {
|
|
fill: var(--color-wall);
|
|
}
|
|
|
|
.wall-side {
|
|
fill: var(--color-wall-side);
|
|
}
|
|
|
|
.door {
|
|
fill: var(--color-door);
|
|
stroke: #5f86ab;
|
|
stroke-width: 3;
|
|
transition: fill 0.4s ease-in-out;
|
|
}
|
|
|
|
/* Phase 6 (F2): kurzes Aufleuchten, waehrend ein "user"-Tuerbesuch die Tuer passiert. */
|
|
.door-active {
|
|
fill: #d7ecff;
|
|
}
|
|
|
|
.wall-label {
|
|
fill: #f8fafc;
|
|
font-size: 22px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Kanban-Board */
|
|
|
|
.board-frame {
|
|
fill: #7a5230;
|
|
stroke: var(--color-board-frame);
|
|
stroke-width: 6;
|
|
}
|
|
|
|
.board-column-label {
|
|
fill: var(--color-text-inverse);
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.board-column-divider {
|
|
stroke: rgba(255, 255, 255, 0.25);
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.note {
|
|
fill: var(--color-note);
|
|
stroke: var(--color-note-border);
|
|
stroke-width: 2;
|
|
}
|
|
|
|
/* Zettel in der Farbe seines Projekts (Issue #27): die Fuellung kommt als Inline-Style aus
|
|
der Projektkonfiguration, die Kontur muss dann neutral sein - die gelbe Standardkontur
|
|
passt nur zum gelben Standardzettel. */
|
|
.note-colored {
|
|
stroke: rgba(15, 23, 42, 0.35);
|
|
}
|
|
|
|
/* Issue #91: Ticket-Nummer auf dem Zettel; heller Rand haelt sie auf dunklen Projektfarben lesbar. */
|
|
.note-number {
|
|
fill: #0f172a;
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
paint-order: stroke;
|
|
stroke: rgba(255, 255, 255, 0.8);
|
|
stroke-width: 3px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.note-pr-stripes {
|
|
fill: url(#pr-stripes);
|
|
stroke: none;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.note-stack-badge {
|
|
fill: var(--color-note-stack-badge);
|
|
stroke: #92400e;
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.note-stack-count {
|
|
fill: #ffffff;
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* Monitor-Wand */
|
|
|
|
.monitor-frame {
|
|
fill: var(--color-monitor-frame);
|
|
}
|
|
|
|
.monitor-screen {
|
|
fill: var(--color-monitor-screen);
|
|
}
|
|
|
|
.monitor-screen-placeholder {
|
|
fill: var(--color-monitor-placeholder);
|
|
}
|
|
|
|
.monitor-event-line {
|
|
font-family: "Consolas", "Courier New", monospace;
|
|
font-size: 13px;
|
|
/* Grundfarbe fuer Schweregrade ohne eigene Farbe (z.B. info) - ohne sie stuende der Text
|
|
schwarz auf dem dunklen Monitor. */
|
|
fill: #cbd5e1;
|
|
}
|
|
|
|
/* Kopfzeile eines Events (Zeit + System): tritt gegenueber der Meldung zurueck. */
|
|
.monitor-event-meta {
|
|
opacity: 0.75;
|
|
}
|
|
|
|
.severity-warning,
|
|
.severity-warning .monitor-event-line {
|
|
fill: #facc15;
|
|
}
|
|
|
|
.severity-error,
|
|
.severity-error .monitor-event-line {
|
|
fill: #f87171;
|
|
}
|
|
|
|
.system-tile-bg {
|
|
fill: #1e293b;
|
|
}
|
|
|
|
.system-tile-mark {
|
|
fill: none;
|
|
stroke: #64748b;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.status-ok .system-tile-mark {
|
|
stroke: #4ade80;
|
|
}
|
|
|
|
.status-error .system-tile-mark {
|
|
stroke: #f87171;
|
|
}
|
|
|
|
/* Servername rechts neben der Kachel. Monospace und klein genug, dass auch lange Namen in
|
|
einer Zeile neben die Kachel passen (gekuerzt wird in renderSystemMonitor). */
|
|
.system-tile-name {
|
|
font-family: "Consolas", "Courier New", monospace;
|
|
font-size: 11px;
|
|
fill: #cbd5e1;
|
|
dominant-baseline: central;
|
|
}
|
|
|
|
.status-error .system-tile-name {
|
|
fill: #f87171;
|
|
}
|
|
|
|
.monitor-placeholder-text {
|
|
fill: #64748b;
|
|
font-size: 15px;
|
|
}
|
|
|
|
/* Schreibtische */
|
|
|
|
.desk-table {
|
|
fill: var(--color-desk-table);
|
|
stroke: #8a6238;
|
|
stroke-width: 3;
|
|
}
|
|
|
|
.desk-screen {
|
|
fill: var(--color-desk-screen-idle);
|
|
stroke: #1f2430;
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.desk-screen.pose-working {
|
|
fill: #7dd3fc;
|
|
}
|
|
|
|
/* Blockierter Platz (Claude-Anmeldung abgelaufen): der Bildschirm traegt den Zustand mit,
|
|
damit er auch dann am Platz sichtbar bleibt, wenn der Avatar gerade nicht dort steht. */
|
|
.desk-screen.pose-auth_expired {
|
|
fill: #7f1d1d;
|
|
stroke: #f87171;
|
|
}
|
|
|
|
.desk-screen.pose-auth_expiring {
|
|
fill: #713f12;
|
|
stroke: #facc15;
|
|
}
|
|
|
|
.desk-chair {
|
|
fill: var(--color-desk-chair);
|
|
}
|
|
|
|
/* Zaehler offener Sprachaufnahmen (Issue #85), oben links am Schreibtisch. */
|
|
.recording-badge-circle {
|
|
fill: var(--color-recording-badge);
|
|
stroke: #7c2d12;
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.recording-badge-count {
|
|
fill: #ffffff;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.person-head {
|
|
fill: #f3d9b1;
|
|
stroke: #d8b98a;
|
|
stroke-width: 1.5;
|
|
}
|
|
|
|
.person-body {
|
|
fill: var(--role-color, #94a3b8);
|
|
}
|
|
|
|
.desk-name {
|
|
fill: #334155;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.desk-name-empty {
|
|
fill: #94a3b8;
|
|
font-style: italic;
|
|
font-weight: 400;
|
|
}
|
|
|
|
/* Der Name eines Agenten am Schreibtisch steht am Tisch, nicht am Avatar (updateAgentsLayer()
|
|
blendet .avatar-name am Platz aus) - der Problemzustand faerbt deshalb hier. */
|
|
.desk-name.desk-name-problem-error {
|
|
fill: #b91c1c;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.desk-name.desk-name-problem-warning {
|
|
fill: #a16207;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.desk-deco-star {
|
|
fill: #fbbf24;
|
|
}
|
|
|
|
.desk-deco-flower circle {
|
|
fill: #f9a8d4;
|
|
}
|
|
|
|
.desk-deco-flower-center {
|
|
fill: #fde047 !important;
|
|
}
|
|
|
|
.desk-deco-check {
|
|
fill: none;
|
|
stroke: #22c55e;
|
|
stroke-width: 4;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.desk-deco-gear circle,
|
|
.desk-deco-gear rect {
|
|
fill: #a78bfa;
|
|
}
|
|
|
|
/* Heller Kern, damit der gefuellte Kreis als Zahnrad-Ring lesbar wird (wie beim Bluetenkern). */
|
|
.desk-deco-gear-center {
|
|
fill: #ede9fe !important;
|
|
}
|
|
|
|
/* Mikrofon am Schreibtisch des Voice-Bots: gefuellte Kapsel, Buegel und Fuss nur als Strich -
|
|
sonst wuerde der Halbkreis als Flaeche zulaufen. */
|
|
.desk-deco-mic-capsule {
|
|
fill: #5eead4;
|
|
}
|
|
|
|
.desk-deco-mic-bracket {
|
|
fill: none;
|
|
stroke: #5eead4;
|
|
stroke-width: 2.5;
|
|
stroke-linecap: round;
|
|
}
|
|
|
|
.desk-empty .desk-chair {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* Klickbare Bereiche (Phase 3/4: Board-Spalten + Monitore oeffnen ein Modal) */
|
|
|
|
.clickable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.board-column-hit {
|
|
fill: transparent;
|
|
pointer-events: all;
|
|
}
|
|
|
|
/* Trefferflaeche des PO-Platzes (Issue #27): macht den ganzen Platz klickbar, nicht nur die
|
|
gefuellten Moebelstuecke - ein Klick daneben landete sonst auf dem Boden. */
|
|
.po-desk-hit {
|
|
fill: transparent;
|
|
pointer-events: all;
|
|
}
|
|
|
|
/* Konfig-Zahnrad (Issue #27 am PO-Platz, Issue #70 am Systeme-Monitor): zeigt ueberhaupt
|
|
erst, dass sich hier etwas einstellen laesst. Aussehen ist ueberall gleich, nur der
|
|
Ausloeser des Hovers unterscheidet sich - beim PO der ganze Schreibtisch, beim Monitor
|
|
das Symbol selbst (der Monitor traegt schon eine eigene Klick-Aktion). */
|
|
.config-hint-bg {
|
|
fill: #ffffff;
|
|
stroke: #94a3b8;
|
|
stroke-width: 1.5;
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.config-hint-tooth,
|
|
.config-hint-hub {
|
|
stroke: #475569;
|
|
stroke-width: 2;
|
|
stroke-linecap: round;
|
|
fill: none;
|
|
}
|
|
|
|
.po-desk:hover .config-hint-bg,
|
|
.system-config-hint:hover .config-hint-bg {
|
|
fill: #e0f2fe;
|
|
stroke: #0284c7;
|
|
opacity: 1;
|
|
}
|
|
|
|
.po-desk:hover .config-hint-tooth,
|
|
.po-desk:hover .config-hint-hub,
|
|
.system-config-hint:hover .config-hint-tooth,
|
|
.system-config-hint:hover .config-hint-hub {
|
|
stroke: #0284c7;
|
|
}
|
|
|
|
.system-config-hint-hit {
|
|
fill: transparent;
|
|
pointer-events: all;
|
|
}
|
|
|
|
/* Reload-Symbol neben der Board-Ueberschrift (Issue #51): stoesst ein komplettes
|
|
Neueinlesen des Kanban-Boards an, analog zum Zahnrad am PO-Platz. */
|
|
.board-reload-hint-bg {
|
|
fill: #ffffff;
|
|
stroke: #94a3b8;
|
|
stroke-width: 1.5;
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.board-reload-hint-arrow {
|
|
fill: none;
|
|
stroke: #475569;
|
|
stroke-width: 2;
|
|
stroke-linecap: round;
|
|
}
|
|
|
|
.board-reload-hint-arrowhead {
|
|
fill: #475569;
|
|
}
|
|
|
|
.board-reload-hint-hit {
|
|
fill: transparent;
|
|
pointer-events: all;
|
|
}
|
|
|
|
.board-reload-hint:hover .board-reload-hint-bg {
|
|
fill: #e0f2fe;
|
|
stroke: #0284c7;
|
|
opacity: 1;
|
|
}
|
|
|
|
.board-reload-hint:hover .board-reload-hint-arrow {
|
|
stroke: #0284c7;
|
|
}
|
|
|
|
.board-reload-hint:hover .board-reload-hint-arrowhead {
|
|
fill: #0284c7;
|
|
}
|
|
|
|
.just-updated .board-frame,
|
|
.just-updated .monitor-frame {
|
|
animation: office-flash 0.9s ease-out;
|
|
}
|
|
|
|
@keyframes office-flash {
|
|
0% {
|
|
filter: drop-shadow(0 0 0 rgba(250, 204, 21, 0));
|
|
}
|
|
25% {
|
|
filter: drop-shadow(0 0 12px rgba(250, 204, 21, 0.9));
|
|
}
|
|
100% {
|
|
filter: drop-shadow(0 0 0 rgba(250, 204, 21, 0));
|
|
}
|
|
}
|
|
|
|
/* Kaffee-Ecke (Phase 5, Raum-Prop zwischen den Schreibtischreihen) */
|
|
|
|
.coffee-table {
|
|
fill: #8a6238;
|
|
stroke: #6b4a28;
|
|
stroke-width: 2;
|
|
}
|
|
|
|
.coffee-icon {
|
|
font-size: 20px;
|
|
}
|
|
|
|
/* Agenten-Avatare (Phase 5: bewegliche Schicht, siehe office-render.js) */
|
|
|
|
.agent-avatar {
|
|
transition: transform 1.1s ease-in-out;
|
|
}
|
|
|
|
.agent-avatar .person-head {
|
|
fill: #f3d9b1;
|
|
stroke: #d8b98a;
|
|
stroke-width: 1.5;
|
|
}
|
|
|
|
.agent-avatar .person-body {
|
|
fill: var(--role-color, #94a3b8);
|
|
}
|
|
|
|
.agent-avatar.pose-walking .person-leg {
|
|
fill: #475569;
|
|
transform-box: fill-box;
|
|
transform-origin: top center;
|
|
animation: office-leg-swing 0.6s ease-in-out infinite alternate;
|
|
}
|
|
|
|
.agent-avatar.pose-walking .person-leg-right {
|
|
animation-delay: 0.3s;
|
|
}
|
|
|
|
@keyframes office-leg-swing {
|
|
from {
|
|
transform: rotate(-18deg);
|
|
}
|
|
to {
|
|
transform: rotate(18deg);
|
|
}
|
|
}
|
|
|
|
/* Blockierter Agent (AGENT_PROBLEM_STATES): der Koerper verliert seine Rollenfarbe, damit die
|
|
Figur als "steht still" lesbar wird, ohne aus der Szene zu verschwinden. */
|
|
.agent-avatar.pose-auth_expired .person-body,
|
|
.agent-avatar.pose-auth_expiring .person-body {
|
|
fill: #94a3b8;
|
|
}
|
|
|
|
.person-prop-lock-body {
|
|
fill: #f87171;
|
|
stroke: #7f1d1d;
|
|
stroke-width: 1.5;
|
|
}
|
|
|
|
.person-prop-lock-shackle {
|
|
fill: none;
|
|
stroke: #f87171;
|
|
stroke-width: 3;
|
|
stroke-linecap: round;
|
|
}
|
|
|
|
.pose-auth_expiring .person-prop-lock-body {
|
|
fill: #facc15;
|
|
stroke: #713f12;
|
|
}
|
|
|
|
.pose-auth_expiring .person-prop-lock-shackle {
|
|
stroke: #facc15;
|
|
}
|
|
|
|
/* Nur der harte Ausfall pulsiert - eine pulsierende Vorwarnung waere auf einem Dauermonitor
|
|
Rauschen, das man nach einer Stunde nicht mehr sieht. */
|
|
.agent-avatar.pose-auth_expired .person-prop-lock {
|
|
animation: office-lock-pulse 1.4s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes office-lock-pulse {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.35;
|
|
}
|
|
}
|
|
|
|
.person-prop-cup {
|
|
fill: #f8fafc;
|
|
stroke: #94a3b8;
|
|
}
|
|
|
|
.person-prop-newspaper {
|
|
fill: #f8fafc;
|
|
stroke: #94a3b8;
|
|
stroke-width: 1;
|
|
}
|
|
|
|
.person-prop-speech {
|
|
fill: #f8fafc;
|
|
stroke: #94a3b8;
|
|
stroke-width: 1;
|
|
}
|
|
|
|
.avatar-name {
|
|
fill: #334155;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
text-anchor: middle;
|
|
}
|
|
|
|
/* KPI-Kacheln */
|
|
|
|
.kpi-tile-label {
|
|
fill: var(--color-text-inverse);
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Kombiniert notiert, weil .kpi-tile-label weiter unten steht als .severity-* und die Farbe
|
|
sonst bei gleicher Spezifitaet ueber die Reihenfolge zurueckgewinnt. */
|
|
.kpi-tile-label.severity-error {
|
|
fill: #f87171;
|
|
}
|
|
|
|
.kpi-tile-label.severity-warning {
|
|
fill: #facc15;
|
|
}
|
|
|
|
/* Modal (Phase 3/4: Board-/Monitor-Detailansicht, Visualization.md 4.5) */
|
|
|
|
.office-modal {
|
|
border: none;
|
|
border-radius: 12px;
|
|
padding: 0;
|
|
width: min(640px, 92vw);
|
|
max-height: 80vh;
|
|
box-shadow: 0 20px 50px rgba(15, 23, 42, 0.4);
|
|
}
|
|
|
|
.office-modal::backdrop {
|
|
background: rgba(15, 23, 42, 0.55);
|
|
}
|
|
|
|
.office-modal-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: 80vh;
|
|
}
|
|
|
|
.office-modal-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16px 20px;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.office-modal-title {
|
|
margin: 0;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.office-modal-close {
|
|
border: none;
|
|
background: transparent;
|
|
font-size: 1.4rem;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
color: #64748b;
|
|
}
|
|
|
|
.office-modal-body {
|
|
padding: 16px 20px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.office-modal-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.office-modal-item {
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
padding: 10px 12px;
|
|
}
|
|
|
|
.office-modal-item p {
|
|
margin: 6px 0 0;
|
|
color: #475569;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.office-modal-item .office-modal-description {
|
|
white-space: pre-line;
|
|
}
|
|
|
|
.office-modal-repo {
|
|
color: #64748b;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.office-modal-item-heading {
|
|
flex-wrap: wrap;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.office-modal-badge {
|
|
font-size: 0.75rem;
|
|
padding: 2px 8px;
|
|
border-radius: 999px;
|
|
background: #e2e8f0;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.office-modal-item.severity-error {
|
|
border-color: #fca5a5;
|
|
background: #fef2f2;
|
|
}
|
|
|
|
.office-modal-item.severity-warning {
|
|
border-color: #fde68a;
|
|
background: #fffbeb;
|
|
}
|
|
|
|
.office-modal-item.status-error {
|
|
border-color: #fca5a5;
|
|
background: #fef2f2;
|
|
}
|
|
|
|
.office-modal-empty {
|
|
color: #64748b;
|
|
font-style: italic;
|
|
}
|
|
|
|
/* Projekte-Modal (Issue #27: Klick auf den PO -> Projekte des Codeberg-Sync verwalten) */
|
|
|
|
.office-modal-error {
|
|
margin: 0 0 10px;
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
background: #fef2f2;
|
|
border: 1px solid #fca5a5;
|
|
color: #991b1b;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.repo-config-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.repo-config-swatch {
|
|
flex: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
border-radius: 4px;
|
|
border: 1px solid rgba(15, 23, 42, 0.15);
|
|
}
|
|
|
|
.repo-config-slug {
|
|
flex: 1;
|
|
font-weight: 600;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.repo-config-actions {
|
|
display: flex;
|
|
gap: 4px;
|
|
flex: none;
|
|
}
|
|
|
|
.repo-config-form {
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.repo-config-form-fields {
|
|
display: flex;
|
|
flex: 1;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.repo-config-form-fields input[type="text"] {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 6px 8px;
|
|
border: 1px solid #cbd5e1;
|
|
border-radius: 6px;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.repo-config-form-fields input[type="color"] {
|
|
flex: none;
|
|
width: 36px;
|
|
height: 32px;
|
|
padding: 2px;
|
|
border: 1px solid #cbd5e1;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.icon-button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 32px;
|
|
height: 32px;
|
|
border: 1px solid transparent;
|
|
border-radius: 6px;
|
|
background: transparent;
|
|
color: #475569;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.icon-button:hover {
|
|
background: #f1f5f9;
|
|
border-color: #e2e8f0;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.icon-button-svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
}
|
|
|
|
.repo-config-add-button {
|
|
margin-top: 8px;
|
|
color: #16a34a;
|
|
}
|
|
|
|
.repo-config-add-button:hover {
|
|
background: #f0fdf4;
|
|
border-color: #bbf7d0;
|
|
color: #15803d;
|
|
}
|
|
|
|
/* Issue #53: Ampel-Symbole (Schreibrechte/Webhook) rechts neben den Bearbeiten-/
|
|
Loeschen-Symbolen einer Projektzeile - Tooltip (title) traegt den Pruefgrund. */
|
|
.repo-config-status {
|
|
display: flex;
|
|
gap: 2px;
|
|
flex: none;
|
|
}
|
|
|
|
.repo-config-status-icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 24px;
|
|
height: 24px;
|
|
cursor: help;
|
|
}
|
|
|
|
.repo-config-status-icon.is-ok {
|
|
color: #16a34a;
|
|
}
|
|
|
|
.repo-config-status-icon.is-fail {
|
|
color: #dc2626;
|
|
}
|
|
|
|
/* Hosts-Modal (Issue #70) - teilt sich Zeilen-, Formular- und Symbolstile mit dem
|
|
Projekte-Modal; eigene Regeln braucht nur, was es dort nicht gibt. */
|
|
|
|
.host-config-subheading {
|
|
margin: 18px 0 4px;
|
|
font-size: 0.95rem;
|
|
color: #1f2937;
|
|
}
|
|
|
|
.host-config-agent {
|
|
flex: none;
|
|
padding: 2px 8px;
|
|
border-radius: 999px;
|
|
background: #f1f5f9;
|
|
color: #475569;
|
|
font-size: 0.8rem;
|
|
}
|