/* 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-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; gap: 16px; } header.office-header h1 { margin: 0; font-size: 1.4rem; } header.office-header p { margin: 0; color: #475569; font-size: 0.9rem; } #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; } } /* Bei knappem Platz weicht zuerst der erklaerende Fliesstext - er kostet in flachen oder schmalen Fenstern mehrere Zeilen Hoehe, die der Szene fehlen. */ @media (max-height: 640px), (max-width: 760px) { header.office-header p { display: none; } } @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; } .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; } .severity-warning { fill: #facc15; } .severity-error { fill: #f87171; } .system-tile-bg { fill: #1e293b; } .system-tile-bar { fill: #334155; } .system-tile-led { fill: #64748b; } .status-ok .system-tile-led { fill: #4ade80; } .status-error .system-tile-led { fill: #f87171; } .system-tile-label { fill: var(--color-text-inverse); font-size: 12px; } .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; } .desk-chair { fill: var(--color-desk-chair); } .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; } .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-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; } .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-cup { fill: #f8fafc; stroke: #94a3b8; stroke-width: 1.5; } .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); } } .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-Sparklines (Phase 4, F10: kein Chart-Lib, eigenes SVG-Zeichnen) */ .kpi-tile-label { fill: var(--color-text-inverse); font-size: 13px; font-weight: 600; } .kpi-sparkline-bg { fill: rgba(255, 255, 255, 0.04); } .kpi-sparkline-line { fill: none; stroke: #7dd3fc; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; } /* 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-heading { 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; } .kpi-modal-sparkline { width: 100%; height: 80px; margin-top: 8px; background: #10131a; border-radius: 6px; }