@rslsp1/fa-app-tools 10.3.2 → 10.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/StageEngine-O5I654LD.js +1243 -0
- package/dist/StageEngine-PYWITIIY.mjs +1243 -0
- package/dist/{chunk-ACB2543O.js → chunk-DDH2SGZM.js} +113 -20
- package/dist/{chunk-TFWIMFNF.mjs → chunk-GKLCL2VQ.mjs} +111 -18
- package/dist/{chunk-HFX6D53W.js → chunk-VSHSZEGV.js} +1810 -606
- package/dist/{chunk-JP7LIWDR.mjs → chunk-XLNA2BD6.mjs} +1448 -244
- package/dist/index.d.mts +107 -2
- package/dist/index.d.ts +107 -2
- package/dist/index.js +437 -108
- package/dist/index.mjs +703 -374
- package/dist/szenen.d.mts +610 -279
- package/dist/szenen.d.ts +610 -279
- package/dist/szenen.js +75 -29
- package/dist/szenen.mjs +48 -2
- package/package.json +1 -1
- package/dist/StageEngine-3MOBM2WX.mjs +0 -590
- package/dist/StageEngine-5VR3KEZB.js +0 -590
package/dist/index.js
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var _chunkVSHSZEGVjs = require('./chunk-VSHSZEGV.js');
|
|
21
21
|
require('./chunk-FTLEDU6C.js');
|
|
22
|
-
require('./chunk-
|
|
22
|
+
require('./chunk-DDH2SGZM.js');
|
|
23
23
|
|
|
24
24
|
// package.json
|
|
25
|
-
var version = "10.3.
|
|
25
|
+
var version = "10.3.4";
|
|
26
26
|
|
|
27
27
|
// src/hooks/useOnClickOutside.ts
|
|
28
28
|
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
@@ -61,7 +61,7 @@ function useKeyboardNavigation(history, currentResult, setCurrentResult) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// src/features/szenen/szenenViewStyles.generated.ts
|
|
64
|
-
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n/* Kette `szenen-design`, P1 \u2014 Bild zuerst, Text auf Abruf. Der Kopf ist nur\n * noch Titel und \u24D8; die Erklaerung klappt darunter auf. */\n.szenen-view__intro {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-view__titel {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n font-size: clamp(1.5rem, 3vw, 1.9rem);\n font-weight: 700;\n letter-spacing: -0.01em;\n line-height: 1.15;\n}\n\n.szenen-view__eyebrow {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-view__info {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-view__info[aria-expanded="true"] {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-view__intro-text {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n font-size: 0.85rem;\n line-height: 1.4;\n}\n\n.szenen-icon {\n flex: none;\n}\n\n/* Fuer Screenreader sichtbar, fuer das Auge nicht \u2014 Status-Punkte und\n * Node-Symbole tragen ihre Bedeutung als Text. */\n.szenen-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n/* Die Bereiche als Pill-Leiste. Sie scrollt in sich, nie die Seite: `min-width:\n * 0` haelt sie in der Spalte, `overflow-x: auto` macht jeden Bereich\n * erreichbar, auch wenn nicht alle nebeneinander passen. */\n.szenen-view__nav {\n display: flex;\n flex-wrap: nowrap;\n gap: var(--space-xs);\n min-width: 0;\n padding: 0 0 var(--space-xs);\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view .szenen-view__nav button {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.9rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.875rem;\n}\n\n.szenen-view .szenen-view__nav button.is-active,\n.szenen-view .szenen-view__nav button[aria-selected="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n/* `box-sizing` steht hier und nicht beim Host: Die React-App bringt in\n * `master.css` einen globalen `* { box-sizing: border-box }` mit, Flow **nicht**\n * \u2014 dort ragte `width: 100%` plus Innenabstand um die Randbreite aus dem\n * Elternelement heraus und erzeugte auf ~390 px einen horizontalen Scroll. Die\n * gemeinsame Ansicht darf sich auf keinen Host-Reset verlassen. */\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-erweitert,\n.szenen-prompts,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Arbeitsoberflaeche: Liste links, Bearbeitung rechts.\n *\n * Breit stehen beide Spalten nebeneinander \u2014 die Auswahl bleibt sichtbar,\n * waehrend bearbeitet wird. Schmal rendert die Komponente nur eine der beiden;\n * hier steht deshalb keine Regel, die die andere versteckt. */\n@media (min-width: 761px) {\n .szenen-elements {\n grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);\n align-items: start;\n }\n\n .szenen-elements__master,\n .szenen-elements__detail {\n min-width: 0;\n }\n}\n\n.szenen-elements__master,\n.szenen-elements__detail {\n display: grid;\n gap: var(--space-sm);\n align-content: start;\n min-width: 0;\n}\n\n.szenen-elements__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-elements__heading {\n margin: 0;\n font-size: 1.05rem;\n}\n\n.szenen-elements__scope {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-elements__scope > select {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.szenen-elements__new {\n flex: none;\n font-weight: 700;\n}\n\n.szenen-elements__create {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-elements__create label {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-elements__create-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n}\n\n.szenen-elements__options > summary {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n cursor: pointer;\n}\n\n.szenen-elements__back {\n justify-self: start;\n font-weight: 700;\n}\n\n.szenen-elements__empty-detail {\n margin: 0;\n color: var(--color-text-tertiary);\n}\n\n.szenen-elements__filter,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button > .szenen-elements__title {\n flex: 1 1 100%;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n/* B1 \u2014 die geschlossene Runde. Vorher stand die `run_id` als erstes und war\n die einzige Information, die niemand liest; jetzt beantwortet die Kopfzeile\n welche Runde, ob sie durchging, mit welchem Modell und was ungef\xE4hr\n herauskam. */\n.szenen-runs__hinweis {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n}\n\n.szenen-runs__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n width: 100%;\n padding: var(--space-xs) 0;\n text-align: left;\n color: var(--color-text-secondary);\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.szenen-runs__marke {\n font-weight: 700;\n color: var(--color-text-primary);\n}\n\n.szenen-runs__status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n}\n\n.szenen-runs__status[data-status="succeeded"] {\n border-color: var(--color-success);\n}\n\n.szenen-runs__status[data-status="failed"] {\n border-color: var(--color-danger);\n}\n\n.szenen-runs__modell {\n font-size: 0.75rem;\n}\n\n/* Der Auszug ist die Inhaltsvorschau der Runde. Er bekommt eine eigene Zeile,\n damit er nicht mit Marke und Modell um dieselbe Zeile ringt. */\n.szenen-runs__auszug {\n flex: 1 1 100%;\n min-width: 0;\n color: var(--color-text-tertiary);\n font-size: 0.8125rem;\n}\n\n/* B2 \u2014 ein Fehler steht ausserhalb der aufklappbaren Fl\xE4che: Wer eine rote\n Runde sieht, soll nicht erst klicken m\xFCssen, um zu erfahren, woran sie\n gescheitert ist. */\n.szenen-runs__fehler {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n}\n\n.szenen-runs__fehler p {\n margin: 0;\n}\n\n.szenen-runs__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-runs__prompt > h5,\n.szenen-runs__sekundaer > h5 {\n margin: 0 0 var(--space-xs);\n}\n\n/* Im Kopf traegt die Zeile selbst den Abstand \u2014 sonst kaeme er doppelt. */\n.szenen-runs__promptkopf > h5 {\n margin: 0;\n}\n\n/* Ueberschrift und Kopierknopf in einer Zeile. Der Knopf gehoert an den Text,\n den er kopiert \u2014 nicht an den Rand der Runde, wo er neben dem falschen\n Abschnitt stuende. */\n.szenen-runs__promptkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n margin: 0 0 var(--space-xs);\n}\n\n/* Ein kompakter Knopf, kein zweiter Titel: Der Prompt ist die Hauptsache des\n Abschnitts, die Aktion daneben darf ihn nicht ueberstimmen. Rahmen und\n Hintergrund kommen aus `.szenen-view button` und bleiben \u2014 dieselbe Optik wie\n jeder andere Knopf der Ansicht; hier wird nur die Groesse zurueckgenommen.\n Zwei Klassen im Selektor, weil `.szenen-view button` sonst spezifischer ist. */\n.szenen-runs__promptkopf .szenen-runs__kopieren {\n min-height: 0;\n padding: 0.1rem 0.45rem;\n font-size: 0.72rem;\n}\n\n/* Regel 11: die Bestaetigung nennt die Zahl, nicht nur \u201EErfolgreich". */\n.szenen-runs__kopiert {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-runs__prompt > p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.szenen-runs__prompt--negativ > p,\n.szenen-runs__sekundaer > p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n}\n\n.szenen-runs__mehr {\n justify-self: start;\n margin-top: var(--space-xs);\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-secondary));\n background: transparent;\n border: none;\n font-size: 0.75rem;\n text-decoration: underline;\n cursor: pointer;\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n /* C1 \u2014 auf 390 px bleiben drei Kacheln je Reihe gross genug zum Erkennen\n und klein genug, dass vier Bilder eine Reihe sind und keine Seite. */\n .szenen-bildgalerie {\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n }\n\n /* Der Viewer bekommt den ganzen Bildschirm; die Bl\xE4tterkn\xF6pfe bleiben am\n Rand, wo der Daumen sie erreicht. */\n .szenen-bildviewer {\n padding: var(--space-xs);\n }\n\n .szenen-bildviewer__blaettern {\n width: 2.25rem;\n height: 4rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n grid-column: 1 / -1;\n }\n\n /* Schmal ist die Liste eine Spalte, und die Auswahl fuehrt weiter \u2014 der\n * Eintrag ist deshalb ein Ziel fuer den Finger, keine Kachel. */\n .szenen-elements__list {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .szenen-elements__list > li > button {\n min-height: 2.75rem;\n }\n\n .szenen-elements__back {\n justify-self: stretch;\n min-height: 2.5rem;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P2: Szenen-\xDCbersicht als Bildgalerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kacheln wie in der Library: quadratisch, Deckbild, Titel ueber einem\n * Verlauf, Bildzahl als Plakette. Eine Szene ohne Bild zeigt ihre\n * Node-Symbole; ein nicht ladbares Deckbild nennt den Grund. Die Schrift auf\n * dem Bild ist hell auf dunklem Verlauf \u2014 unabhaengig vom Hostthema, weil das\n * Bild es auch ist. */\n.szenen-galerie {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-galerie__kopf > .szenen-elements__heading {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-galerie__anzahl,\n.szenen-galerie__sortierung {\n color: var(--color-text-secondary);\n font-weight: 400;\n}\n\n.szenen-galerie__sortierung {\n font-size: 0.8rem;\n}\n\n.szenen-galerie__raster {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));\n gap: 0.625rem;\n min-width: 0;\n}\n\n/* Die Kacheln sind Zellen desselben Rasters wie die Neu-Kachel. */\n.szenen-view .szenen-galerie__liste {\n display: contents;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-galerie__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-galerie__kachel > button,\n.szenen-view .szenen-galerie__neu,\n.szenen-view .szenen-galerie__zuletzt {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-galerie__kachel > button {\n aspect-ratio: 1 / 1;\n}\n\n.szenen-view .szenen-galerie__kachel > button[aria-current="true"],\n.szenen-view .szenen-galerie__zuletzt[aria-current="true"] {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-galerie__bild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-galerie__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.88) 0%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0) 65%);\n}\n\n.szenen-galerie__ohnebild {\n position: absolute;\n inset: 0;\n padding: 0.75rem;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 14px 14px,\n var(--color-bg-surface);\n}\n\n.szenen-galerie__bildfehler {\n position: absolute;\n inset: 0;\n /* Oben Platz fuer Status-Punkte und Bildzahl, die darueber liegen. */\n padding: 2.25rem 0.75rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-galerie__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.25rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__text,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__zuletzt-text {\n color: #fff;\n}\n\n.szenen-galerie__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 0.875rem;\n font-weight: 650;\n line-height: 1.25;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n overflow-wrap: anywhere;\n}\n\n.szenen-galerie__meta {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__meta,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-galerie__tags {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.szenen-galerie__tag {\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n overflow: hidden;\n color: inherit;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-full);\n font-size: 0.68rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__tag {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.szenen-galerie__status {\n position: absolute;\n top: 0.7rem;\n left: 0.7rem;\n display: flex;\n gap: 0.3rem;\n}\n\n.szenen-galerie__punkt {\n width: 0.625rem;\n height: 0.625rem;\n background: var(--color-text-secondary);\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n.szenen-galerie__punkt[data-ton="info"] { background: var(--color-accent-blue); }\n.szenen-galerie__punkt[data-ton="ok"] { background: var(--color-success); }\n.szenen-galerie__punkt[data-ton="fertig"] { background: var(--color-warning); }\n/* Unvollstaendig ist ein Ring: Die Form unterscheidet es von \u201Evollstaendig",\n * nicht nur der Farbton (P8). */\n.szenen-galerie__punkt[data-ton="warn"] {\n background: transparent;\n box-shadow: inset 0 0 0 2px var(--color-accent-orange), 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n/* Die Legende der Punkte \u2014 einmal je Ansicht. */\n.szenen-statuslegende {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem 0.85rem;\n margin: 0;\n padding: 0;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n list-style: none;\n}\n\n.szenen-statuslegende__eintrag {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-statuslegende .szenen-galerie__punkt {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.szenen-galerie__bildzahl {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.15rem 0.5rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-galerie__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: 0.3rem;\n}\n\n.szenen-galerie__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 1.875rem;\n height: 1.875rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-galerie__symbol[data-node-type="light"] {\n color: var(--color-warning);\n}\n\n.szenen-galerie__symbol--rest {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n}\n\n.szenen-view .szenen-galerie__neu {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.6rem;\n aspect-ratio: 1 / 1;\n text-align: center;\n background: var(--color-bg-app);\n border: 1.5px dashed var(--color-border-hover, var(--color-border));\n}\n\n.szenen-galerie__neu-plus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border-radius: 50%;\n}\n\n.szenen-galerie__neu-titel {\n font-size: 0.95rem;\n font-weight: 600;\n}\n\n.szenen-galerie__neu-text {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt-bild {\n position: relative;\n display: block;\n aspect-ratio: 4 / 3;\n max-height: 17rem;\n width: 100%;\n}\n\n.szenen-galerie__chip {\n position: absolute;\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.3rem 0.6rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt .szenen-galerie__status {\n right: 0.75rem;\n left: auto;\n top: 1rem;\n}\n\n/* Die Symbole einer Szene ohne Bild stehen unter dem Chip, nicht darauf. */\n.szenen-galerie__zuletzt .szenen-galerie__ohnebild {\n padding-top: 3rem;\n}\n\n.szenen-galerie__zuletzt-text {\n position: absolute;\n right: 1rem;\n bottom: 0.9rem;\n left: 1rem;\n display: grid;\n gap: 0.35rem;\n}\n\n.szenen-galerie__zuletzt-text .szenen-galerie__titel {\n font-size: 1.3rem;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.szenen-galerie__zuletzt-fuss {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: 0.75rem 0.9rem;\n}\n\n.szenen-galerie__oeffnen {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.25rem;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 Browser und Inspector, dem Labs-Tab nachgebildet,\n aber mit dem CSS dieser Ansicht: eine gemeinsame Komponente \xFCber zwei\n Dom\xE4nengrenzen w\xE4re eine Kopplung, die keiner gewollt hat.\n\n Der Review vom 2026-08-22 (R12.1/R12.2) hat den Ma\xDFstab gesetzt: Der Bestand\n ist ein **Browser**, kein Seiteninhalt. Vierzig Werke d\xFCrfen die Szenenseite\n nicht meterlang machen, und zw\xF6lf Varianten eines Werkes keine zw\xF6lf\n Bildschirmseiten. Deshalb steht hier alles unter zwei Regeln \u2014 begrenzte\n Fl\xE4che mit eigenem Scroll, und Kacheln statt Karten. */\n\n/* \u2500\u2500 Ebene 1: der Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl {\n /* Dieselbe Begr\xFCndung wie beim Inspector: Als Grid-Element w\xFCrde der\n W\xE4hler sonst so breit wie sein breitester Inhalt. */\n min-width: 0;\n}\n\n.szenen-bildwahl__browser {\n /* Die eigene Scrollfl\xE4che ist der ganze Punkt: Der Bestand w\xE4chst nach\n innen, nicht nach unten. Dieselbe Gr\xF6\xDFenordnung wie `max-h-[300px]` im\n Labs-Browser. */\n max-height: 19rem;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__raster {\n display: grid;\n /* Vier Spalten auf schmalen Displays \u2014 der gemeldete Screenshot zeigte eine\n einzige Spalte gro\xDFer Karten. Breiter wird automatisch dichter. */\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__karte {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-surface);\n text-align: left;\n cursor: pointer;\n}\n\n/* Das fokussierte Werk ist klar markiert \u2014 sonst wei\xDF niemand, wessen Galerie\n der Inspector unten zeigt. */\n.szenen-bildwahl__karte.is-fokus {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n/* \u2500\u2500 Die Kachel selbst \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Der Platz steht, bevor das Bild da ist \u2014 sonst springt das Raster, sobald\n die erste Vorschau eintrifft. */\n.szenen-bildkachel {\n display: block;\n width: 100%;\n aspect-ratio: 1;\n overflow: hidden;\n background: var(--color-bg-app);\n}\n\n.szenen-bildkachel img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.szenen-bildkachel__leer {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, var(--color-bg-app), var(--color-bg-surface));\n}\n\n/* R12.3: Eine fehlende Vorschau bleibt kachelgro\xDF. Vorher fiel die Karte auf\n ihren Prompttext zur\xFCck \u2014 und ein Prompt hat im echten Bestand mehrere\n hundert Zeichen. */\n.szenen-bildkachel__zeichen {\n font-size: 0.875rem;\n font-weight: 700;\n color: var(--color-text-secondary);\n opacity: 0.6;\n}\n\n/* Wie viele Varianten das Werk hat \u2014 klein und \xFCberlagernd, nie als\n dominanter Text. */\n.szenen-bildwahl__anzahl {\n position: absolute;\n top: 0.15rem;\n right: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n font-weight: 700;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Eine Zeile, dann Schluss. Der Prompt eines Werkes ist oft mehrere hundert\n Zeichen lang und w\xE4re als Prim\xE4rdarstellung genau die Textw\xFCste, gegen die\n der Review antritt. */\n.szenen-bildwahl__kacheltitel {\n display: block;\n padding: 0.15rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.3;\n color: var(--color-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Ebene 2: der Inspector \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__inspector {\n /* Ohne `min-width: 0` gewinnt der Inhalt: Der W\xE4hler ist Element eines\n Grids (`.szenen-form`), und dort ist `min-width: auto` die Vorgabe. Der\n Streifen unten ist rund 1000 px breit \u2014 gemessen am 2026-08-22 im echten\n Browser zog er die Auswahl von 374 px auf 1088 px auf und schob die\n ganze Seite waagerecht heraus, statt selbst zu scrollen. */\n min-width: 0;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n /* Sichtbar abgesetzt vom Browser: zwei Ebenen, nicht eine lange Liste. */\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__inspektorkopf {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bildwahl__werktitel {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--color-text-primary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bildwahl__zurueck {\n flex: 0 0 auto;\n font-size: 0.6875rem;\n padding: 0.15rem 0.5rem;\n}\n\n/* Der Streifen: waagerecht scrollend, feste kleine Kacheln \u2014 zw\xF6lf Varianten\n bleiben ein \xDCberblick statt zw\xF6lf Bildschirmseiten. */\n.szenen-bildwahl__streifen {\n /* Die Breite kommt vom Elter, nie vom Inhalt \u2014 sonst scrollt hier nichts. */\n max-width: 100%;\n display: flex;\n gap: var(--space-sm);\n margin: 0;\n padding: 0 0 0.25rem;\n list-style: none;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.szenen-bildwahl__streifen > li {\n flex: 0 0 auto;\n width: 5rem;\n}\n\n.szenen-bildwahl__variante {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-app);\n cursor: pointer;\n}\n\n.szenen-bildwahl__variante.is-gewaehlt {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n.szenen-bildwahl__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Das Gew\xE4hlte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n max-width: 100%;\n}\n\n/* Das gew\xE4hlte Bild wird best\xE4tigt, nicht nur benannt: eine kleine Vorschau\n neben dem Titel. */\n.szenen-bildwahl__gewaehlt .szenen-bildkachel {\n width: 2.25rem;\n flex: 0 0 auto;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__gewaehlt .szenen-bildwahl__kacheltitel {\n min-width: 0;\n max-width: 12rem;\n font-size: 0.75rem;\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n/* Das Eingangsbild benutzt seit C3 dieselbe Kachel wie W\xE4hler und Galerie.\n Sie ist von Haus aus so breit wie ihr Platz \u2014 in dieser Zeile bekommt sie\n deshalb eine feste Gr\xF6sse, sonst sch\xF6be sie die Metadaten heraus. */\n.szenen-bilder__eingangsliste .szenen-bildkachel {\n flex: 0 0 auto;\n width: 4rem;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batchkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-bilder__herkunft {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n/* Review-Befund \u2014 ein transienter Bildfehler ist wiederholbar, kein\n endg\xFCltiges \u201Efehlt". Dezent wie ein Angebot, nicht wie ein Fehlerzustand. */\n.szenen-bilder__retry {\n justify-self: start;\n padding: 0.15rem 0.5rem;\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n/* C4 \u2014 die Provenienz vollst\xE4ndig, aber sekund\xE4r. */\n.szenen-bilder__technik > summary {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-bilder__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n}\n\n/* C5 \u2014 der Verlauf verdichtet, seine Ausreisser nicht. */\n.szenen-bilder__verlauf > summary {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n cursor: pointer;\n}\n\n.szenen-bilder__verlauf[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__auffaellig {\n margin: 0;\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n.szenen-bilder__auftragskennung {\n flex-basis: 100%;\n color: var(--color-text-tertiary);\n font-size: 0.6875rem;\n}\n\n/* \u2500\u2500 C1/C2 \u2014 Galerie und grosse Ansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Das Raster w\xE4chst mit dem Platz: auf 390 px drei bis vier Kacheln je Reihe,\n auf dem Desktop entsprechend mehr. Vorher war jedes Bild eine Zeile aus\n Daumennagel plus vier Metadatenfeldern \u2014 vier Bilder ergaben vier Textzeilen\n und das Protokoll war die Hauptsache. */\n.szenen-bildgalerie {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));\n gap: var(--space-sm);\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildgalerie__kachel {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildgalerie__kachel:hover,\n.szenen-bildgalerie__kachel:focus-visible {\n border-color: var(--color-accent-teal, var(--color-text-primary));\n}\n\n.szenen-bildgalerie__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* Die grosse Ansicht liegt \xFCber allem und bringt ihren eigenen Grund mit \u2014\n `position: fixed` bezieht sich im Flow-Canvas auf dessen Rahmen, in React auf\n das Fenster; in beiden F\xE4llen genau das Gew\xFCnschte. */\n.szenen-bildviewer {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: grid;\n grid-template-rows: auto 1fr auto;\n gap: var(--space-sm);\n padding: var(--space-sm);\n /* Deckend, nicht get\xF6nt: Bei 0.92 schimmerte der Laufbereich durch und man\n las Prompttext quer \xFCber dem Bild \u2014 im Browser gemessen. */\n background: #000;\n}\n\n/* Titel, Z\xE4hlung, Schliessen \u2014 drei Spalten, damit ein langer Werktitel die\n Z\xE4hlung nicht in die n\xE4chste Zeile und \xFCber das Bild schiebt. */\n.szenen-bildviewer__kopf {\n display: grid;\n /* Titel nimmt den Rest; Zaehler, eine optionale Bildaktion (P6) und\n Schliessen stehen rechts \u2014 mit und ohne Aktion in einer Zeile. */\n grid-template-columns: minmax(0, 1fr);\n grid-auto-columns: auto;\n grid-auto-flow: column;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-bildviewer__titel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n}\n\n.szenen-bildviewer__zaehler {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n}\n\n.szenen-bildviewer__buehne {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 0;\n min-width: 0;\n}\n\n/* Der Rahmen nimmt den Platz, der zwischen den Bl\xE4tterkn\xF6pfen \xFCbrig ist \u2014\n `min-width: 0`, damit er auch wirklich schrumpft statt sie hinauszuschieben. */\n.szenen-bildviewer__rahmen {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n min-height: 0;\n height: 100%;\n}\n\n.szenen-bildviewer__bild {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n\n.szenen-bildviewer__leer {\n color: var(--color-text-secondary);\n text-align: center;\n}\n\n/* Die Bl\xE4tterkn\xF6pfe sind daumengross und liegen an den R\xE4ndern \u2014 auf einem\n Telefon ist der Rand erreichbar, die Bildmitte nicht. */\n.szenen-bildviewer__blaettern {\n flex: 0 0 auto;\n width: 2.75rem;\n height: 3.5rem;\n font-size: 1.75rem;\n line-height: 1;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildviewer__details {\n max-height: 8rem;\n overflow-y: auto;\n color: var(--color-text-secondary);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n/* D \u2014 die Aktionen stehen abgesetzt und standardm\xE4ssig kompakt: Sie sind\n Angebote, keine Ausk\xFCnfte. Vorher hielten beide Formulare dauerhaft offen und\n machten aus jedem Lauf zwei zus\xE4tzliche Bildschirmseiten. */\n.szenen-bilder__aktion {\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > summary {\n color: var(--color-text-primary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-bilder__aktion[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* Regelwerk-UX Schritt 16 \u2014 der ZIP-Sammelimport.\n *\n * \xA78: Der gemeldete Einsatz ist mobil. Deshalb **ein** Seedfeld statt einer\n * gestapelten Eingabe je Bild, und die Zuordnung Bild -> Seed als umbrechende\n * Zeile statt als Tabelle: Eine Tabelle waere auf 390 px abgeschnitten, und\n * abgeschnitten heisst hier, dass der Nutzer die Zuordnung nicht mehr pruefen\n * kann \u2014 genau die Pruefung, wegen der die Vorschau existiert. */\n.szenen-bilder__zip {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bilder__zipkopf {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipvorlagen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n}\n\n/* Eine laengere Liste bleibt scrollbar, statt die Sektion und damit den\n * Import-Knopf aus dem Blick zu schieben (\xA78, letzter Punkt). */\n.szenen-bilder__zipliste {\n max-height: 16rem;\n overflow-y: auto;\n}\n\n.szenen-bilder__zipliste > li {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-bilder__zipliste > li > span:first-child {\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipliste > li > span:last-child {\n color: var(--color-text-secondary);\n white-space: nowrap;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen von Objektfeldern (`prompt_render_settings`, `overrides`,\n `blender_render_settings`) \u2014 seit A1/A2 auf- und zuklappbar. Eine optionale\n Gruppe startet zu: Blender und `overrides` f\xFCllten auf einem 390-px-Display\n sonst mehrere Bildschirmseiten, obwohl die meisten Shots sie nie anfassen. */\n.szenen-detail__group {\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > summary {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__group[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n/* A2 \u2014 dass eine zugeklappte Gruppe schon Werte tr\xE4gt, muss man sehen, ohne\n sie zu \xF6ffnen. Sonst \xFCbersieht man eine gesetzte Blender-Ausgabe genau so\n lange, bis sie im Ergebnis auftaucht. */\n.szenen-detail__group-status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--color-text-tertiary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group[data-konfiguriert="ja"] > summary .szenen-detail__group-status {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-detail__group-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n/* A3 \u2014 die Kernaussage steht am Feld, die Begr\xFCndung dahinter. Nicht als\n Tooltip: Auf einem Telefon gibt es kein Hover, und was dort unerreichbar ist,\n ist gestrichen \u2014 nur ohne dass es jemand entschieden h\xE4tte. */\n.szenen-detail__warum > summary {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-detail__warum > small {\n display: block;\n padding-top: var(--space-xs);\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__fieldrow {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n margin-bottom: var(--space-md);\n}\n\n/* A4 \u2014 der technische Feldname bleibt lesbar, tritt aber hinter das fachliche\n Label zur\xFCck. */\n.szenen-detail__field-label {\n color: var(--color-text-primary);\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-bilder__modellwahl,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n/* \u201ENeues Modell hinzufuegen" im Importdialog \u2014 dieselben Abstaende wie jedes\n andere Formular dieser Ansicht, damit es kein Fremdkoerper wird. */\n.szenen-feld__zielmodell-neu {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-feld__zielmodell-neu-aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n\n/* Bereich `Prompts` \u2014 die herkunftsuebergreifende Sicht (P1-A).\n *\n * Die Eintraege selbst rendert `RundenEintrag` und tragen damit die\n * `szenen-runs__*`-Regeln. Hier stehen nur Rahmen und Kennzeichen; eine zweite\n * Laufdarstellung gibt es nicht, also braucht sie auch kein zweites Aussehen. */\n.szenen-prompts__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-prompts__heading {\n margin: 0;\n font-size: 1.05rem;\n margin-right: auto;\n}\n\n.szenen-view__fokus {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-prompts__fokus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-accent, #0d9488);\n border-radius: var(--radius-sm, 4px);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-prompts__hinweis {\n font-style: italic;\n}\n\n.szenen-prompts__ausgeblendet {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P8 \u2014 der Bereich `Prompts` als Bildraster\n ========================================================================== */\n\n/* Herkunfts-Chips: eine Zeile, die in sich scrollt \u2014 nie die Seite. */\n.szenen-prompts__chips {\n display: flex;\n flex-wrap: nowrap;\n gap: 0.375rem;\n min-width: 0;\n padding-bottom: 0.15rem;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view .szenen-prompts__chip {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.8rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__chip[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-prompts__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.375rem;\n min-width: 0;\n}\n\n.szenen-prompts__anzahl {\n flex: 1 1 8rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__umschalter {\n min-height: 2rem;\n padding: 0 0.65rem;\n font-size: 0.75rem;\n}\n\n.szenen-prompts__raster-bereich {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Der neueste Lauf \u2014 gross, mit Promptzeile und Kopierknopf. */\n.szenen-prompts__neuester {\n min-width: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__oeffnen {\n display: block;\n width: 100%;\n padding: 0;\n color: var(--color-text-primary);\n text-align: left;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-prompts__bild {\n position: relative;\n display: block;\n height: 17.5rem;\n overflow: hidden;\n}\n\n.szenen-prompts__neuester .szenen-galerie__status {\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.35rem 0.5rem;\n background: rgba(0, 0, 0, 0.55);\n border-radius: var(--radius-full);\n}\n\n.szenen-prompts__neuester .szenen-galerie__bildzahl {\n top: 0.75rem;\n right: 0.75rem;\n}\n\n.szenen-prompts__promptzeile {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.6rem 0.5rem 0.6rem 0.9rem;\n}\n\n.szenen-prompts__prompt {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-kopieren--symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n color: var(--color-text-primary);\n border-radius: var(--radius-lg);\n}\n\n.szenen-prompts__promptzeile .szenen-lauf__kopieren {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n}\n\n/* Gruppe aufeinanderfolgender Laeufe derselben Szene. */\n.szenen-prompts__gruppe {\n display: grid;\n gap: 0.6rem;\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf h4 {\n min-width: 0;\n margin: 0;\n font-size: 1rem;\n font-weight: 650;\n line-height: 1.3;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__gruppenkopf span {\n flex: none;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Zwei Spalten, Kacheln im Format 3:4. */\n.szenen-view .szenen-prompts__raster {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 0.625rem;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n@media (min-width: 761px) {\n .szenen-view .szenen-prompts__raster {\n grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));\n }\n}\n\n.szenen-prompts__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-prompts__kachel > button {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n aspect-ratio: 3 / 4;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__kachel.is-fokus > button,\n.szenen-view .szenen-prompts__neuester.is-fokus {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-prompts__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__text {\n color: #fff;\n}\n\n.szenen-prompts__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 1.25rem;\n font-weight: 700;\n line-height: 1.2;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__kachelrunde {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-prompts__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.3rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-prompts__statuspunkt {\n display: inline-block;\n flex: none;\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: 50%;\n}\n\n.szenen-prompts__statuspunkt[data-status="failed"] {\n background: var(--color-danger);\n}\n\n/* Eine Kachel ohne Bild nennt ihren Grund \u2014 oben, damit der Text unten frei bleibt. */\n.szenen-prompts__grund {\n display: grid;\n align-content: start;\n gap: 0.3rem;\n padding-top: 2.25rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-prompts__fehlertext {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 4;\n overflow-wrap: anywhere;\n}\n\n/* ==========================================================================\n ZIP-MODELLVORSCHLAG (modaler Best\xE4tigungsdialog)\n ========================================================================== */\n\n/* Wie die grosse Bildansicht: eigener Grund, `position: fixed`, damit der\n Dialog im Flow-Canvas und in React gleichermassen \xFCber allem liegt. */\n.szenen-zipmodell {\n position: fixed;\n inset: 0;\n z-index: 1100;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-md);\n background: rgba(0, 0, 0, 0.72);\n}\n\n.szenen-zipmodell__karte {\n display: grid;\n gap: var(--space-sm);\n width: min(34rem, 100%);\n max-height: 100%;\n overflow-y: auto;\n padding: var(--space-md);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-zipmodell__titel {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__treffer,\n.szenen-zipmodell__vertrauen,\n.szenen-zipmodell__fallback {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__vertrauen {\n color: var(--color-text-secondary);\n}\n\n/* Ein schwacher oder mehrdeutiger Treffer muss sich vom sicheren unterscheiden,\n sonst ist die Warnung nur ein weiterer Satz. */\n.szenen-zipmodell__warnung {\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n color: var(--color-text-primary);\n background: rgba(234, 179, 8, 0.14);\n border-left: 3px solid #eab308;\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen {\n display: grid;\n gap: 0.2rem;\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen > label {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-zipmodell__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n/* ==========================================================================\n MEHR LADEN \u2014 der gemeinsame Fuss jeder seitenweise geladenen Liste\n ========================================================================== */\n\n.szenen-mehr-laden {\n display: grid;\n gap: var(--space-xs);\n justify-items: start;\n padding: var(--space-xs) 0;\n}\n\n.szenen-mehr-laden__button {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.85rem;\n cursor: pointer;\n}\n\n.szenen-mehr-laden__button:disabled {\n cursor: progress;\n opacity: 0.6;\n}\n\n.szenen-mehr-laden__fehler {\n margin: 0;\n color: var(--color-danger, #f87171);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n PROMPTKARTE \u2014 Tags, Vorschau und Bildzahl\n (Kette `szenen-prompt-anzeige-bilder-tags`)\n\n Der Zuschnitt ist der der Library-Karte (`.library-item` + der absolut\n gesetzte Bildstreifen in `LibraryTab`): Textteil links, Deckbild rechts am\n Rand ueber die ganze Kartenhoehe, Bildzahl als Plakette darauf. Dieselben\n Werte (7rem Streifenbreite, linke Trennlinie, Plakette unten rechts), nur\n hier statt in Tailwind-Klassen \u2014 die Szenen-Ansicht teilt dieses Stylesheet\n byteweise mit Flow, und Flow hat kein Tailwind.\n ========================================================================== */\n\n.szenen-promptkarte {\n position: relative;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-sm);\n}\n\n/* Nur wo ein Bild liegt, wird Platz dafuer freigehalten. Ohne Bild nutzt der\n Textteil die ganze Breite \u2014 keine leere Spalte. */\n.szenen-promptkarte--mitbild .szenen-promptkarte__inhalt {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-promptkarte__bild {\n position: absolute;\n top: 0;\n right: 0;\n width: 7rem;\n height: 100%;\n /* Hoechstens so hoch wie breit \u2014 der Streifen bleibt eine Kachel.\n `height: 100%` allein band ihn an die **Kartenhoehe**, und die ist in der\n aufgeklappten Runde die Hoehe des ganzen Prompts: Das Deckbild sprang\n dann als mehrere hundert Pixel hoher, auf Streifenbreite beschnittener\n Balken an den rechten Rand. Geschlossen aendert die Grenze nichts \u2014 dort\n ist die Karte niedriger als 7rem. */\n max-height: 7rem;\n border-left: 1px solid var(--color-border);\n background: #000;\n}\n\n/* Die gemeinsame Kachel bringt `width: 100%` und `aspect-ratio: 1` mit \u2014 hier\n fuellt sie stattdessen den Streifen, genau wie das Library-Deckbild. */\n.szenen-promptkarte__bild .szenen-bildkachel {\n width: 100%;\n height: 100%;\n aspect-ratio: auto;\n}\n\n.szenen-promptkarte__bildzahl {\n position: absolute;\n right: 0.25rem;\n bottom: 0.25rem;\n padding: 0.1rem 0.35rem;\n border-radius: var(--radius-sm);\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 0.62rem;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n/* Ein Kasten je Karte, nicht zwei.\n *\n * `.szenen-view button` (master.css) gibt **jedem** Knopf der Ansicht Rahmen\n * und Hintergrund und schlaegt dabei `.szenen-runs__kopf` (eine Klasse gegen\n * Klasse plus Element). In der Laufhistorie ist das richtig: Dort ist der Kopf\n * der Eintrag. In der Promptkarte ist die Karte der Eintrag \u2014 ein zweiter\n * Kasten darin waere die doppelte Umrandung, die die Library nicht hat.\n * Der Hover braucht eine eigene Zeile, weil die Regel dort spezifischer ist. */\n.szenen-promptkarte .szenen-runs__kopf,\n.szenen-promptkarte .szenen-runs__kopf:hover:not(:disabled) {\n min-height: 0;\n padding: var(--space-xs) 0;\n background: transparent;\n border: none;\n}\n\n/* Dieselbe Karte in der Elementliste.\n *\n * Dort ist der Auswahlknopf die Karte \u2014 er traegt Rahmen, Hintergrund und die\n * Auswahlmarkierung. Der Bildstreifen liegt deshalb **darueber** statt darin:\n * Ein `<button>` nimmt nur Phrasing Content auf, ein Streifen-`div` darin\n * waere ungueltiges Markup. Damit der rechte Kartenrand trotzdem auswaehlbar\n * bleibt, laesst der Streifen Klicks durch. */\n.szenen-elementkarte {\n position: relative;\n}\n\n.szenen-elementkarte--mitbild > button {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-elementkarte > .szenen-promptkarte__bild {\n border-radius: 0 var(--radius-sm) var(--radius-sm) 0;\n}\n\n.szenen-promptkarte__bild--durchklickbar {\n pointer-events: none;\n}\n\n/* Null Bilder: die Zahl, keine Flaeche. */\n/* Die Tagliste bricht um. Auf einem Telefon ist das der Unterschied zwischen\n einer kompakten Karte und einer Zeile, die seitlich herauslaeuft. */\n.szenen-tagliste {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n align-items: center;\n margin: 0 0 var(--space-xs);\n padding: 0;\n list-style: none;\n}\n\n.szenen-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.05rem 0.4rem;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n font-size: 0.72rem;\n line-height: 1.5;\n white-space: nowrap;\n}\n\n/* Herkunft sichtbar, aber ohne zweite Bedeutungsebene: Ein Prompt-Tag steht\n voll, ein reiner Library-Tag zurueckgenommen. Die Karte soll schnell lesbar\n sein, nicht zwei Farbcodes lehren. */\n.szenen-tag[data-herkunft="library"] {\n border-style: dashed;\n opacity: 0.85;\n}\n\n.szenen-tag--rest {\n border-style: none;\n opacity: 0.7;\n}\n\n.szenen-tag__weg {\n border: none;\n background: none;\n padding: 0;\n color: var(--color-text-secondary, inherit);\n font-size: 0.85rem;\n line-height: 1;\n cursor: pointer;\n}\n\n.szenen-tag__weg:disabled {\n cursor: progress;\n opacity: 0.5;\n}\n\n.szenen-taggeber {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-xs);\n margin-bottom: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-taggeber__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: 0;\n}\n\n.szenen-taggeber__label {\n font-size: 0.72rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n opacity: 0.75;\n}\n\n.szenen-taggeber__leer,\n.szenen-taggeber__hinweis {\n font-size: 0.72rem;\n opacity: 0.75;\n}\n\n.szenen-taggeber input[type="text"] {\n flex: 1 1 8rem;\n min-width: 0;\n padding: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n BILDAUFTR\xC4GE \u2014 die bestandsweite Arbeitsqueue\n Kette `szenen-bildauftraege-arbeitsqueue`, Schritt 01.\n ========================================================================== */\n\n.szenen-bildauftraege {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bildauftraege__steuerung,\n.szenen-bildauftraege__filter,\n.szenen-bildauftraege__aktionen,\n.szenen-bildauftraege__nachladen,\n.szenen-bildauftraege__blaettern {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n}\n\n/* Der manuelle Refresh \u2014 Schritt 03 \xA72. Er steht oben und sichtbar, weil er\n die einzige Stelle ist, an der dieser Bereich nachlaedt: Es gibt keinen\n Timer mehr, den er ersetzen koennte. */\n.szenen-bildauftraege__nachladen {\n justify-content: flex-start;\n}\n\n.szenen-bildauftraege__nachladen span {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Die Blaetterleiste der Bildkontrolle \u2014 Schritt 03 \xA73.1. */\n.szenen-bildauftraege__blaettern {\n margin: 0;\n}\n\n/* \u201EWeitere Bilder" \u2014 seit Schritt 06 eine **Leiste in der Zeile**, kein\n aufklappbares Formular: Modell, Anzahl, Knopf nebeneinander. */\n.szenen-bildauftraege__weitere {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: var(--space-xs) 0 0;\n font-size: 0.85rem;\n}\n\n.szenen-bildauftraege__weitere label {\n color: var(--color-text-secondary);\n}\n\n/* Der Lauf-Zaehler: sichtbar, aber nicht im Weg (Schritt 06). */\n.szenen-bildauftraege__laufzaehler {\n padding: 0.05rem var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm, 4px);\n font-size: 0.8rem;\n font-variant-numeric: tabular-nums;\n}\n\n/* Die Vorschau steht oben und beh\xE4lt ihren Platz, auch solange noch kein Bild\n vorliegt \u2014 sie ist die Kontrollfl\xE4che des zweiten Browserfensters (\xA75). */\n.szenen-bildauftraege__letztes {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-bildauftraege__letztes h3 {\n margin: 0;\n font-size: 0.95rem;\n}\n\n.szenen-bildauftraege__letztes .szenen-bildkachel {\n width: min(100%, 22rem);\n height: auto;\n}\n\n.szenen-bildauftraege__lauf {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__lauf p {\n margin: 0.1rem 0;\n}\n\n.szenen-bildauftraege__liste {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildauftraege__zeile {\n display: grid;\n gap: 0.25rem;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__kopf,\n.szenen-bildauftraege__prompt {\n margin: 0;\n}\n\n.szenen-bildauftraege__meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.15rem var(--space-sm);\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bildauftraege__prompt {\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P4: Szene als Studio \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kopf mit Speichern, Hero mit Titelbild und Versions-Pill, die B\xFChne auf\n * einem Punktraster, das Element-Sheet von unten, der Prompt-Start als ein\n * Block, L\xE4ufe als Bildstreifen, Aufklapper unten. Kn\xF6pfe in der B\xFChne und im\n * Sheet setzen die Grundoptik von `.szenen-view button` gezielt zur\xFCck \u2014 daher\n * die zwei Klassen in diesen Selektoren. */\n.szenen-studio {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-studio__kopf {\n position: sticky;\n top: 0;\n z-index: 3;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n}\n\n.szenen-studio__kopf > .szenen-detail__ids {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-studio__ungespeichert {\n color: var(--color-warning);\n font-size: 0.8rem;\n font-weight: 600;\n}\n\n.szenen-view .szenen-studio__speichern {\n min-height: 2.25rem;\n padding: 0 1rem;\n color: var(--color-accent-teal, #2dd4bf);\n background: transparent;\n border-color: var(--color-accent-teal, #2dd4bf);\n border-radius: var(--radius-full);\n font-weight: 650;\n}\n\n.szenen-studio__hero {\n position: relative;\n min-height: 12rem;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-studio__hero--mitbild {\n min-height: 16rem;\n border-color: transparent;\n}\n\n.szenen-studio__titelbild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-studio__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0) 70%);\n}\n\n.szenen-studio__ohnebild {\n position: absolute;\n inset: 0;\n padding: var(--space-md);\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-surface);\n}\n\n.szenen-studio__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__bildfehler {\n margin: 0 0 var(--space-sm);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-studio__herotext {\n position: absolute;\n right: var(--space-md);\n bottom: var(--space-md);\n left: var(--space-md);\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-studio__herotext h3 {\n margin: 0;\n font-size: 1.5rem;\n line-height: 1.2;\n overflow-wrap: anywhere;\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__herotext {\n color: #fff;\n}\n\n.szenen-studio__herometa {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-studio__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n color: inherit;\n background: rgba(0, 0, 0, 0.55);\n border: 1px solid rgba(255, 255, 255, 0.25);\n border-radius: var(--radius-full);\n}\n\n.szenen-studio__hero:not(.szenen-studio__hero--mitbild) .szenen-studio__pill {\n background: var(--color-bg-elevated);\n border-color: var(--color-border);\n}\n\n/* Kette `szenen-design`, P6 \u2014 Titelbild: \u22EF-Menue im Hero, Hinweis, Zeile\n unter \u201ETechnisch" und die Aktion im Bildviewer. */\n.szenen-studio__heromenu {\n position: relative;\n display: inline-flex;\n}\n\n.szenen-view .szenen-studio__menuknopf {\n justify-content: center;\n min-width: 2.25rem;\n padding: 0 0.5rem;\n}\n\n.szenen-studio__menu {\n position: absolute;\n top: calc(100% + 0.25rem);\n left: 0;\n z-index: 5;\n display: grid;\n min-width: 12rem;\n padding: var(--space-xs, 0.25rem);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md, 0.5rem);\n}\n\n.szenen-studio__menu button {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n text-align: left;\n color: inherit;\n background: transparent;\n border: 0;\n}\n\n.szenen-studio__menu button:disabled {\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__titelbildhinweis {\n margin: 0;\n font-size: 0.8rem;\n color: var(--color-warning);\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__titelbildhinweis {\n color: #fde68a;\n}\n\n.szenen-studio__titelbildzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: var(--space-sm) 0;\n font-size: 0.875rem;\n}\n\n.szenen-studio__titelbildref {\n display: block;\n overflow-wrap: anywhere;\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bildviewer__aktion {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n}\n\n.szenen-bildviewer__titelbild {\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.8125rem;\n}\n\n.szenen-studio__komposition {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-studio__abschnittkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-studio__abschnittkopf h4 {\n margin: 0;\n}\n\n.szenen-studio__umschalter {\n display: inline-flex;\n padding: 3px;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button {\n min-height: 2rem;\n padding: 0 0.75rem;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-studio__aufklapper {\n display: grid;\n min-width: 0;\n}\n\n.szenen-studio__aufklapper > details {\n min-width: 0;\n border-top: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details:last-child {\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details > summary {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n cursor: pointer;\n}\n\n.szenen-studio__zusammenfassung {\n margin-left: auto;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Die B\xFChne */\n.szenen-buehne {\n position: relative;\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-buehne--leer {\n display: grid;\n place-items: center;\n aspect-ratio: auto;\n min-height: 8rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-buehne__linien {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n\n.szenen-buehne__linie {\n stroke: var(--color-text-tertiary);\n stroke-width: 1.5;\n}\n\n.szenen-buehne__linie--naehe {\n stroke-width: 1;\n stroke-dasharray: 3 4;\n}\n\n.szenen-buehne__linie--kontakt {\n stroke: var(--color-text-primary);\n stroke-width: 3;\n}\n\n.szenen-buehne__kegel-start {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0.35;\n}\n\n.szenen-buehne__kegel-ende {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0;\n}\n\n.szenen-view .szenen-buehne__node {\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.3rem;\n min-height: 0;\n max-width: 6rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n transform: translate(-50%, -50%);\n}\n\n.szenen-view .szenen-buehne__node:hover:not(:disabled) {\n background: transparent;\n}\n\n.szenen-buehne__symbol {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__symbol {\n width: 4rem;\n height: 4rem;\n border: 2px solid var(--color-text-primary);\n}\n\n.szenen-buehne__node--light .szenen-buehne__symbol {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-buehne__node[aria-pressed="true"] .szenen-buehne__symbol {\n box-shadow: 0 0 0 2px var(--color-accent-blue);\n}\n\n.szenen-buehne__name {\n max-width: 100%;\n padding: 0 0.25rem;\n overflow: hidden;\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__name {\n font-weight: 650;\n}\n\n.szenen-buehne__legende {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-md);\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-buehne__legende > span {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-buehne__legende-hinweis {\n margin-left: auto;\n}\n\n.szenen-buehne__muster {\n display: inline-block;\n width: 1.1rem;\n border-top: 1px dashed var(--color-text-tertiary);\n}\n\n.szenen-buehne__muster--kontakt {\n border-top: 3px solid var(--color-text-primary);\n}\n\n/* Das Element-Sheet */\n.szenen-sheet {\n position: fixed;\n inset: 0;\n z-index: 50;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.szenen-view .szenen-sheet__hintergrund {\n position: absolute;\n inset: 0;\n padding: 0;\n background: rgba(0, 0, 0, 0.6);\n border: none;\n border-radius: 0;\n cursor: default;\n}\n\n.szenen-sheet__flaeche {\n position: relative;\n display: grid;\n gap: var(--space-md);\n width: 100%;\n max-width: 40rem;\n max-height: 85vh;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n overflow-y: auto;\n box-sizing: border-box;\n background: var(--color-bg-surface);\n border-top: 1px solid var(--color-border);\n border-radius: 1.5rem 1.5rem 0 0;\n}\n\n.szenen-sheet__griff {\n justify-self: center;\n width: 2.5rem;\n height: 4px;\n background: var(--color-border);\n border-radius: 2px;\n}\n\n.szenen-sheet__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-sheet__symbol {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 3.5rem;\n height: 3.5rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-sheet__symbol--light {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-sheet__titel {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n}\n\n.szenen-sheet__titel strong {\n font-size: 1.25rem;\n}\n\n.szenen-sheet__titel code {\n overflow: hidden;\n color: var(--color-text-secondary);\n font-family: var(--font-mono);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n}\n\n.szenen-view .szenen-sheet__schliessen {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n margin-left: auto;\n padding: 0;\n border-radius: 50%;\n}\n\n.szenen-sheet__abschnitt {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-sheet__abschnitt h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-sheet__leer {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-sheet__beziehungen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__beziehungen li {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-sheet__beziehungsart {\n color: var(--color-text-secondary);\n}\n\n.szenen-sheet__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__bild {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-sheet__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-sheet__bildtext {\n display: grid;\n gap: 0.2rem;\n padding: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n.szenen-sheet__bildtext code {\n font-family: var(--font-mono);\n}\n\n.szenen-view .szenen-sheet__fertig {\n min-height: 3rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-weight: 700;\n}\n\n/* Der Prompt-Start als ein Block */\n.szenen-start {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-start__primaer {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1.05rem;\n font-weight: 700;\n}\n\n.szenen-start__kosten {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n text-align: center;\n}\n\n.szenen-start__manuell {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-start__zweit {\n min-height: 2.75rem;\n background: transparent;\n}\n\n.szenen-start__erklaerung > summary {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-start__erklaerung[open] .szenen-start__chevron {\n transform: rotate(90deg);\n}\n\n/* L\xE4ufe als Bildstreifen */\n.szenen-streifen {\n display: grid;\n gap: 0.35rem;\n padding: 0 var(--space-sm) var(--space-sm);\n}\n\n.szenen-streifen__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-streifen__bild {\n position: relative;\n aspect-ratio: 3 / 4;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n.szenen-streifen__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-streifen__fehler {\n display: block;\n padding: 0.25rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n}\n\n.szenen-streifen__mehr {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-streifen__anzahl {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n/* \xC4ltere Runden: kompakte Zeile mit \xFCberlappenden Miniaturen. */\n.szenen-streifen--zeile {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bilder {\n display: flex;\n gap: 0;\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild {\n width: 2.1rem;\n height: 2.75rem;\n aspect-ratio: auto;\n border: 2px solid var(--color-bg-surface);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild + .szenen-streifen__bild {\n margin-left: -0.75rem;\n}\n\n.szenen-runs__eintrag--karte {\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n/* Szenenst\xE4nde enthalten mehrere Runden derselben eingefrorenen Szene (#538). */\n.szenen-runs__stand > h5 {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-runs__stand-laeufe {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-runs__stand-laeufe > li {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P5 \u2014 der Prompt-Lauf als Ergebnisgalerie\n ========================================================================== */\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-chip,\n.szenen-view .szenen-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n min-height: 1.75rem;\n padding: 0 0.65rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-chip--knopf {\n min-height: 2.25rem;\n color: var(--color-text-primary);\n cursor: pointer;\n}\n\n.szenen-chip--library,\n.szenen-view .szenen-chip--library {\n color: var(--color-accent-teal, #2dd4bf);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n/* \u2500\u2500 Navigation der Laufansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__nav {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n scroll-margin-top: var(--space-md);\n}\n\n.szenen-view .szenen-lauf__zurueck {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n min-height: 2.75rem;\n padding: 0 0.6rem 0 0.25rem;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__blaettern {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.2rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-lauf__blaettern button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n min-height: 2.5rem;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n/* \u2500\u2500 Kopf: Runde, Status, Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-laufinhalt {\n gap: var(--space-md);\n}\n\n.szenen-lauf__kopf {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-lauf__szene {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__titelzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__runde {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.6rem;\n font-weight: 700;\n line-height: 1.15;\n}\n\n.szenen-lauf__status {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 1.6rem;\n padding: 0 0.6rem;\n border: 1px solid currentColor;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-lauf__status::before {\n content: "";\n width: 0.4rem;\n height: 0.4rem;\n border-radius: 50%;\n background: currentColor;\n}\n\n.szenen-lauf__status[data-status="succeeded"] { color: var(--color-success); }\n.szenen-lauf__status[data-status="failed"] { color: var(--color-danger); }\n\n.szenen-lauf__chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.4rem;\n min-width: 0;\n}\n\n.szenen-lauf__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Galerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf .szenen-bilder__ausgang {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-lauf {\n gap: var(--space-md);\n margin-top: 0;\n}\n\n.szenen-lauf .szenen-bilder__batch {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-bildgalerie--ergebnis {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n overflow: hidden;\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--einzeln {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildgalerie__kachel {\n border: none;\n border-radius: 0;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildgalerie__kachel {\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildkachel {\n aspect-ratio: 3 / 4;\n}\n\n.szenen-bildgalerie__alle-text {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.1rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n font-size: 0.75rem;\n}\n\n.szenen-bildgalerie__alle-text strong {\n font-size: 1.25rem;\n}\n\n/* P5-Akzeptanz: Eine leere Kachel nennt ihren Grund \u2014 lesbar, nicht nur im\n Tooltip. */\n.szenen-bildkachel__grund {\n display: -webkit-box;\n max-width: 90%;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.3;\n text-align: center;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n/* \u2500\u2500 Karten: Prompt, Tags \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__karte {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-lauf__kartenkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__label {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__legende {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-lauf__kopieren {\n display: inline-flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__prompttext {\n margin: 0;\n color: var(--color-text-primary);\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n/* Drei Zeilen Vorschau \u2014 der volle Text bleibt im Dokument (Kopieren,\n Markieren), gek\xFCrzt wird nur die Darstellung. */\n.szenen-lauf__prompttext--zu {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n.szenen-view .szenen-lauf__ganz {\n justify-self: start;\n min-height: 2.25rem;\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-primary));\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__negativ {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-lauf__negativ[hidden] {\n display: none;\n}\n\n.szenen-lauf__negativ p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.szenen-lauf__karte .szenen-taggeber {\n margin: 0;\n}\n\n.szenen-tagliste .szenen-tag__neu {\n min-height: 2rem;\n}\n\n/* \u2500\u2500 \u201ENeue Bilder" (Serverauftrag des Hosts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-neuebilder {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg, var(--radius-md));\n}\n\n.szenen-neuebilder__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-neuebilder__kopf h4 {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.05rem;\n}\n\n.szenen-neuebilder__symbol {\n color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-neuebilder__weg {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-neuebilder__felder {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-wahlfeld {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding: 0.4rem 0.6rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-wahlfeld__label {\n color: var(--color-text-secondary);\n font-size: 0.68rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-wahlfeld select {\n min-height: 1.75rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n font-weight: 600;\n}\n\n.szenen-umschalter {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n padding: 3px;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-umschalter button {\n min-height: 2.5rem;\n background: transparent;\n border: none;\n}\n\n.szenen-view .szenen-umschalter button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n font-weight: 600;\n}\n\n.szenen-view .szenen-neuebilder__start {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1rem;\n font-weight: 700;\n}\n\n.szenen-view .szenen-neuebilder__start:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n opacity: 0.9;\n}\n\n.szenen-neuebilder__laedt,\n.szenen-neuebilder__fehler {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-neuebilder__laedt { color: var(--color-text-secondary); }\n\n/* Referenzbild eines Laufs (#569-Folge): eigener Bereich \xFCber den Ergebnissen. */\n.szenen-bilder__referenz {\n display: flex;\n gap: var(--space-md);\n align-items: center;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-md);\n}\n\n.szenen-bilder__referenzbild {\n flex: none;\n width: 9rem;\n}\n\n.szenen-bilder__referenzbild img {\n display: block;\n width: 100%;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__referenzleer {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n font-size: 0.8rem;\n}\n\n.szenen-bilder__referenztext {\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-bilder__referenztext strong {\n color: var(--color-text-primary);\n}\n\n/* Referenzbild und Prompt am einzelnen Bildauftrag. */\n.szenen-zeitleiste__referenz {\n display: flex;\n gap: var(--space-sm);\n align-items: center;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-zeitleiste__referenz img,\n.szenen-zeitleiste__referenz-leer {\n display: block;\n width: 4.5rem;\n aspect-ratio: 4 / 3;\n object-fit: cover;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-zeitleiste__prompt {\n white-space: pre-wrap;\n user-select: text;\n}\n\n/* Das mitgegebene Kamera-Preview (#569-Folge) \u2014 sichtbar, bevor bestellt wird. */\n.szenen-neuebilder__referenz {\n margin: 0;\n padding: 0.35rem 0.6rem;\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-left: 2px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n font-size: 0.82rem;\n}\n.szenen-neuebilder__fehler { color: var(--color-danger); }\n\n.szenen-neuebilder__warnung > summary {\n display: flex;\n align-items: flex-start;\n gap: var(--space-sm);\n color: var(--color-warning);\n font-size: 0.85rem;\n line-height: 1.45;\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-neuebilder__warnung > summary::-webkit-details-marker { display: none; }\n\n.szenen-neuebilder__warnung > p,\n.szenen-neuebilder__zuordnung ul {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n line-height: 1.5;\n}\n\n.szenen-neuebilder__zuordnung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-neuebilder__zuordnung ul {\n padding-left: 1.1rem;\n}\n\n/* \u2500\u2500 Aufklapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-aufklapper {\n display: grid;\n min-width: 0;\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-aufklapper__eintrag,\n.szenen-aufklapper .szenen-bilder__aktion {\n min-width: 0;\n padding: 0;\n border: none;\n border-top: 1px solid var(--color-border);\n border-radius: 0;\n}\n\n.szenen-aufklapper__eintrag > summary,\n.szenen-aufklapper .szenen-bilder__aktion > summary {\n list-style: none;\n cursor: pointer;\n}\n\n.szenen-aufklapper__eintrag > summary::-webkit-details-marker { display: none; }\n\n.szenen-aufklapper .szenen-bilder__aktion[open] > summary {\n margin-bottom: 0;\n}\n\n.szenen-aufklapper__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: 0 var(--space-xs);\n color: var(--color-text-primary);\n font-weight: 400;\n}\n\n.szenen-aufklapper__pfeil {\n flex: none;\n transition: transform 0.15s ease;\n}\n\ndetails[open] > summary .szenen-aufklapper__pfeil {\n transform: rotate(90deg);\n}\n\n.szenen-aufklapper__titel {\n min-width: 0;\n}\n\n.szenen-aufklapper__meta {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-aufklapper__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: 0 var(--space-xs) var(--space-md) 2rem;\n}\n\n@media (max-width: 760px) {\n .szenen-aufklapper__inhalt {\n padding-left: var(--space-xs);\n }\n}\n\n.szenen-aufklapper__inhalt > p {\n margin: 0;\n}\n\n/* \u2500\u2500 Zeitleiste der Bildauftr\xE4ge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-zeitleiste {\n display: grid;\n gap: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-zeitleiste__schritt {\n position: relative;\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-md);\n}\n\n/* Die Linie zur n\xE4chsten Zeile. */\n.szenen-zeitleiste__schritt:not(:last-child)::before {\n content: "";\n position: absolute;\n top: 2.1rem;\n bottom: 0;\n left: calc(1rem - 1px);\n width: 2px;\n background: var(--color-border);\n}\n\n.szenen-zeitleiste__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: 1px solid var(--color-border);\n border-radius: 50%;\n background: var(--color-bg-elevated);\n color: var(--color-text-secondary);\n font-weight: 700;\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fertig"] {\n color: var(--color-success);\n border-color: var(--color-success);\n background: var(--color-accent-green-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fehlgeschlagen"] {\n color: var(--color-danger);\n border-color: var(--color-danger);\n background: var(--color-accent-red-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="teilweise"] {\n color: var(--color-warning);\n border-color: var(--color-warning);\n}\n\n.szenen-zeitleiste__inhalt {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding-top: 0.3rem;\n}\n\n.szenen-zeitleiste__titel {\n color: var(--color-text-primary);\n font-size: 0.9rem;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis,\n.szenen-zeitleiste__zusatz {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis[data-zustand="fehlgeschlagen"] { color: var(--color-danger); }\n.szenen-zeitleiste__ergebnis[data-zustand="teilweise"] { color: var(--color-warning); }\n\n.szenen-zeitleiste__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin-top: var(--space-xs);\n}\n\n.szenen-zeitleiste__meldung > summary {\n min-height: 2rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n line-height: 2rem;\n cursor: pointer;\n}\n\n.szenen-zeitleiste__meldung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__meldung code {\n display: block;\n margin-top: var(--space-xs);\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-family: var(--font-mono);\n font-size: 0.72rem;\n overflow-wrap: anywhere;\n}\n\n/* \u2500\u2500 Annahmen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-annahmen {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-annahmen__zeile {\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-annahmen__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: 50%;\n}\n\n.szenen-annahmen__text {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n font-size: 0.85rem;\n line-height: 1.45;\n overflow-wrap: anywhere;\n}\n\n.szenen-annahmen__art {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-annahmen__text details > summary,\n.szenen-lauf__erlaeuterung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-annahmen__text details p,\n.szenen-lauf__erlaeuterung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n.szenen-lauf__handeingabe h5 {\n margin: 0 0 var(--space-xs);\n}\n\n.szenen-lauf__handeingabe p {\n margin: 0;\n font-size: 0.85rem;\n}\n\n/* Kette `szenen-design`, P7 (#533) \u2014 die Szene aus Bausteinen. Felder als\n Karten, Bausteine im Feld als Chips; die Leiste ist das vorhandene\n Bottom-Sheet mit Bildkacheln. Bedient wird durch Antippen, nicht Ziehen. */\n.szenen-bausteinfelder {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-bausteinfelder__liste {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinfeld {\n display: grid;\n align-content: start;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bausteinfeld__kopf {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-bausteinfeld__leer,\n.szenen-bausteinfeld__gesperrt {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bausteinfeld__refs {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinchip {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-view .szenen-bausteinchip__name {\n min-height: 2.25rem;\n max-width: 100%;\n padding: 0 0.75rem;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinchip__aktionen {\n display: inline-flex;\n gap: var(--space-xs);\n}\n\n.szenen-view .szenen-bausteinchip__aktionen button {\n min-width: 2.25rem;\n min-height: 2.25rem;\n padding: 0 0.6rem;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-bausteinfeld__plus {\n display: inline-flex;\n align-items: center;\n justify-self: start;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: transparent;\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-bausteinfelder__weitere {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-bausteinfelder__weitere h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-bausteinfelder__weitere ul {\n display: grid;\n gap: 0.25rem;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: 0.85rem;\n}\n\n.szenen-bausteinfelder__ort {\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bausteinleiste__suche {\n min-height: 2.75rem;\n width: 100%;\n box-sizing: border-box;\n}\n\n.szenen-bausteinleiste {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-view .szenen-bausteinkachel {\n display: grid;\n gap: 0.25rem;\n width: 100%;\n padding: 0;\n overflow: hidden;\n text-align: left;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-bausteinkachel[aria-pressed="true"] {\n border-color: var(--color-text-primary);\n}\n\n.szenen-view .szenen-bausteinkachel:disabled {\n cursor: default;\n opacity: 0.7;\n}\n\n.szenen-bausteinkachel__name {\n display: flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0 0.4rem;\n overflow: hidden;\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinkachel__status,\n.szenen-bausteinkachel__grund {\n padding: 0 0.4rem 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n@media (min-width: 761px) {\n .szenen-bausteinleiste {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n }\n}\n/* Issue #569: mobile stage controls and exact camera letterbox. */\n/* 3D-B\xFChne (#569): Ansicht zuerst, Werte als Karten darunter. */\n.szenen-3d {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-3d__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-3d__kopf h4 {\n margin: 0 auto 0 0;\n}\n\n/* Als Ansicht \u201E3D\u201C der Komposition: kein zweiter Rahmen im Abschnitt. */\n.szenen-3d--eingebettet {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-3d__kopf {\n flex-wrap: wrap;\n}\n\n.szenen-3d .szenen-3d__aufbau {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-width: 0;\n margin-right: auto;\n}\n\n.szenen-3d .szenen-3d__aufbau select {\n width: auto;\n min-width: 0;\n max-width: 100%;\n}\n\n.szenen-3d__stand {\n min-width: 0;\n margin-right: auto;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-3d__sync {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__sync::before {\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: var(--radius-full);\n content: "";\n}\n\n.szenen-3d__sync[data-state="speichert"]::before {\n background: var(--color-warning);\n}\n\n.szenen-3d__sync[data-state="ansicht"]::before {\n background: var(--color-accent-blue);\n}\n\n.szenen-3d__meldung,\n.szenen-3d__fehler {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-elevated);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-3d__fehler {\n border-left-color: var(--color-danger);\n}\n\n.szenen-3d__oeffnen {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-3d label {\n display: grid;\n gap: 0.3rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__leiste {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-3d__katalog {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-3d__katalog > span {\n margin-right: 0.15rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-3d__katalog button,\n.szenen-view .szenen-3d__elemente button {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2rem;\n padding: 0 0.7rem;\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-3d__katalog i,\n.szenen-3d__elemente i {\n flex: none;\n width: 0.6rem;\n height: 0.6rem;\n border-radius: 2px;\n}\n\n.szenen-view .szenen-3d__elemente button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-text-primary);\n}\n\n/* Viewport: feste H\xF6he f\xFCr Drauf- und Seitenansicht; die Kameraansicht wird\n * darin auf das gespeicherte Kameraformat eingepasst (Letterbox). */\n.szenen-3d__viewport {\n position: relative;\n display: grid;\n place-items: center;\n height: clamp(320px, 58vh, 560px);\n overflow: hidden;\n background: #0d0f12;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n container-type: size;\n outline: none;\n}\n\n.szenen-3d__viewport:focus-visible {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-3d__surface {\n position: relative;\n width: 100%;\n height: 100%;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.szenen-3d__viewport[data-view="camera"] {\n background: #050607;\n}\n\n.szenen-3d__viewport[data-view="camera"] .szenen-3d__surface {\n width: min(100cqw, calc(100cqh * var(--seitenverhaeltnis)));\n height: min(100cqh, calc(100cqw / var(--seitenverhaeltnis)));\n}\n\n.szenen-3d__hud {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #d4d4d4;\n font-size: 0.78rem;\n font-variant-numeric: tabular-nums;\n pointer-events: none;\n}\n\n.szenen-3d__hud--werkzeuge {\n top: 0.6rem;\n right: 0.6rem;\n gap: 0.25rem;\n pointer-events: auto;\n}\n\n.szenen-view .szenen-3d__hud--werkzeuge button {\n min-width: 2rem;\n min-height: 2rem;\n padding: 0 0.6rem;\n color: #e5e5e5;\n background: rgba(23, 23, 23, 0.85);\n border-color: rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(4px);\n}\n\n.szenen-3d__hud--kamera {\n top: 0.6rem;\n left: 0.6rem;\n padding: 0.2rem 0.55rem;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n}\n\n.szenen-3d__hud--info {\n bottom: 0.6rem;\n left: 0.6rem;\n max-width: calc(100% - 7rem);\n padding: 0.25rem 0.6rem;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.szenen-3d__hud--info strong {\n color: #ffffff;\n font-weight: 600;\n}\n\n.szenen-3d__hud i {\n font-style: normal;\n font-weight: 700;\n}\n\n.szenen-3d__hud--achsen {\n right: 0.75rem;\n bottom: 0.7rem;\n gap: 0.6rem;\n font-weight: 700;\n}\n\n.szenen-3d__labels {\n position: absolute;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.szenen-3d__label {\n position: absolute;\n padding: 0.05rem 0.4rem;\n color: #f5f5f5;\n background: rgba(10, 10, 10, 0.72);\n border-left: 2px solid var(--farbe, #9bafbc);\n border-radius: 3px;\n font: 500 0.72rem/1.4 var(--font-sans);\n white-space: nowrap;\n transform: translate(-50%, 6px);\n}\n\n.szenen-3d__label--side {\n transform: translate(-50%, calc(-100% - 6px));\n}\n\n.szenen-3d__label--kamera {\n color: #bfdbfe;\n border-left-color: #60a5fa;\n transform: translate(14px, -50%);\n}\n\n.szenen-3d__label--kamera.is-links {\n transform: translate(calc(-100% - 14px), -50%);\n}\n\n.szenen-3d__label.is-selected {\n color: #000000;\n background: #ffffff;\n}\n\n.szenen-3d__inspektor {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-3d__karte {\n display: grid;\n align-content: start;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-3d__karte h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.72rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-3d__elemente {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem;\n}\n\n.szenen-3d__werte {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.4rem;\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.szenen-3d__werte legend {\n margin-bottom: 0.4rem;\n padding: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-3d__werte legend span {\n margin-left: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n font-weight: 400;\n}\n\n.szenen-3d__zeilenkopf {\n grid-column: 1 / -1;\n margin-top: 0.2rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__werte > button {\n grid-column: 1 / -1;\n}\n\n.szenen-3d .szenen-3d__feld {\n position: relative;\n display: block;\n}\n\n.szenen-3d__achse {\n position: absolute;\n top: 50%;\n left: 0.55rem;\n font-size: 0.72rem;\n font-weight: 700;\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n.szenen-3d__achse--x { color: #f87171; }\n.szenen-3d__achse--y { color: #4ade80; }\n.szenen-3d__achse--z { color: #60a5fa; }\n\n.szenen-view .szenen-3d__feld input {\n padding-left: 1.6rem;\n font-variant-numeric: tabular-nums;\n}\n\n.szenen-3d__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-3d__abschluss {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-3d__primaer {\n min-height: 2.75rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view .szenen-3d__primaer:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-primary-hover);\n}\n\n.szenen-view .szenen-3d__nebenaktion {\n justify-self: start;\n min-height: 2rem;\n padding: 0;\n background: none;\n border: none;\n font-size: 0.82rem;\n text-decoration: underline;\n}\n\n/* Hinweise passend zum Eingabeger\xE4t; ohne Angabe gilt die Maus-Variante. */\n.szenen-3d__nur-touch {\n display: none;\n}\n\n@media (hover: none) and (pointer: coarse) {\n .szenen-3d__nur-maus {\n display: none;\n }\n\n .szenen-3d__nur-touch {\n display: inline;\n }\n\n /* Fingergerechte Ziele (44 px) f\xFCr Ansichtssteuerung, Katalog und Elemente. */\n .szenen-view .szenen-3d__hud--werkzeuge button,\n .szenen-view .szenen-3d__katalog button,\n .szenen-view .szenen-3d__elemente button,\n .szenen-view .szenen-3d .szenen-studio__umschalter button {\n min-width: 2.75rem;\n min-height: 2.75rem;\n }\n}\n\n@media (max-width: 760px) {\n .szenen-3d {\n gap: var(--space-sm);\n padding: var(--space-sm);\n }\n\n .szenen-3d__leiste {\n display: grid;\n }\n\n .szenen-3d .szenen-studio__umschalter {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n }\n\n /* Katalog als eine Zeile, die in sich scrollt, statt die Ansicht nach unten zu schieben. */\n .szenen-3d__katalog {\n flex-wrap: nowrap;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .szenen-3d__katalog > * {\n flex: none;\n }\n\n .szenen-3d__viewport {\n height: clamp(300px, 62svh, 560px);\n margin: 0 calc(-1 * var(--space-sm));\n border-right: none;\n border-left: none;\n border-radius: 0;\n }\n\n .szenen-3d__hud--info {\n max-width: calc(100% - 1.2rem);\n bottom: 2.4rem;\n }\n\n .szenen-3d__hud--achsen {\n bottom: 0.8rem;\n left: 0.75rem;\n right: auto;\n }\n}\n\n/* One DOM canvas, no nested React renderer. */\n.szenen-3d__canvas { display: block; width: 100%; height: 100%; }\n\n/* Prompt choices before the 3D run; mobile buttons wrap within each category. */\n.szenen-3d__prompt details { margin-block: .65rem; }\n.szenen-3d__prompt summary { cursor: pointer; font-weight: 600; }\n.szenen-3d__prompt fieldset { border: 0; padding: .6rem 0; min-width: 0; }\n.szenen-3d__prompt legend { color: var(--color-text-secondary); font-size: .85rem; }\n.szenen-3d__prompt textarea { min-height: 6rem; width: 100%; box-sizing: border-box; }\n.szenen-3d__referenz { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .9rem; }\n\n.szenen-3d__gemini img { display: block; width: 100%; max-height: 28rem; object-fit: contain; background: #eef0f3; border-radius: .4rem; }\n.szenen-3d__gemini pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; font-size: .8rem; }\n.szenen-3d__gemini ul { list-style: none; padding: 0; }\n.szenen-3d__gemini li { margin-block: .6rem; overflow-wrap: anywhere; }\n.szenen-3d__gemini li i { display: inline-block; width: .9rem; height: .9rem; margin-right: .4rem; border-radius: .15rem; }\n';
|
|
64
|
+
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n/* Kette `szenen-design`, P1 \u2014 Bild zuerst, Text auf Abruf. Der Kopf ist nur\n * noch Titel und \u24D8; die Erklaerung klappt darunter auf. */\n.szenen-view__intro {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-view__titel {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n font-size: clamp(1.5rem, 3vw, 1.9rem);\n font-weight: 700;\n letter-spacing: -0.01em;\n line-height: 1.15;\n}\n\n.szenen-view__eyebrow {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-view__info {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-view__info[aria-expanded="true"] {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-view__intro-text {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n font-size: 0.85rem;\n line-height: 1.4;\n}\n\n.szenen-icon {\n flex: none;\n}\n\n/* Fuer Screenreader sichtbar, fuer das Auge nicht \u2014 Status-Punkte und\n * Node-Symbole tragen ihre Bedeutung als Text. */\n.szenen-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n/* Die Bereiche als Pill-Leiste. Sie scrollt in sich, nie die Seite: `min-width:\n * 0` haelt sie in der Spalte, `overflow-x: auto` macht jeden Bereich\n * erreichbar, auch wenn nicht alle nebeneinander passen. */\n.szenen-view__nav {\n display: flex;\n flex-wrap: nowrap;\n gap: var(--space-xs);\n min-width: 0;\n padding: 0 0 var(--space-xs);\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view .szenen-view__nav button {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.9rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.875rem;\n}\n\n.szenen-view .szenen-view__nav button.is-active,\n.szenen-view .szenen-view__nav button[aria-selected="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n/* `box-sizing` steht hier und nicht beim Host: Die React-App bringt in\n * `master.css` einen globalen `* { box-sizing: border-box }` mit, Flow **nicht**\n * \u2014 dort ragte `width: 100%` plus Innenabstand um die Randbreite aus dem\n * Elternelement heraus und erzeugte auf ~390 px einen horizontalen Scroll. Die\n * gemeinsame Ansicht darf sich auf keinen Host-Reset verlassen. */\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-erweitert,\n.szenen-prompts,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Arbeitsoberflaeche: Liste links, Bearbeitung rechts.\n *\n * Breit stehen beide Spalten nebeneinander \u2014 die Auswahl bleibt sichtbar,\n * waehrend bearbeitet wird. Schmal rendert die Komponente nur eine der beiden;\n * hier steht deshalb keine Regel, die die andere versteckt. */\n@media (min-width: 761px) {\n .szenen-elements {\n grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);\n align-items: start;\n }\n\n .szenen-elements__master,\n .szenen-elements__detail {\n min-width: 0;\n }\n}\n\n.szenen-elements__master,\n.szenen-elements__detail {\n display: grid;\n gap: var(--space-sm);\n align-content: start;\n min-width: 0;\n}\n\n.szenen-elements__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-elements__heading {\n margin: 0;\n font-size: 1.05rem;\n}\n\n.szenen-elements__scope {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-elements__scope > select {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.szenen-elements__new {\n flex: none;\n font-weight: 700;\n}\n\n.szenen-elements__create {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-elements__create label {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-elements__create-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n}\n\n.szenen-elements__options > summary {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n cursor: pointer;\n}\n\n.szenen-elements__back {\n justify-self: start;\n font-weight: 700;\n}\n\n.szenen-elements__empty-detail {\n margin: 0;\n color: var(--color-text-tertiary);\n}\n\n.szenen-elements__filter,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button > .szenen-elements__title {\n flex: 1 1 100%;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n/* B1 \u2014 die geschlossene Runde. Vorher stand die `run_id` als erstes und war\n die einzige Information, die niemand liest; jetzt beantwortet die Kopfzeile\n welche Runde, ob sie durchging, mit welchem Modell und was ungef\xE4hr\n herauskam. */\n.szenen-runs__hinweis {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n}\n\n.szenen-runs__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n width: 100%;\n padding: var(--space-xs) 0;\n text-align: left;\n color: var(--color-text-secondary);\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.szenen-runs__marke {\n font-weight: 700;\n color: var(--color-text-primary);\n}\n\n.szenen-runs__status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n}\n\n.szenen-runs__status[data-status="succeeded"] {\n border-color: var(--color-success);\n}\n\n.szenen-runs__status[data-status="failed"] {\n border-color: var(--color-danger);\n}\n\n.szenen-runs__modell {\n font-size: 0.75rem;\n}\n\n/* Der Auszug ist die Inhaltsvorschau der Runde. Er bekommt eine eigene Zeile,\n damit er nicht mit Marke und Modell um dieselbe Zeile ringt. */\n.szenen-runs__auszug {\n flex: 1 1 100%;\n min-width: 0;\n color: var(--color-text-tertiary);\n font-size: 0.8125rem;\n}\n\n/* B2 \u2014 ein Fehler steht ausserhalb der aufklappbaren Fl\xE4che: Wer eine rote\n Runde sieht, soll nicht erst klicken m\xFCssen, um zu erfahren, woran sie\n gescheitert ist. */\n.szenen-runs__fehler {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n}\n\n.szenen-runs__fehler p {\n margin: 0;\n}\n\n.szenen-runs__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-runs__prompt > h5,\n.szenen-runs__sekundaer > h5 {\n margin: 0 0 var(--space-xs);\n}\n\n/* Im Kopf traegt die Zeile selbst den Abstand \u2014 sonst kaeme er doppelt. */\n.szenen-runs__promptkopf > h5 {\n margin: 0;\n}\n\n/* Ueberschrift und Kopierknopf in einer Zeile. Der Knopf gehoert an den Text,\n den er kopiert \u2014 nicht an den Rand der Runde, wo er neben dem falschen\n Abschnitt stuende. */\n.szenen-runs__promptkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n margin: 0 0 var(--space-xs);\n}\n\n/* Ein kompakter Knopf, kein zweiter Titel: Der Prompt ist die Hauptsache des\n Abschnitts, die Aktion daneben darf ihn nicht ueberstimmen. Rahmen und\n Hintergrund kommen aus `.szenen-view button` und bleiben \u2014 dieselbe Optik wie\n jeder andere Knopf der Ansicht; hier wird nur die Groesse zurueckgenommen.\n Zwei Klassen im Selektor, weil `.szenen-view button` sonst spezifischer ist. */\n.szenen-runs__promptkopf .szenen-runs__kopieren {\n min-height: 0;\n padding: 0.1rem 0.45rem;\n font-size: 0.72rem;\n}\n\n/* Regel 11: die Bestaetigung nennt die Zahl, nicht nur \u201EErfolgreich". */\n.szenen-runs__kopiert {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-runs__prompt > p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.szenen-runs__prompt--negativ > p,\n.szenen-runs__sekundaer > p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n}\n\n.szenen-runs__mehr {\n justify-self: start;\n margin-top: var(--space-xs);\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-secondary));\n background: transparent;\n border: none;\n font-size: 0.75rem;\n text-decoration: underline;\n cursor: pointer;\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n /* C1 \u2014 auf 390 px bleiben drei Kacheln je Reihe gross genug zum Erkennen\n und klein genug, dass vier Bilder eine Reihe sind und keine Seite. */\n .szenen-bildgalerie {\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n }\n\n /* Der Viewer bekommt den ganzen Bildschirm; die Bl\xE4tterkn\xF6pfe bleiben am\n Rand, wo der Daumen sie erreicht. */\n .szenen-bildviewer {\n padding: var(--space-xs);\n }\n\n .szenen-bildviewer__blaettern {\n width: 2.25rem;\n height: 4rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n grid-column: 1 / -1;\n }\n\n /* Schmal ist die Liste eine Spalte, und die Auswahl fuehrt weiter \u2014 der\n * Eintrag ist deshalb ein Ziel fuer den Finger, keine Kachel. */\n .szenen-elements__list {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .szenen-elements__list > li > button {\n min-height: 2.75rem;\n }\n\n .szenen-elements__back {\n justify-self: stretch;\n min-height: 2.5rem;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P2: Szenen-\xDCbersicht als Bildgalerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kacheln wie in der Library: quadratisch, Deckbild, Titel ueber einem\n * Verlauf, Bildzahl als Plakette. Eine Szene ohne Bild zeigt ihre\n * Node-Symbole; ein nicht ladbares Deckbild nennt den Grund. Die Schrift auf\n * dem Bild ist hell auf dunklem Verlauf \u2014 unabhaengig vom Hostthema, weil das\n * Bild es auch ist. */\n.szenen-galerie {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-galerie__kopf > .szenen-elements__heading {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-galerie__anzahl,\n.szenen-galerie__sortierung {\n color: var(--color-text-secondary);\n font-weight: 400;\n}\n\n.szenen-galerie__sortierung {\n font-size: 0.8rem;\n}\n\n.szenen-galerie__raster {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));\n gap: 0.625rem;\n min-width: 0;\n}\n\n/* Die Kacheln sind Zellen desselben Rasters wie die Neu-Kachel. */\n.szenen-view .szenen-galerie__liste {\n display: contents;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-galerie__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-galerie__kachel > button,\n.szenen-view .szenen-galerie__neu,\n.szenen-view .szenen-galerie__zuletzt {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-galerie__kachel > button {\n aspect-ratio: 1 / 1;\n}\n\n.szenen-view .szenen-galerie__kachel > button[aria-current="true"],\n.szenen-view .szenen-galerie__zuletzt[aria-current="true"] {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-galerie__bild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-galerie__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.88) 0%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0) 65%);\n}\n\n.szenen-galerie__ohnebild {\n position: absolute;\n inset: 0;\n padding: 0.75rem;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 14px 14px,\n var(--color-bg-surface);\n}\n\n.szenen-galerie__bildfehler {\n position: absolute;\n inset: 0;\n /* Oben Platz fuer Status-Punkte und Bildzahl, die darueber liegen. */\n padding: 2.25rem 0.75rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-galerie__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.25rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__text,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__zuletzt-text {\n color: #fff;\n}\n\n.szenen-galerie__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 0.875rem;\n font-weight: 650;\n line-height: 1.25;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n overflow-wrap: anywhere;\n}\n\n.szenen-galerie__meta {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__meta,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-galerie__tags {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.szenen-galerie__tag {\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n overflow: hidden;\n color: inherit;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-full);\n font-size: 0.68rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__tag {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.szenen-galerie__status {\n position: absolute;\n top: 0.7rem;\n left: 0.7rem;\n display: flex;\n gap: 0.3rem;\n}\n\n.szenen-galerie__punkt {\n width: 0.625rem;\n height: 0.625rem;\n background: var(--color-text-secondary);\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n.szenen-galerie__punkt[data-ton="info"] { background: var(--color-accent-blue); }\n.szenen-galerie__punkt[data-ton="ok"] { background: var(--color-success); }\n.szenen-galerie__punkt[data-ton="fertig"] { background: var(--color-warning); }\n/* Unvollstaendig ist ein Ring: Die Form unterscheidet es von \u201Evollstaendig",\n * nicht nur der Farbton (P8). */\n.szenen-galerie__punkt[data-ton="warn"] {\n background: transparent;\n box-shadow: inset 0 0 0 2px var(--color-accent-orange), 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n/* Die Legende der Punkte \u2014 einmal je Ansicht. */\n.szenen-statuslegende {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem 0.85rem;\n margin: 0;\n padding: 0;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n list-style: none;\n}\n\n.szenen-statuslegende__eintrag {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-statuslegende .szenen-galerie__punkt {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.szenen-galerie__bildzahl {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.15rem 0.5rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-galerie__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: 0.3rem;\n}\n\n.szenen-galerie__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 1.875rem;\n height: 1.875rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-galerie__symbol[data-node-type="light"] {\n color: var(--color-warning);\n}\n\n.szenen-galerie__symbol--rest {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n}\n\n.szenen-view .szenen-galerie__neu {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.6rem;\n aspect-ratio: 1 / 1;\n text-align: center;\n background: var(--color-bg-app);\n border: 1.5px dashed var(--color-border-hover, var(--color-border));\n}\n\n.szenen-galerie__neu-plus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border-radius: 50%;\n}\n\n.szenen-galerie__neu-titel {\n font-size: 0.95rem;\n font-weight: 600;\n}\n\n.szenen-galerie__neu-text {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt-bild {\n position: relative;\n display: block;\n aspect-ratio: 4 / 3;\n max-height: 17rem;\n width: 100%;\n}\n\n.szenen-galerie__chip {\n position: absolute;\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.3rem 0.6rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt .szenen-galerie__status {\n right: 0.75rem;\n left: auto;\n top: 1rem;\n}\n\n/* Die Symbole einer Szene ohne Bild stehen unter dem Chip, nicht darauf. */\n.szenen-galerie__zuletzt .szenen-galerie__ohnebild {\n padding-top: 3rem;\n}\n\n.szenen-galerie__zuletzt-text {\n position: absolute;\n right: 1rem;\n bottom: 0.9rem;\n left: 1rem;\n display: grid;\n gap: 0.35rem;\n}\n\n.szenen-galerie__zuletzt-text .szenen-galerie__titel {\n font-size: 1.3rem;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.szenen-galerie__zuletzt-fuss {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: 0.75rem 0.9rem;\n}\n\n.szenen-galerie__oeffnen {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.25rem;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 Browser und Inspector, dem Labs-Tab nachgebildet,\n aber mit dem CSS dieser Ansicht: eine gemeinsame Komponente \xFCber zwei\n Dom\xE4nengrenzen w\xE4re eine Kopplung, die keiner gewollt hat.\n\n Der Review vom 2026-08-22 (R12.1/R12.2) hat den Ma\xDFstab gesetzt: Der Bestand\n ist ein **Browser**, kein Seiteninhalt. Vierzig Werke d\xFCrfen die Szenenseite\n nicht meterlang machen, und zw\xF6lf Varianten eines Werkes keine zw\xF6lf\n Bildschirmseiten. Deshalb steht hier alles unter zwei Regeln \u2014 begrenzte\n Fl\xE4che mit eigenem Scroll, und Kacheln statt Karten. */\n\n/* \u2500\u2500 Ebene 1: der Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl {\n /* Dieselbe Begr\xFCndung wie beim Inspector: Als Grid-Element w\xFCrde der\n W\xE4hler sonst so breit wie sein breitester Inhalt. */\n min-width: 0;\n}\n\n.szenen-bildwahl__browser {\n /* Die eigene Scrollfl\xE4che ist der ganze Punkt: Der Bestand w\xE4chst nach\n innen, nicht nach unten. Dieselbe Gr\xF6\xDFenordnung wie `max-h-[300px]` im\n Labs-Browser. */\n max-height: 19rem;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__raster {\n display: grid;\n /* Vier Spalten auf schmalen Displays \u2014 der gemeldete Screenshot zeigte eine\n einzige Spalte gro\xDFer Karten. Breiter wird automatisch dichter. */\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__karte {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-surface);\n text-align: left;\n cursor: pointer;\n}\n\n/* Das fokussierte Werk ist klar markiert \u2014 sonst wei\xDF niemand, wessen Galerie\n der Inspector unten zeigt. */\n.szenen-bildwahl__karte.is-fokus {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n/* \u2500\u2500 Die Kachel selbst \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Der Platz steht, bevor das Bild da ist \u2014 sonst springt das Raster, sobald\n die erste Vorschau eintrifft. */\n.szenen-bildkachel {\n display: block;\n width: 100%;\n aspect-ratio: 1;\n overflow: hidden;\n background: var(--color-bg-app);\n}\n\n.szenen-bildkachel img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.szenen-bildkachel__leer {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, var(--color-bg-app), var(--color-bg-surface));\n}\n\n/* R12.3: Eine fehlende Vorschau bleibt kachelgro\xDF. Vorher fiel die Karte auf\n ihren Prompttext zur\xFCck \u2014 und ein Prompt hat im echten Bestand mehrere\n hundert Zeichen. */\n.szenen-bildkachel__zeichen {\n font-size: 0.875rem;\n font-weight: 700;\n color: var(--color-text-secondary);\n opacity: 0.6;\n}\n\n/* Wie viele Varianten das Werk hat \u2014 klein und \xFCberlagernd, nie als\n dominanter Text. */\n.szenen-bildwahl__anzahl {\n position: absolute;\n top: 0.15rem;\n right: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n font-weight: 700;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Eine Zeile, dann Schluss. Der Prompt eines Werkes ist oft mehrere hundert\n Zeichen lang und w\xE4re als Prim\xE4rdarstellung genau die Textw\xFCste, gegen die\n der Review antritt. */\n.szenen-bildwahl__kacheltitel {\n display: block;\n padding: 0.15rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.3;\n color: var(--color-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Ebene 2: der Inspector \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__inspector {\n /* Ohne `min-width: 0` gewinnt der Inhalt: Der W\xE4hler ist Element eines\n Grids (`.szenen-form`), und dort ist `min-width: auto` die Vorgabe. Der\n Streifen unten ist rund 1000 px breit \u2014 gemessen am 2026-08-22 im echten\n Browser zog er die Auswahl von 374 px auf 1088 px auf und schob die\n ganze Seite waagerecht heraus, statt selbst zu scrollen. */\n min-width: 0;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n /* Sichtbar abgesetzt vom Browser: zwei Ebenen, nicht eine lange Liste. */\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__inspektorkopf {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bildwahl__werktitel {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--color-text-primary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bildwahl__zurueck {\n flex: 0 0 auto;\n font-size: 0.6875rem;\n padding: 0.15rem 0.5rem;\n}\n\n/* Der Streifen: waagerecht scrollend, feste kleine Kacheln \u2014 zw\xF6lf Varianten\n bleiben ein \xDCberblick statt zw\xF6lf Bildschirmseiten. */\n.szenen-bildwahl__streifen {\n /* Die Breite kommt vom Elter, nie vom Inhalt \u2014 sonst scrollt hier nichts. */\n max-width: 100%;\n display: flex;\n gap: var(--space-sm);\n margin: 0;\n padding: 0 0 0.25rem;\n list-style: none;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.szenen-bildwahl__streifen > li {\n flex: 0 0 auto;\n width: 5rem;\n}\n\n.szenen-bildwahl__variante {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-app);\n cursor: pointer;\n}\n\n.szenen-bildwahl__variante.is-gewaehlt {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n.szenen-bildwahl__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Das Gew\xE4hlte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n max-width: 100%;\n}\n\n/* Das gew\xE4hlte Bild wird best\xE4tigt, nicht nur benannt: eine kleine Vorschau\n neben dem Titel. */\n.szenen-bildwahl__gewaehlt .szenen-bildkachel {\n width: 2.25rem;\n flex: 0 0 auto;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__gewaehlt .szenen-bildwahl__kacheltitel {\n min-width: 0;\n max-width: 12rem;\n font-size: 0.75rem;\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n/* Das Eingangsbild benutzt seit C3 dieselbe Kachel wie W\xE4hler und Galerie.\n Sie ist von Haus aus so breit wie ihr Platz \u2014 in dieser Zeile bekommt sie\n deshalb eine feste Gr\xF6sse, sonst sch\xF6be sie die Metadaten heraus. */\n.szenen-bilder__eingangsliste .szenen-bildkachel {\n flex: 0 0 auto;\n width: 4rem;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batchkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-bilder__herkunft {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n/* Review-Befund \u2014 ein transienter Bildfehler ist wiederholbar, kein\n endg\xFCltiges \u201Efehlt". Dezent wie ein Angebot, nicht wie ein Fehlerzustand. */\n.szenen-bilder__retry {\n justify-self: start;\n padding: 0.15rem 0.5rem;\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n/* C4 \u2014 die Provenienz vollst\xE4ndig, aber sekund\xE4r. */\n.szenen-bilder__technik > summary {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-bilder__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n}\n\n/* C5 \u2014 der Verlauf verdichtet, seine Ausreisser nicht. */\n.szenen-bilder__verlauf > summary {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n cursor: pointer;\n}\n\n.szenen-bilder__verlauf[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__auffaellig {\n margin: 0;\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n.szenen-bilder__auftragskennung {\n flex-basis: 100%;\n color: var(--color-text-tertiary);\n font-size: 0.6875rem;\n}\n\n/* \u2500\u2500 C1/C2 \u2014 Galerie und grosse Ansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Das Raster w\xE4chst mit dem Platz: auf 390 px drei bis vier Kacheln je Reihe,\n auf dem Desktop entsprechend mehr. Vorher war jedes Bild eine Zeile aus\n Daumennagel plus vier Metadatenfeldern \u2014 vier Bilder ergaben vier Textzeilen\n und das Protokoll war die Hauptsache. */\n.szenen-bildgalerie {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));\n gap: var(--space-sm);\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildgalerie__kachel {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildgalerie__kachel:hover,\n.szenen-bildgalerie__kachel:focus-visible {\n border-color: var(--color-accent-teal, var(--color-text-primary));\n}\n\n.szenen-bildgalerie__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* Die grosse Ansicht liegt \xFCber allem und bringt ihren eigenen Grund mit \u2014\n `position: fixed` bezieht sich im Flow-Canvas auf dessen Rahmen, in React auf\n das Fenster; in beiden F\xE4llen genau das Gew\xFCnschte. */\n.szenen-bildviewer {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: grid;\n grid-template-rows: auto 1fr auto;\n gap: var(--space-sm);\n padding: var(--space-sm);\n /* Deckend, nicht get\xF6nt: Bei 0.92 schimmerte der Laufbereich durch und man\n las Prompttext quer \xFCber dem Bild \u2014 im Browser gemessen. */\n background: #000;\n}\n\n/* Titel, Z\xE4hlung, Schliessen \u2014 drei Spalten, damit ein langer Werktitel die\n Z\xE4hlung nicht in die n\xE4chste Zeile und \xFCber das Bild schiebt. */\n.szenen-bildviewer__kopf {\n display: grid;\n /* Titel nimmt den Rest; Zaehler, eine optionale Bildaktion (P6) und\n Schliessen stehen rechts \u2014 mit und ohne Aktion in einer Zeile. */\n grid-template-columns: minmax(0, 1fr);\n grid-auto-columns: auto;\n grid-auto-flow: column;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-bildviewer__titel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n}\n\n.szenen-bildviewer__zaehler {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n}\n\n.szenen-bildviewer__buehne {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 0;\n min-width: 0;\n}\n\n/* Der Rahmen nimmt den Platz, der zwischen den Bl\xE4tterkn\xF6pfen \xFCbrig ist \u2014\n `min-width: 0`, damit er auch wirklich schrumpft statt sie hinauszuschieben. */\n.szenen-bildviewer__rahmen {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n min-height: 0;\n height: 100%;\n}\n\n.szenen-bildviewer__bild {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n\n.szenen-bildviewer__leer {\n color: var(--color-text-secondary);\n text-align: center;\n}\n\n/* Die Bl\xE4tterkn\xF6pfe sind daumengross und liegen an den R\xE4ndern \u2014 auf einem\n Telefon ist der Rand erreichbar, die Bildmitte nicht. */\n.szenen-bildviewer__blaettern {\n flex: 0 0 auto;\n width: 2.75rem;\n height: 3.5rem;\n font-size: 1.75rem;\n line-height: 1;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildviewer__details {\n max-height: 8rem;\n overflow-y: auto;\n color: var(--color-text-secondary);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n/* D \u2014 die Aktionen stehen abgesetzt und standardm\xE4ssig kompakt: Sie sind\n Angebote, keine Ausk\xFCnfte. Vorher hielten beide Formulare dauerhaft offen und\n machten aus jedem Lauf zwei zus\xE4tzliche Bildschirmseiten. */\n.szenen-bilder__aktion {\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > summary {\n color: var(--color-text-primary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-bilder__aktion[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* Regelwerk-UX Schritt 16 \u2014 der ZIP-Sammelimport.\n *\n * \xA78: Der gemeldete Einsatz ist mobil. Deshalb **ein** Seedfeld statt einer\n * gestapelten Eingabe je Bild, und die Zuordnung Bild -> Seed als umbrechende\n * Zeile statt als Tabelle: Eine Tabelle waere auf 390 px abgeschnitten, und\n * abgeschnitten heisst hier, dass der Nutzer die Zuordnung nicht mehr pruefen\n * kann \u2014 genau die Pruefung, wegen der die Vorschau existiert. */\n.szenen-bilder__zip {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bilder__zipkopf {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipvorlagen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n}\n\n/* Eine laengere Liste bleibt scrollbar, statt die Sektion und damit den\n * Import-Knopf aus dem Blick zu schieben (\xA78, letzter Punkt). */\n.szenen-bilder__zipliste {\n max-height: 16rem;\n overflow-y: auto;\n}\n\n.szenen-bilder__zipliste > li {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-bilder__zipliste > li > span:first-child {\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipliste > li > span:last-child {\n color: var(--color-text-secondary);\n white-space: nowrap;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen von Objektfeldern (`prompt_render_settings`, `overrides`,\n `blender_render_settings`) \u2014 seit A1/A2 auf- und zuklappbar. Eine optionale\n Gruppe startet zu: Blender und `overrides` f\xFCllten auf einem 390-px-Display\n sonst mehrere Bildschirmseiten, obwohl die meisten Shots sie nie anfassen. */\n.szenen-detail__group {\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > summary {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__group[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n/* A2 \u2014 dass eine zugeklappte Gruppe schon Werte tr\xE4gt, muss man sehen, ohne\n sie zu \xF6ffnen. Sonst \xFCbersieht man eine gesetzte Blender-Ausgabe genau so\n lange, bis sie im Ergebnis auftaucht. */\n.szenen-detail__group-status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--color-text-tertiary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group[data-konfiguriert="ja"] > summary .szenen-detail__group-status {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-detail__group-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n/* A3 \u2014 die Kernaussage steht am Feld, die Begr\xFCndung dahinter. Nicht als\n Tooltip: Auf einem Telefon gibt es kein Hover, und was dort unerreichbar ist,\n ist gestrichen \u2014 nur ohne dass es jemand entschieden h\xE4tte. */\n.szenen-detail__warum > summary {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-detail__warum > small {\n display: block;\n padding-top: var(--space-xs);\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__fieldrow {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n margin-bottom: var(--space-md);\n}\n\n/* A4 \u2014 der technische Feldname bleibt lesbar, tritt aber hinter das fachliche\n Label zur\xFCck. */\n.szenen-detail__field-label {\n color: var(--color-text-primary);\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-bilder__modellwahl,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n/* \u201ENeues Modell hinzufuegen" im Importdialog \u2014 dieselben Abstaende wie jedes\n andere Formular dieser Ansicht, damit es kein Fremdkoerper wird. */\n.szenen-feld__zielmodell-neu {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-feld__zielmodell-neu-aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n\n/* Bereich `Prompts` \u2014 die herkunftsuebergreifende Sicht (P1-A).\n *\n * Die Eintraege selbst rendert `RundenEintrag` und tragen damit die\n * `szenen-runs__*`-Regeln. Hier stehen nur Rahmen und Kennzeichen; eine zweite\n * Laufdarstellung gibt es nicht, also braucht sie auch kein zweites Aussehen. */\n.szenen-prompts__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-prompts__heading {\n margin: 0;\n font-size: 1.05rem;\n margin-right: auto;\n}\n\n.szenen-view__fokus {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-prompts__fokus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-accent, #0d9488);\n border-radius: var(--radius-sm, 4px);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-prompts__hinweis {\n font-style: italic;\n}\n\n.szenen-prompts__ausgeblendet {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P8 \u2014 der Bereich `Prompts` als Bildraster\n ========================================================================== */\n\n/* Herkunfts-Chips: eine Zeile, die in sich scrollt \u2014 nie die Seite. */\n.szenen-prompts__chips {\n display: flex;\n flex-wrap: nowrap;\n gap: 0.375rem;\n min-width: 0;\n padding-bottom: 0.15rem;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view .szenen-prompts__chip {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.8rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__chip[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-prompts__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.375rem;\n min-width: 0;\n}\n\n.szenen-prompts__anzahl {\n flex: 1 1 8rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__umschalter {\n min-height: 2rem;\n padding: 0 0.65rem;\n font-size: 0.75rem;\n}\n\n.szenen-prompts__raster-bereich {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Der neueste Lauf \u2014 gross, mit Promptzeile und Kopierknopf. */\n.szenen-prompts__neuester {\n min-width: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__oeffnen {\n display: block;\n width: 100%;\n padding: 0;\n color: var(--color-text-primary);\n text-align: left;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-prompts__bild {\n position: relative;\n display: block;\n height: 17.5rem;\n overflow: hidden;\n}\n\n.szenen-prompts__neuester .szenen-galerie__status {\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.35rem 0.5rem;\n background: rgba(0, 0, 0, 0.55);\n border-radius: var(--radius-full);\n}\n\n.szenen-prompts__neuester .szenen-galerie__bildzahl {\n top: 0.75rem;\n right: 0.75rem;\n}\n\n.szenen-prompts__promptzeile {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.6rem 0.5rem 0.6rem 0.9rem;\n}\n\n.szenen-prompts__prompt {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-kopieren--symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n color: var(--color-text-primary);\n border-radius: var(--radius-lg);\n}\n\n.szenen-prompts__promptzeile .szenen-lauf__kopieren {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n}\n\n/* Gruppe aufeinanderfolgender Laeufe derselben Szene. */\n.szenen-prompts__gruppe {\n display: grid;\n gap: 0.6rem;\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf h4 {\n min-width: 0;\n margin: 0;\n font-size: 1rem;\n font-weight: 650;\n line-height: 1.3;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__gruppenkopf span {\n flex: none;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Zwei Spalten, Kacheln im Format 3:4. */\n.szenen-view .szenen-prompts__raster {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 0.625rem;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n@media (min-width: 761px) {\n .szenen-view .szenen-prompts__raster {\n grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));\n }\n}\n\n.szenen-prompts__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-prompts__kachel > button {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n aspect-ratio: 3 / 4;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__kachel.is-fokus > button,\n.szenen-view .szenen-prompts__neuester.is-fokus {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-prompts__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__text {\n color: #fff;\n}\n\n.szenen-prompts__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 1.25rem;\n font-weight: 700;\n line-height: 1.2;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__kachelrunde {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-prompts__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.3rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-prompts__statuspunkt {\n display: inline-block;\n flex: none;\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: 50%;\n}\n\n.szenen-prompts__statuspunkt[data-status="failed"] {\n background: var(--color-danger);\n}\n\n/* Eine Kachel ohne Bild nennt ihren Grund \u2014 oben, damit der Text unten frei bleibt. */\n.szenen-prompts__grund {\n display: grid;\n align-content: start;\n gap: 0.3rem;\n padding-top: 2.25rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-prompts__fehlertext {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 4;\n overflow-wrap: anywhere;\n}\n\n/* ==========================================================================\n ZIP-MODELLVORSCHLAG (modaler Best\xE4tigungsdialog)\n ========================================================================== */\n\n/* Wie die grosse Bildansicht: eigener Grund, `position: fixed`, damit der\n Dialog im Flow-Canvas und in React gleichermassen \xFCber allem liegt. */\n.szenen-zipmodell {\n position: fixed;\n inset: 0;\n z-index: 1100;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-md);\n background: rgba(0, 0, 0, 0.72);\n}\n\n.szenen-zipmodell__karte {\n display: grid;\n gap: var(--space-sm);\n width: min(34rem, 100%);\n max-height: 100%;\n overflow-y: auto;\n padding: var(--space-md);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-zipmodell__titel {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__treffer,\n.szenen-zipmodell__vertrauen,\n.szenen-zipmodell__fallback {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__vertrauen {\n color: var(--color-text-secondary);\n}\n\n/* Ein schwacher oder mehrdeutiger Treffer muss sich vom sicheren unterscheiden,\n sonst ist die Warnung nur ein weiterer Satz. */\n.szenen-zipmodell__warnung {\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n color: var(--color-text-primary);\n background: rgba(234, 179, 8, 0.14);\n border-left: 3px solid #eab308;\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen {\n display: grid;\n gap: 0.2rem;\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen > label {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-zipmodell__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n/* ==========================================================================\n MEHR LADEN \u2014 der gemeinsame Fuss jeder seitenweise geladenen Liste\n ========================================================================== */\n\n.szenen-mehr-laden {\n display: grid;\n gap: var(--space-xs);\n justify-items: start;\n padding: var(--space-xs) 0;\n}\n\n.szenen-mehr-laden__button {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.85rem;\n cursor: pointer;\n}\n\n.szenen-mehr-laden__button:disabled {\n cursor: progress;\n opacity: 0.6;\n}\n\n.szenen-mehr-laden__fehler {\n margin: 0;\n color: var(--color-danger, #f87171);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n PROMPTKARTE \u2014 Tags, Vorschau und Bildzahl\n (Kette `szenen-prompt-anzeige-bilder-tags`)\n\n Der Zuschnitt ist der der Library-Karte (`.library-item` + der absolut\n gesetzte Bildstreifen in `LibraryTab`): Textteil links, Deckbild rechts am\n Rand ueber die ganze Kartenhoehe, Bildzahl als Plakette darauf. Dieselben\n Werte (7rem Streifenbreite, linke Trennlinie, Plakette unten rechts), nur\n hier statt in Tailwind-Klassen \u2014 die Szenen-Ansicht teilt dieses Stylesheet\n byteweise mit Flow, und Flow hat kein Tailwind.\n ========================================================================== */\n\n.szenen-promptkarte {\n position: relative;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-sm);\n}\n\n/* Nur wo ein Bild liegt, wird Platz dafuer freigehalten. Ohne Bild nutzt der\n Textteil die ganze Breite \u2014 keine leere Spalte. */\n.szenen-promptkarte--mitbild .szenen-promptkarte__inhalt {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-promptkarte__bild {\n position: absolute;\n top: 0;\n right: 0;\n width: 7rem;\n height: 100%;\n /* Hoechstens so hoch wie breit \u2014 der Streifen bleibt eine Kachel.\n `height: 100%` allein band ihn an die **Kartenhoehe**, und die ist in der\n aufgeklappten Runde die Hoehe des ganzen Prompts: Das Deckbild sprang\n dann als mehrere hundert Pixel hoher, auf Streifenbreite beschnittener\n Balken an den rechten Rand. Geschlossen aendert die Grenze nichts \u2014 dort\n ist die Karte niedriger als 7rem. */\n max-height: 7rem;\n border-left: 1px solid var(--color-border);\n background: #000;\n}\n\n/* Die gemeinsame Kachel bringt `width: 100%` und `aspect-ratio: 1` mit \u2014 hier\n fuellt sie stattdessen den Streifen, genau wie das Library-Deckbild. */\n.szenen-promptkarte__bild .szenen-bildkachel {\n width: 100%;\n height: 100%;\n aspect-ratio: auto;\n}\n\n.szenen-promptkarte__bildzahl {\n position: absolute;\n right: 0.25rem;\n bottom: 0.25rem;\n padding: 0.1rem 0.35rem;\n border-radius: var(--radius-sm);\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 0.62rem;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n/* Ein Kasten je Karte, nicht zwei.\n *\n * `.szenen-view button` (master.css) gibt **jedem** Knopf der Ansicht Rahmen\n * und Hintergrund und schlaegt dabei `.szenen-runs__kopf` (eine Klasse gegen\n * Klasse plus Element). In der Laufhistorie ist das richtig: Dort ist der Kopf\n * der Eintrag. In der Promptkarte ist die Karte der Eintrag \u2014 ein zweiter\n * Kasten darin waere die doppelte Umrandung, die die Library nicht hat.\n * Der Hover braucht eine eigene Zeile, weil die Regel dort spezifischer ist. */\n.szenen-promptkarte .szenen-runs__kopf,\n.szenen-promptkarte .szenen-runs__kopf:hover:not(:disabled) {\n min-height: 0;\n padding: var(--space-xs) 0;\n background: transparent;\n border: none;\n}\n\n/* Dieselbe Karte in der Elementliste.\n *\n * Dort ist der Auswahlknopf die Karte \u2014 er traegt Rahmen, Hintergrund und die\n * Auswahlmarkierung. Der Bildstreifen liegt deshalb **darueber** statt darin:\n * Ein `<button>` nimmt nur Phrasing Content auf, ein Streifen-`div` darin\n * waere ungueltiges Markup. Damit der rechte Kartenrand trotzdem auswaehlbar\n * bleibt, laesst der Streifen Klicks durch. */\n.szenen-elementkarte {\n position: relative;\n}\n\n.szenen-elementkarte--mitbild > button {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-elementkarte > .szenen-promptkarte__bild {\n border-radius: 0 var(--radius-sm) var(--radius-sm) 0;\n}\n\n.szenen-promptkarte__bild--durchklickbar {\n pointer-events: none;\n}\n\n/* Null Bilder: die Zahl, keine Flaeche. */\n/* Die Tagliste bricht um. Auf einem Telefon ist das der Unterschied zwischen\n einer kompakten Karte und einer Zeile, die seitlich herauslaeuft. */\n.szenen-tagliste {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n align-items: center;\n margin: 0 0 var(--space-xs);\n padding: 0;\n list-style: none;\n}\n\n.szenen-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.05rem 0.4rem;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n font-size: 0.72rem;\n line-height: 1.5;\n white-space: nowrap;\n}\n\n/* Herkunft sichtbar, aber ohne zweite Bedeutungsebene: Ein Prompt-Tag steht\n voll, ein reiner Library-Tag zurueckgenommen. Die Karte soll schnell lesbar\n sein, nicht zwei Farbcodes lehren. */\n.szenen-tag[data-herkunft="library"] {\n border-style: dashed;\n opacity: 0.85;\n}\n\n.szenen-tag--rest {\n border-style: none;\n opacity: 0.7;\n}\n\n.szenen-tag__weg {\n border: none;\n background: none;\n padding: 0;\n color: var(--color-text-secondary, inherit);\n font-size: 0.85rem;\n line-height: 1;\n cursor: pointer;\n}\n\n.szenen-tag__weg:disabled {\n cursor: progress;\n opacity: 0.5;\n}\n\n.szenen-taggeber {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-xs);\n margin-bottom: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-taggeber__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: 0;\n}\n\n.szenen-taggeber__label {\n font-size: 0.72rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n opacity: 0.75;\n}\n\n.szenen-taggeber__leer,\n.szenen-taggeber__hinweis {\n font-size: 0.72rem;\n opacity: 0.75;\n}\n\n.szenen-taggeber input[type="text"] {\n flex: 1 1 8rem;\n min-width: 0;\n padding: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n BILDAUFTR\xC4GE \u2014 die bestandsweite Arbeitsqueue\n Kette `szenen-bildauftraege-arbeitsqueue`, Schritt 01.\n ========================================================================== */\n\n.szenen-bildauftraege {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bildauftraege__steuerung,\n.szenen-bildauftraege__filter,\n.szenen-bildauftraege__aktionen,\n.szenen-bildauftraege__nachladen,\n.szenen-bildauftraege__blaettern {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n}\n\n/* Der manuelle Refresh \u2014 Schritt 03 \xA72. Er steht oben und sichtbar, weil er\n die einzige Stelle ist, an der dieser Bereich nachlaedt: Es gibt keinen\n Timer mehr, den er ersetzen koennte. */\n.szenen-bildauftraege__nachladen {\n justify-content: flex-start;\n}\n\n.szenen-bildauftraege__nachladen span {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Die Blaetterleiste der Bildkontrolle \u2014 Schritt 03 \xA73.1. */\n.szenen-bildauftraege__blaettern {\n margin: 0;\n}\n\n/* \u201EWeitere Bilder" \u2014 seit Schritt 06 eine **Leiste in der Zeile**, kein\n aufklappbares Formular: Modell, Anzahl, Knopf nebeneinander. */\n.szenen-bildauftraege__weitere {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: var(--space-xs) 0 0;\n font-size: 0.85rem;\n}\n\n.szenen-bildauftraege__weitere label {\n color: var(--color-text-secondary);\n}\n\n/* Der Lauf-Zaehler: sichtbar, aber nicht im Weg (Schritt 06). */\n.szenen-bildauftraege__laufzaehler {\n padding: 0.05rem var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm, 4px);\n font-size: 0.8rem;\n font-variant-numeric: tabular-nums;\n}\n\n/* Die Vorschau steht oben und beh\xE4lt ihren Platz, auch solange noch kein Bild\n vorliegt \u2014 sie ist die Kontrollfl\xE4che des zweiten Browserfensters (\xA75). */\n.szenen-bildauftraege__letztes {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-bildauftraege__letztes h3 {\n margin: 0;\n font-size: 0.95rem;\n}\n\n.szenen-bildauftraege__letztes .szenen-bildkachel {\n width: min(100%, 22rem);\n height: auto;\n}\n\n.szenen-bildauftraege__lauf {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__lauf p {\n margin: 0.1rem 0;\n}\n\n.szenen-bildauftraege__liste {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildauftraege__zeile {\n display: grid;\n gap: 0.25rem;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__kopf,\n.szenen-bildauftraege__prompt {\n margin: 0;\n}\n\n.szenen-bildauftraege__meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.15rem var(--space-sm);\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bildauftraege__prompt {\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P4: Szene als Studio \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kopf mit Speichern, Hero mit Titelbild und Versions-Pill, die B\xFChne auf\n * einem Punktraster, das Element-Sheet von unten, der Prompt-Start als ein\n * Block, L\xE4ufe als Bildstreifen, Aufklapper unten. Kn\xF6pfe in der B\xFChne und im\n * Sheet setzen die Grundoptik von `.szenen-view button` gezielt zur\xFCck \u2014 daher\n * die zwei Klassen in diesen Selektoren. */\n.szenen-studio {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-studio__kopf {\n position: sticky;\n top: 0;\n z-index: 3;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n}\n\n.szenen-studio__kopf > .szenen-detail__ids {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-studio__ungespeichert {\n color: var(--color-warning);\n font-size: 0.8rem;\n font-weight: 600;\n}\n\n.szenen-view .szenen-studio__speichern {\n min-height: 2.25rem;\n padding: 0 1rem;\n color: var(--color-accent-teal, #2dd4bf);\n background: transparent;\n border-color: var(--color-accent-teal, #2dd4bf);\n border-radius: var(--radius-full);\n font-weight: 650;\n}\n\n.szenen-studio__hero {\n position: relative;\n min-height: 12rem;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-studio__hero--mitbild {\n min-height: 16rem;\n border-color: transparent;\n}\n\n.szenen-studio__titelbild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-studio__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0) 70%);\n}\n\n.szenen-studio__ohnebild {\n position: absolute;\n inset: 0;\n padding: var(--space-md);\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-surface);\n}\n\n.szenen-studio__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__bildfehler {\n margin: 0 0 var(--space-sm);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-studio__herotext {\n position: absolute;\n right: var(--space-md);\n bottom: var(--space-md);\n left: var(--space-md);\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-studio__herotext h3 {\n margin: 0;\n font-size: 1.5rem;\n line-height: 1.2;\n overflow-wrap: anywhere;\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__herotext {\n color: #fff;\n}\n\n.szenen-studio__herometa {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-studio__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n color: inherit;\n background: rgba(0, 0, 0, 0.55);\n border: 1px solid rgba(255, 255, 255, 0.25);\n border-radius: var(--radius-full);\n}\n\n.szenen-studio__hero:not(.szenen-studio__hero--mitbild) .szenen-studio__pill {\n background: var(--color-bg-elevated);\n border-color: var(--color-border);\n}\n\n/* Kette `szenen-design`, P6 \u2014 Titelbild: \u22EF-Menue im Hero, Hinweis, Zeile\n unter \u201ETechnisch" und die Aktion im Bildviewer. */\n.szenen-studio__heromenu {\n position: relative;\n display: inline-flex;\n}\n\n.szenen-view .szenen-studio__menuknopf {\n justify-content: center;\n min-width: 2.25rem;\n padding: 0 0.5rem;\n}\n\n.szenen-studio__menu {\n position: absolute;\n top: calc(100% + 0.25rem);\n left: 0;\n z-index: 5;\n display: grid;\n min-width: 12rem;\n padding: var(--space-xs, 0.25rem);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md, 0.5rem);\n}\n\n.szenen-studio__menu button {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n text-align: left;\n color: inherit;\n background: transparent;\n border: 0;\n}\n\n.szenen-studio__menu button:disabled {\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__titelbildhinweis {\n margin: 0;\n font-size: 0.8rem;\n color: var(--color-warning);\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__titelbildhinweis {\n color: #fde68a;\n}\n\n.szenen-studio__titelbildzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: var(--space-sm) 0;\n font-size: 0.875rem;\n}\n\n.szenen-studio__titelbildref {\n display: block;\n overflow-wrap: anywhere;\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bildviewer__aktion {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n}\n\n.szenen-bildviewer__titelbild {\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.8125rem;\n}\n\n.szenen-studio__komposition {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-studio__abschnittkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-studio__abschnittkopf h4 {\n margin: 0;\n}\n\n.szenen-studio__umschalter {\n display: inline-flex;\n padding: 3px;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button {\n min-height: 2rem;\n padding: 0 0.75rem;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-studio__aufklapper {\n display: grid;\n min-width: 0;\n}\n\n.szenen-studio__aufklapper > details {\n min-width: 0;\n border-top: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details:last-child {\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details > summary {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n cursor: pointer;\n}\n\n.szenen-studio__zusammenfassung {\n margin-left: auto;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Die B\xFChne */\n.szenen-buehne {\n position: relative;\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-buehne--leer {\n display: grid;\n place-items: center;\n aspect-ratio: auto;\n min-height: 8rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-buehne__linien {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n\n.szenen-buehne__linie {\n stroke: var(--color-text-tertiary);\n stroke-width: 1.5;\n}\n\n.szenen-buehne__linie--naehe {\n stroke-width: 1;\n stroke-dasharray: 3 4;\n}\n\n.szenen-buehne__linie--kontakt {\n stroke: var(--color-text-primary);\n stroke-width: 3;\n}\n\n.szenen-buehne__kegel-start {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0.35;\n}\n\n.szenen-buehne__kegel-ende {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0;\n}\n\n.szenen-view .szenen-buehne__node {\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.3rem;\n min-height: 0;\n max-width: 6rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n transform: translate(-50%, -50%);\n}\n\n.szenen-view .szenen-buehne__node:hover:not(:disabled) {\n background: transparent;\n}\n\n.szenen-buehne__symbol {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__symbol {\n width: 4rem;\n height: 4rem;\n border: 2px solid var(--color-text-primary);\n}\n\n.szenen-buehne__node--light .szenen-buehne__symbol {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-buehne__node[aria-pressed="true"] .szenen-buehne__symbol {\n box-shadow: 0 0 0 2px var(--color-accent-blue);\n}\n\n.szenen-buehne__name {\n max-width: 100%;\n padding: 0 0.25rem;\n overflow: hidden;\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__name {\n font-weight: 650;\n}\n\n.szenen-buehne__legende {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-md);\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-buehne__legende > span {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-buehne__legende-hinweis {\n margin-left: auto;\n}\n\n.szenen-buehne__muster {\n display: inline-block;\n width: 1.1rem;\n border-top: 1px dashed var(--color-text-tertiary);\n}\n\n.szenen-buehne__muster--kontakt {\n border-top: 3px solid var(--color-text-primary);\n}\n\n/* Das Element-Sheet */\n.szenen-sheet {\n position: fixed;\n inset: 0;\n z-index: 50;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.szenen-view .szenen-sheet__hintergrund {\n position: absolute;\n inset: 0;\n padding: 0;\n background: rgba(0, 0, 0, 0.6);\n border: none;\n border-radius: 0;\n cursor: default;\n}\n\n.szenen-sheet__flaeche {\n position: relative;\n display: grid;\n gap: var(--space-md);\n width: 100%;\n max-width: 40rem;\n max-height: 85vh;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n overflow-y: auto;\n box-sizing: border-box;\n background: var(--color-bg-surface);\n border-top: 1px solid var(--color-border);\n border-radius: 1.5rem 1.5rem 0 0;\n}\n\n.szenen-sheet__griff {\n justify-self: center;\n width: 2.5rem;\n height: 4px;\n background: var(--color-border);\n border-radius: 2px;\n}\n\n.szenen-sheet__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-sheet__symbol {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 3.5rem;\n height: 3.5rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-sheet__symbol--light {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-sheet__titel {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n}\n\n.szenen-sheet__titel strong {\n font-size: 1.25rem;\n}\n\n.szenen-sheet__titel code {\n overflow: hidden;\n color: var(--color-text-secondary);\n font-family: var(--font-mono);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n}\n\n.szenen-view .szenen-sheet__schliessen {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n margin-left: auto;\n padding: 0;\n border-radius: 50%;\n}\n\n.szenen-sheet__abschnitt {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-sheet__abschnitt h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-sheet__leer {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-sheet__beziehungen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__beziehungen li {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-sheet__beziehungsart {\n color: var(--color-text-secondary);\n}\n\n.szenen-sheet__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__bild {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-sheet__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-sheet__bildtext {\n display: grid;\n gap: 0.2rem;\n padding: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n.szenen-sheet__bildtext code {\n font-family: var(--font-mono);\n}\n\n.szenen-view .szenen-sheet__fertig {\n min-height: 3rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-weight: 700;\n}\n\n/* Der Prompt-Start als ein Block */\n.szenen-start {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-start__primaer {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1.05rem;\n font-weight: 700;\n}\n\n.szenen-start__kosten {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n text-align: center;\n}\n\n.szenen-start__manuell {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-start__zweit {\n min-height: 2.75rem;\n background: transparent;\n}\n\n.szenen-start__erklaerung > summary {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-start__erklaerung[open] .szenen-start__chevron {\n transform: rotate(90deg);\n}\n\n/* L\xE4ufe als Bildstreifen */\n.szenen-streifen {\n display: grid;\n gap: 0.35rem;\n padding: 0 var(--space-sm) var(--space-sm);\n}\n\n.szenen-streifen__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-streifen__bild {\n position: relative;\n aspect-ratio: 3 / 4;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n.szenen-streifen__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-streifen__fehler {\n display: block;\n padding: 0.25rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n}\n\n.szenen-streifen__mehr {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-streifen__anzahl {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n/* \xC4ltere Runden: kompakte Zeile mit \xFCberlappenden Miniaturen. */\n.szenen-streifen--zeile {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bilder {\n display: flex;\n gap: 0;\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild {\n width: 2.1rem;\n height: 2.75rem;\n aspect-ratio: auto;\n border: 2px solid var(--color-bg-surface);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild + .szenen-streifen__bild {\n margin-left: -0.75rem;\n}\n\n.szenen-runs__eintrag--karte {\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n/* Szenenst\xE4nde enthalten mehrere Runden derselben eingefrorenen Szene (#538). */\n.szenen-runs__stand > h5 {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-runs__stand-laeufe {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-runs__stand-laeufe > li {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P5 \u2014 der Prompt-Lauf als Ergebnisgalerie\n ========================================================================== */\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-chip,\n.szenen-view .szenen-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n min-height: 1.75rem;\n padding: 0 0.65rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-chip--knopf {\n min-height: 2.25rem;\n color: var(--color-text-primary);\n cursor: pointer;\n}\n\n.szenen-chip--library,\n.szenen-view .szenen-chip--library {\n color: var(--color-accent-teal, #2dd4bf);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n/* \u2500\u2500 Navigation der Laufansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__nav {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n scroll-margin-top: var(--space-md);\n}\n\n.szenen-view .szenen-lauf__zurueck {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n min-height: 2.75rem;\n padding: 0 0.6rem 0 0.25rem;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__blaettern {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.2rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-lauf__blaettern button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n min-height: 2.5rem;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n/* \u2500\u2500 Kopf: Runde, Status, Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-laufinhalt {\n gap: var(--space-md);\n}\n\n.szenen-lauf__kopf {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-lauf__szene {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__titelzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__runde {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.6rem;\n font-weight: 700;\n line-height: 1.15;\n}\n\n.szenen-lauf__status {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 1.6rem;\n padding: 0 0.6rem;\n border: 1px solid currentColor;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-lauf__status::before {\n content: "";\n width: 0.4rem;\n height: 0.4rem;\n border-radius: 50%;\n background: currentColor;\n}\n\n.szenen-lauf__status[data-status="succeeded"] { color: var(--color-success); }\n.szenen-lauf__status[data-status="failed"] { color: var(--color-danger); }\n\n.szenen-lauf__chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.4rem;\n min-width: 0;\n}\n\n.szenen-lauf__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Galerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf .szenen-bilder__ausgang {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-lauf {\n gap: var(--space-md);\n margin-top: 0;\n}\n\n.szenen-lauf .szenen-bilder__batch {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-bildgalerie--ergebnis {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n overflow: hidden;\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--einzeln {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildgalerie__kachel {\n border: none;\n border-radius: 0;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildgalerie__kachel {\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildkachel {\n aspect-ratio: 3 / 4;\n}\n\n/* Ein einzelnes Ergebnisbild im echten Format zeigen \u2014 wie das Gemini-Preview:\n zentriert, ganz sichtbar, nichts abgeschnitten (vorher 3:4 mit cover). */\n.szenen-bildgalerie--einzeln .szenen-bildkachel {\n aspect-ratio: auto;\n background: none;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildkachel:not(:has(img)) {\n aspect-ratio: 4 / 3;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildkachel img {\n width: auto;\n max-width: 100%;\n height: auto;\n max-height: 28rem;\n margin-inline: auto;\n object-fit: contain;\n border: 1px solid var(--color-border-hover);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie__alle-text {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.1rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n font-size: 0.75rem;\n}\n\n.szenen-bildgalerie__alle-text strong {\n font-size: 1.25rem;\n}\n\n/* P5-Akzeptanz: Eine leere Kachel nennt ihren Grund \u2014 lesbar, nicht nur im\n Tooltip. */\n.szenen-bildkachel__grund {\n display: -webkit-box;\n max-width: 90%;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.3;\n text-align: center;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n/* \u2500\u2500 Karten: Prompt, Tags \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__karte {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-lauf__kartenkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__label {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__legende {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-lauf__kopieren {\n display: inline-flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__prompttext {\n margin: 0;\n color: var(--color-text-primary);\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n/* Drei Zeilen Vorschau \u2014 der volle Text bleibt im Dokument (Kopieren,\n Markieren), gek\xFCrzt wird nur die Darstellung. */\n.szenen-lauf__prompttext--zu {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n.szenen-view .szenen-lauf__ganz {\n justify-self: start;\n min-height: 2.25rem;\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-primary));\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__negativ {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-lauf__negativ[hidden] {\n display: none;\n}\n\n.szenen-lauf__negativ p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.szenen-lauf__karte .szenen-taggeber {\n margin: 0;\n}\n\n.szenen-tagliste .szenen-tag__neu {\n min-height: 2rem;\n}\n\n/* \u2500\u2500 \u201ENeue Bilder" (Serverauftrag des Hosts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-neuebilder {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg, var(--radius-md));\n}\n\n.szenen-neuebilder__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-neuebilder__kopf h4 {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.05rem;\n}\n\n.szenen-neuebilder__symbol {\n color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-neuebilder__weg {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-neuebilder__felder {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-wahlfeld {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding: 0.4rem 0.6rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-wahlfeld__label {\n color: var(--color-text-secondary);\n font-size: 0.68rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-wahlfeld select {\n min-height: 1.75rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n font-weight: 600;\n}\n\n.szenen-umschalter {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n padding: 3px;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-umschalter button {\n min-height: 2.5rem;\n background: transparent;\n border: none;\n}\n\n.szenen-view .szenen-umschalter button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n font-weight: 600;\n}\n\n.szenen-view .szenen-neuebilder__start {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1rem;\n font-weight: 700;\n}\n\n.szenen-view .szenen-neuebilder__start:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n opacity: 0.9;\n}\n\n.szenen-neuebilder__laedt,\n.szenen-neuebilder__fehler {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-neuebilder__laedt { color: var(--color-text-secondary); }\n\n/* Referenzbild eines Laufs (#569-Folge): eigener Bereich \xFCber den Ergebnissen. */\n.szenen-bilder__referenz {\n display: flex;\n gap: var(--space-md);\n align-items: center;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-md);\n}\n\n.szenen-bilder__referenzbild {\n flex: none;\n width: 9rem;\n}\n\n.szenen-bilder__referenzbild img {\n display: block;\n width: 100%;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__referenzleer {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n font-size: 0.8rem;\n}\n\n.szenen-bilder__referenztext {\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-bilder__referenztext strong {\n color: var(--color-text-primary);\n}\n\n/* Referenzbild und Prompt am einzelnen Bildauftrag. */\n.szenen-zeitleiste__referenz {\n display: flex;\n gap: var(--space-sm);\n align-items: center;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-zeitleiste__referenz img,\n.szenen-zeitleiste__referenz-leer {\n display: block;\n width: 4.5rem;\n aspect-ratio: 4 / 3;\n object-fit: cover;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-zeitleiste__prompt {\n white-space: pre-wrap;\n user-select: text;\n}\n\n/* Das mitgegebene Kamera-Preview (#569-Folge) \u2014 sichtbar, bevor bestellt wird. */\n.szenen-neuebilder__referenz {\n margin: 0;\n padding: 0.35rem 0.6rem;\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-left: 2px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n font-size: 0.82rem;\n}\n.szenen-neuebilder__fehler { color: var(--color-danger); }\n\n.szenen-neuebilder__warnung > summary {\n display: flex;\n align-items: flex-start;\n gap: var(--space-sm);\n color: var(--color-warning);\n font-size: 0.85rem;\n line-height: 1.45;\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-neuebilder__warnung > summary::-webkit-details-marker { display: none; }\n\n.szenen-neuebilder__warnung > p,\n.szenen-neuebilder__zuordnung ul {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n line-height: 1.5;\n}\n\n.szenen-neuebilder__zuordnung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-neuebilder__zuordnung ul {\n padding-left: 1.1rem;\n}\n\n/* \u2500\u2500 Aufklapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-aufklapper {\n display: grid;\n min-width: 0;\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-aufklapper__eintrag,\n.szenen-aufklapper .szenen-bilder__aktion {\n min-width: 0;\n padding: 0;\n border: none;\n border-top: 1px solid var(--color-border);\n border-radius: 0;\n}\n\n.szenen-aufklapper__eintrag > summary,\n.szenen-aufklapper .szenen-bilder__aktion > summary {\n list-style: none;\n cursor: pointer;\n}\n\n.szenen-aufklapper__eintrag > summary::-webkit-details-marker { display: none; }\n\n.szenen-aufklapper .szenen-bilder__aktion[open] > summary {\n margin-bottom: 0;\n}\n\n.szenen-aufklapper__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: 0 var(--space-xs);\n color: var(--color-text-primary);\n font-weight: 400;\n}\n\n.szenen-aufklapper__pfeil {\n flex: none;\n transition: transform 0.15s ease;\n}\n\ndetails[open] > summary .szenen-aufklapper__pfeil {\n transform: rotate(90deg);\n}\n\n.szenen-aufklapper__titel {\n min-width: 0;\n}\n\n.szenen-aufklapper__meta {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-aufklapper__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: 0 var(--space-xs) var(--space-md) 2rem;\n}\n\n@media (max-width: 760px) {\n .szenen-aufklapper__inhalt {\n padding-left: var(--space-xs);\n }\n}\n\n.szenen-aufklapper__inhalt > p {\n margin: 0;\n}\n\n/* \u2500\u2500 Zeitleiste der Bildauftr\xE4ge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-zeitleiste {\n display: grid;\n gap: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-zeitleiste__schritt {\n position: relative;\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-md);\n}\n\n/* Die Linie zur n\xE4chsten Zeile. */\n.szenen-zeitleiste__schritt:not(:last-child)::before {\n content: "";\n position: absolute;\n top: 2.1rem;\n bottom: 0;\n left: calc(1rem - 1px);\n width: 2px;\n background: var(--color-border);\n}\n\n.szenen-zeitleiste__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: 1px solid var(--color-border);\n border-radius: 50%;\n background: var(--color-bg-elevated);\n color: var(--color-text-secondary);\n font-weight: 700;\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fertig"] {\n color: var(--color-success);\n border-color: var(--color-success);\n background: var(--color-accent-green-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fehlgeschlagen"] {\n color: var(--color-danger);\n border-color: var(--color-danger);\n background: var(--color-accent-red-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="teilweise"] {\n color: var(--color-warning);\n border-color: var(--color-warning);\n}\n\n.szenen-zeitleiste__inhalt {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding-top: 0.3rem;\n}\n\n.szenen-zeitleiste__titel {\n color: var(--color-text-primary);\n font-size: 0.9rem;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis,\n.szenen-zeitleiste__zusatz {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis[data-zustand="fehlgeschlagen"] { color: var(--color-danger); }\n.szenen-zeitleiste__ergebnis[data-zustand="teilweise"] { color: var(--color-warning); }\n\n.szenen-zeitleiste__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin-top: var(--space-xs);\n}\n\n.szenen-zeitleiste__meldung > summary {\n min-height: 2rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n line-height: 2rem;\n cursor: pointer;\n}\n\n.szenen-zeitleiste__meldung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__meldung code {\n display: block;\n margin-top: var(--space-xs);\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-family: var(--font-mono);\n font-size: 0.72rem;\n overflow-wrap: anywhere;\n}\n\n/* \u2500\u2500 Annahmen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-annahmen {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-annahmen__zeile {\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-annahmen__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: 50%;\n}\n\n.szenen-annahmen__text {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n font-size: 0.85rem;\n line-height: 1.45;\n overflow-wrap: anywhere;\n}\n\n.szenen-annahmen__art {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-annahmen__text details > summary,\n.szenen-lauf__erlaeuterung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-annahmen__text details p,\n.szenen-lauf__erlaeuterung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n.szenen-lauf__handeingabe h5 {\n margin: 0 0 var(--space-xs);\n}\n\n.szenen-lauf__handeingabe p {\n margin: 0;\n font-size: 0.85rem;\n}\n\n/* Kette `szenen-design`, P7 (#533) \u2014 die Szene aus Bausteinen. Felder als\n Karten, Bausteine im Feld als Chips; die Leiste ist das vorhandene\n Bottom-Sheet mit Bildkacheln. Bedient wird durch Antippen, nicht Ziehen. */\n.szenen-bausteinfelder {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-bausteinfelder__liste {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinfeld {\n display: grid;\n align-content: start;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bausteinfeld__kopf {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-bausteinfeld__leer,\n.szenen-bausteinfeld__gesperrt {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bausteinfeld__refs {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinchip {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-view .szenen-bausteinchip__name {\n min-height: 2.25rem;\n max-width: 100%;\n padding: 0 0.75rem;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinchip__aktionen {\n display: inline-flex;\n gap: var(--space-xs);\n}\n\n.szenen-view .szenen-bausteinchip__aktionen button {\n min-width: 2.25rem;\n min-height: 2.25rem;\n padding: 0 0.6rem;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-bausteinfeld__plus {\n display: inline-flex;\n align-items: center;\n justify-self: start;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: transparent;\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-bausteinfelder__weitere {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-bausteinfelder__weitere h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-bausteinfelder__weitere ul {\n display: grid;\n gap: 0.25rem;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: 0.85rem;\n}\n\n.szenen-bausteinfelder__ort {\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bausteinleiste__suche {\n min-height: 2.75rem;\n width: 100%;\n box-sizing: border-box;\n}\n\n.szenen-bausteinleiste {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-view .szenen-bausteinkachel {\n display: grid;\n gap: 0.25rem;\n width: 100%;\n padding: 0;\n overflow: hidden;\n text-align: left;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-bausteinkachel[aria-pressed="true"] {\n border-color: var(--color-text-primary);\n}\n\n.szenen-view .szenen-bausteinkachel:disabled {\n cursor: default;\n opacity: 0.7;\n}\n\n.szenen-bausteinkachel__name {\n display: flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0 0.4rem;\n overflow: hidden;\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinkachel__status,\n.szenen-bausteinkachel__grund {\n padding: 0 0.4rem 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n@media (min-width: 761px) {\n .szenen-bausteinleiste {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n }\n}\n/* MCP_STAGE_START: shared stage styles embedded in the gateway resource. */\n/* Issue #569: mobile stage controls and exact camera letterbox. */\n/* 3D-B\xFChne (#569): Ansicht zuerst, Werte als Karten darunter. */\n.szenen-3d {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-3d__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-3d__kopf h4 {\n margin: 0 auto 0 0;\n}\n\n/* Als Ansicht \u201E3D\u201C der Komposition: kein zweiter Rahmen im Abschnitt. */\n.szenen-3d--eingebettet {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-3d__kopf {\n flex-wrap: wrap;\n}\n\n.szenen-3d .szenen-3d__aufbau {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-width: 0;\n margin-right: auto;\n}\n\n.szenen-3d .szenen-3d__aufbau select {\n width: auto;\n min-width: 0;\n max-width: 100%;\n}\n\n.szenen-3d__stand {\n min-width: 0;\n margin-right: auto;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-3d__sync {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__sync::before {\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: var(--radius-full);\n content: "";\n}\n\n.szenen-3d__sync[data-state="speichert"]::before {\n background: var(--color-warning);\n}\n\n.szenen-3d__sync[data-state="ansicht"]::before {\n background: var(--color-accent-blue);\n}\n\n.szenen-3d__meldung,\n.szenen-3d__fehler {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-elevated);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-3d__fehler {\n border-left-color: var(--color-danger);\n}\n\n.szenen-3d__oeffnen {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-3d label {\n display: grid;\n gap: 0.3rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__leiste {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-3d__katalog {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-3d__katalog > span {\n margin-right: 0.15rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-3d__katalog button,\n.szenen-view .szenen-3d__elemente button {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2rem;\n padding: 0 0.7rem;\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-3d__katalog i,\n.szenen-3d__elemente i {\n flex: none;\n width: 0.6rem;\n height: 0.6rem;\n border-radius: 2px;\n}\n\n.szenen-view .szenen-3d__elemente button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-text-primary);\n}\n\n/* Viewport: feste H\xF6he f\xFCr Drauf- und Seitenansicht; die Kameraansicht wird\n * darin auf das gespeicherte Kameraformat eingepasst (Letterbox). */\n.szenen-3d__viewport {\n position: relative;\n display: grid;\n place-items: center;\n /* Dieselbe Gr\xF6\xDFe wie die 2D-B\xFChne (`.szenen-buehne`): Beim Wechsel springt nichts. */\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background: #0d0f12;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n container-type: size;\n outline: none;\n}\n\n.szenen-3d__viewport--laden {\n background:\n linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px) 0 0 / 32px 32px,\n linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px) 0 0 / 32px 32px,\n #0d0f12;\n}\n\n.szenen-3d__geruest {\n display: contents;\n}\n\n.szenen-3d__geruest button {\n pointer-events: none;\n}\n\n.szenen-3d__viewport:focus-visible {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-3d__surface {\n position: relative;\n width: 100%;\n height: 100%;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.szenen-3d__viewport[data-view="camera"] {\n background: #050607;\n}\n\n.szenen-3d__viewport[data-view="camera"] .szenen-3d__surface {\n width: min(100cqw, calc(100cqh * var(--seitenverhaeltnis)));\n height: min(100cqh, calc(100cqw / var(--seitenverhaeltnis)));\n}\n\n.szenen-3d__hud {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #d4d4d4;\n font-size: 0.78rem;\n font-variant-numeric: tabular-nums;\n pointer-events: none;\n}\n\n.szenen-3d__hud--werkzeuge {\n top: 0.6rem;\n right: 0.6rem;\n gap: 0.25rem;\n pointer-events: auto;\n}\n\n.szenen-view .szenen-3d__hud--werkzeuge button {\n min-width: 2rem;\n min-height: 2rem;\n padding: 0 0.6rem;\n color: #e5e5e5;\n background: rgba(23, 23, 23, 0.85);\n border-color: rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(4px);\n}\n\n.szenen-3d__hud--kamera {\n top: 0.6rem;\n left: 0.6rem;\n padding: 0.2rem 0.55rem;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n}\n\n.szenen-3d__hud--info {\n bottom: 0.6rem;\n left: 0.6rem;\n max-width: calc(100% - 7rem);\n padding: 0.25rem 0.6rem;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.szenen-3d__hud--info strong {\n color: #ffffff;\n font-weight: 600;\n}\n\n.szenen-3d__hud i {\n font-style: normal;\n font-weight: 700;\n}\n\n.szenen-3d__hud--achsen {\n right: 0.75rem;\n bottom: 0.7rem;\n gap: 0.6rem;\n font-weight: 700;\n}\n\n.szenen-3d__labels {\n position: absolute;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.szenen-3d__label {\n position: absolute;\n padding: 0.05rem 0.4rem;\n color: #f5f5f5;\n background: rgba(10, 10, 10, 0.72);\n border-left: 2px solid var(--farbe, #9bafbc);\n border-radius: 3px;\n font: 500 0.72rem/1.4 var(--font-sans);\n white-space: nowrap;\n transform: translate(-50%, 6px);\n}\n\n.szenen-3d__label--side {\n transform: translate(-50%, calc(-100% - 6px));\n}\n\n.szenen-3d__label--kamera {\n color: #bfdbfe;\n border-left-color: #60a5fa;\n transform: translate(14px, -50%);\n}\n\n.szenen-3d__label--kamera.is-links {\n transform: translate(calc(-100% - 14px), -50%);\n}\n\n.szenen-3d__label.is-selected {\n color: #000000;\n background: #ffffff;\n}\n\n.szenen-3d__inspektor {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-3d__karte {\n display: grid;\n align-content: start;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-3d__karte h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.72rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-3d__elemente {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem;\n}\n\n.szenen-3d__werte {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.4rem;\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.szenen-3d__werte legend {\n margin-bottom: 0.4rem;\n padding: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-3d__werte legend span {\n margin-left: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n font-weight: 400;\n}\n\n.szenen-3d__zeilenkopf {\n grid-column: 1 / -1;\n margin-top: 0.2rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__werte > button {\n grid-column: 1 / -1;\n}\n\n/* Markerfarbe eines Proxys (#587): W\xE4hler, Hexfeld und R\xFCcksetzen in einer\n Zeile; auf schmalem Touch-Viewport bricht sie um, ohne Controls zu verdecken. */\n.szenen-3d__farbe {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-view .szenen-3d__farbe input[type="color"] {\n flex: 0 0 auto;\n width: 2.75rem;\n min-height: 2.75rem;\n padding: 0.15rem;\n cursor: pointer;\n}\n\n.szenen-view .szenen-3d__farbe input[type="text"] {\n flex: 1 1 6.5rem;\n min-width: 6.5rem;\n min-height: 2.75rem;\n font-family: var(--font-mono, monospace);\n text-transform: lowercase;\n}\n\n.szenen-view .szenen-3d__farbe button {\n flex: 0 0 auto;\n min-height: 2.75rem;\n}\n\n.szenen-3d__entfernen {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-3d__entfernen > span {\n flex: 1 1 100%;\n color: var(--color-text-primary);\n font-size: 0.85rem;\n}\n\n.szenen-view .szenen-3d__entfernen button {\n min-height: 2.75rem;\n}\n\n.szenen-view .szenen-3d__gefahr {\n color: #fff;\n background: var(--color-danger);\n border-color: var(--color-danger);\n}\n\n.szenen-3d__farbe-auto {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__farbe-hinweis {\n grid-column: 1 / -1;\n margin: 0;\n color: var(--color-warning, #eab308);\n font-size: 0.78rem;\n}\n\n.szenen-3d .szenen-3d__feld {\n position: relative;\n display: block;\n}\n\n.szenen-3d__achse {\n position: absolute;\n top: 50%;\n left: 0.55rem;\n font-size: 0.72rem;\n font-weight: 700;\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n.szenen-3d__achse--x { color: #f87171; }\n.szenen-3d__achse--y { color: #4ade80; }\n.szenen-3d__achse--z { color: #60a5fa; }\n\n.szenen-view .szenen-3d__feld input {\n padding-left: 1.6rem;\n font-variant-numeric: tabular-nums;\n}\n\n.szenen-3d__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-3d__abschluss {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-3d__primaer {\n min-height: 2.75rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view .szenen-3d__primaer:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-primary-hover);\n}\n\n.szenen-view .szenen-3d__nebenaktion {\n justify-self: start;\n min-height: 2rem;\n padding: 0;\n background: none;\n border: none;\n font-size: 0.82rem;\n text-decoration: underline;\n}\n\n/* Hinweise passend zum Eingabeger\xE4t; ohne Angabe gilt die Maus-Variante. */\n.szenen-3d__nur-touch {\n display: none;\n}\n\n@media (hover: none) and (pointer: coarse) {\n .szenen-3d__nur-maus {\n display: none;\n }\n\n .szenen-3d__nur-touch {\n display: inline;\n }\n\n /* Fingergerechte Ziele (44 px) f\xFCr Ansichtssteuerung, Katalog und Elemente. */\n .szenen-view .szenen-3d__hud--werkzeuge button,\n .szenen-view .szenen-3d__katalog button,\n .szenen-view .szenen-3d__elemente button,\n .szenen-view .szenen-3d .szenen-studio__umschalter button {\n min-width: 2.75rem;\n min-height: 2.75rem;\n }\n}\n\n@media (max-width: 760px) {\n .szenen-3d {\n gap: var(--space-sm);\n padding: var(--space-sm);\n }\n\n .szenen-3d__leiste {\n display: grid;\n }\n\n .szenen-3d .szenen-studio__umschalter {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n }\n\n /* Katalog als eine Zeile, die in sich scrollt, statt die Ansicht nach unten zu schieben. */\n .szenen-3d__katalog {\n flex-wrap: nowrap;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .szenen-3d__katalog > * {\n flex: none;\n }\n\n .szenen-3d__viewport {\n aspect-ratio: 358 / 330;\n margin: 0 calc(-1 * var(--space-sm));\n border-right: none;\n border-left: none;\n border-radius: 0;\n }\n\n .szenen-3d__hud--info {\n max-width: calc(100% - 1.2rem);\n bottom: 2.4rem;\n }\n\n .szenen-3d__hud--achsen {\n bottom: 0.8rem;\n left: 0.75rem;\n right: auto;\n }\n}\n\n/* One DOM canvas, no nested React renderer. */\n.szenen-3d__canvas { display: block; width: 100%; height: 100%; }\n\n/* Prompt choices before the 3D run; mobile buttons wrap within each category. */\n.szenen-3d__prompt details { margin-block: .65rem; }\n.szenen-3d__prompt summary { cursor: pointer; font-weight: 600; }\n.szenen-3d__prompt fieldset { border: 0; padding: .6rem 0; min-width: 0; }\n.szenen-3d__prompt legend { color: var(--color-text-secondary); font-size: .85rem; }\n.szenen-3d__prompt textarea { min-height: 6rem; width: 100%; box-sizing: border-box; }\n.szenen-3d__referenz { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .9rem; }\n\n/* Das Preview in seinem echten Format (z. B. 4:3) \u2014 keine F\xFCllfl\xE4che in Hintergrundfarbe, die ein Querformat vort\xE4uscht. */\n.szenen-3d__gemini img { display: block; width: auto; max-width: 100%; height: auto; max-height: 28rem; margin-inline: auto; border: 1px solid var(--color-border-hover); border-radius: .4rem; }\n.szenen-3d__gemini pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; font-size: .8rem; }\n.szenen-3d__gemini ul { list-style: none; padding: 0; }\n.szenen-3d__gemini li { margin-block: .6rem; overflow-wrap: anywhere; }\n.szenen-3d__gemini li i { display: inline-block; width: .9rem; height: .9rem; margin-right: .4rem; border-radius: .15rem; }\n\n/* Desktop: 2D- und 3D-B\xFChne auf 60 % der Breite, gleich gro\xDF und zentriert.\n Unter 761 px bleibt die volle Breite (Touch, schmale Spalte). Steht am\n Dateiende, damit es die Grundregeln beider B\xFChnen \xFCberschreibt. */\n@media (min-width: 761px) {\n .szenen-buehne,\n .szenen-3d__viewport {\n width: 60%;\n justify-self: center;\n margin-inline: auto;\n }\n}\n\n/* One mobile object sheet and a separate ring gesture on the selected object. */\n.szenen-3d__drehring { position:absolute; overflow:visible; pointer-events:none; z-index:12; }\n.szenen-3d__drehring circle { pointer-events:stroke; cursor:grab; touch-action:none; }\n.szenen-3d__drehring circle:focus-visible { stroke:#ffffff; outline:none; }\n.szenen-3d__blatt-schliessen { display:none; }\n.szenen-3d__objekt-aktionen, .szenen-3d__pose { display:flex; flex-wrap:wrap; gap:.4rem; grid-column:1/-1; }\n.szenen-3d__morph { display:flex; align-items:center; gap:.6rem; grid-column:1/-1; }\n.szenen-3d__morph input { flex:1; min-width:0; min-height:44px; }\n.szenen-3d__pose button[aria-pressed="true"] { border-color:var(--color-accent-blue); }\n@media (max-width:760px) {\n .szenen-3d__objektblatt { position:fixed; left:0; right:0; bottom:0; z-index:50; max-height:42dvh; overflow:auto; overscroll-behavior:contain; background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border); border-radius:18px 18px 0 0; padding:.7rem 1rem calc(.8rem + env(safe-area-inset-bottom)); box-shadow:0 -8px 30px #0008; }\n .szenen-3d__blatt-schliessen { display:block; margin-left:auto; min-height:44px; }\n .szenen-3d__objektblatt button, .szenen-3d__objektblatt input, .szenen-3d__objektblatt select { min-height:44px; }\n}\n\n.szenen-3d__werte { min-width:0; }\n.szenen-3d__objektblatt input, .szenen-3d__objektblatt select { min-width:0; max-width:100%; }\n\n@media (max-width:760px) { .szenen-3d__objektblatt { width:100vw; max-width:100vw; box-sizing:border-box; } }\n\n.szenen-3d__karte, .szenen-3d__abschluss { grid-template-columns:minmax(0,1fr); }\n\n\n.szenen-3d { overflow-x:clip; }\n\n/* Display options (walls, fullscreen) and the fullscreen stage (#582 follow-up).\n Fullscreen: the stage frame covers the screen; sheets lie over the 3D view. */\n.szenen-3d__ansichtsoptionen { display:flex; flex-wrap:wrap; gap:.4rem; }\n.szenen-view .szenen-3d__ansichtsoptionen button[aria-pressed="true"] { border-color:var(--color-accent-blue); }\n.szenen-3d__buehne { display:grid; gap:var(--space-sm); min-width:0; }\n.szenen-3d__buehne.is-vollbild { position:fixed; inset:0; z-index:1000; display:flex; flex-direction:column; gap:0; background:#0d0f12;\n padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left); }\n/* Two rows, both always visible: the four views, then walls/camera/exit. */\n.szenen-3d__buehne.is-vollbild .szenen-3d__leiste { display:grid; flex:none; gap:.35rem; padding:.4rem; }\n.szenen-3d__buehne.is-vollbild .szenen-studio__umschalter { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); }\n.szenen-3d__buehne.is-vollbild .szenen-studio__umschalter button { min-width:0; padding-inline:.3rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__ansichtsoptionen { display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr); }\n.szenen-3d__buehne.is-vollbild .szenen-3d__katalog { display:none; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__viewport { flex:1; min-height:0; width:100%; aspect-ratio:auto; margin:0; border:0; border-radius:0; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt { position:absolute; left:0; right:0; bottom:0; z-index:20; width:auto; max-width:none; max-height:45%;\n overflow:auto; overscroll-behavior:contain; box-sizing:border-box; background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border);\n border-radius:18px 18px 0 0; padding:.7rem 1rem calc(.8rem + env(safe-area-inset-bottom)); box-shadow:0 -8px 30px #0008; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__blatt-schliessen { display:block; margin-left:auto; min-height:44px; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt button,\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt input,\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt select { min-height:44px; }\n.szenen-3d__kamerablatt label { display:grid; gap:.25rem; grid-column:1/-1; }\n@media (min-width:761px) {\n .szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt { left:auto; top:0; width:min(26rem,40%); max-height:none; border-radius:18px 0 0 18px; }\n}\n\n/* Visibility list and sheet switch (editor display only, never saved).\n "Objektblatt" only matters where the sheet covers the stage: fullscreen and phone width. */\n.szenen-3d__sichtbar { position:relative; min-width:0; }\n.szenen-3d__sichtbar > summary { display:flex; align-items:center; justify-content:center; box-sizing:border-box; height:100%; min-height:2.25rem;\n padding:.45rem .75rem; color:var(--color-text-secondary); background:var(--color-bg-elevated); border:1px solid var(--color-border);\n border-radius:var(--radius-sm); cursor:pointer; list-style:none; text-align:center; }\n.szenen-3d__sichtbar > summary::-webkit-details-marker { display:none; }\n.szenen-3d__sichtbar[open] > summary { border-color:var(--color-accent-blue); color:var(--color-text-primary); }\n.szenen-3d__sichtbar-liste { position:absolute; top:calc(100% + .3rem); left:0; z-index:40; display:grid; gap:.1rem; width:max-content; min-width:14rem;\n max-width:min(22rem,calc(100vw - 1rem)); max-height:60vh; overflow:auto; overscroll-behavior:contain; box-sizing:border-box; padding:.4rem;\n background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border); border-radius:var(--radius-md); box-shadow:0 8px 30px #0008; }\n.szenen-3d__sichtbar-liste label { display:flex; align-items:center; gap:.5rem; min-height:44px; padding:0 .4rem; cursor:pointer; }\n.szenen-3d__sichtbar-liste input { width:1.15rem; height:1.15rem; margin:0; flex:none; }\n.szenen-3d__sichtbar-liste i { flex:none; width:.6rem; height:.6rem; border-radius:2px; }\n.szenen-3d__sichtbar-liste button { margin-top:.3rem; min-height:44px; }\n.szenen-3d__blatt-schalter { display:none; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__blatt-schalter { display:block; }\n@media (max-width:760px) {\n .szenen-3d__blatt-schalter { display:block; }\n .szenen-3d__objektblatt.is-zu { display:none; }\n}\n\n/* MCP_STAGE_END */\n';
|
|
65
65
|
|
|
66
66
|
// src/lib/utils.ts
|
|
67
67
|
var getFormattedTimestamp = () => {
|
|
@@ -2416,7 +2416,7 @@ function useHFState(token, namespace) {
|
|
|
2416
2416
|
setForks(findForks(dag));
|
|
2417
2417
|
setEventCount(afterConsolidation.length);
|
|
2418
2418
|
if (afterConsolidation.length) setLastEventTs(Math.max(...afterConsolidation.map((e) => e.ts)));
|
|
2419
|
-
return
|
|
2419
|
+
return _chunkVSHSZEGVjs.applyEvents.call(void 0, snapshot, afterConsolidation);
|
|
2420
2420
|
}, []);
|
|
2421
2421
|
const loadFull = _react.useCallback.call(void 0, async () => {
|
|
2422
2422
|
if (!token || !namespace) return;
|
|
@@ -2424,14 +2424,14 @@ function useHFState(token, namespace) {
|
|
|
2424
2424
|
setError(null);
|
|
2425
2425
|
knownFilePaths.current = /* @__PURE__ */ new Set();
|
|
2426
2426
|
try {
|
|
2427
|
-
const snapshot = await
|
|
2427
|
+
const snapshot = await _chunkVSHSZEGVjs.loadHFState.call(void 0, namespace, token);
|
|
2428
2428
|
setHasStateZip(snapshot !== null);
|
|
2429
2429
|
const base = _nullishCoalesce(snapshot, () => ( {
|
|
2430
2430
|
metadata: [],
|
|
2431
2431
|
tags: { by_category: {}, all: [] },
|
|
2432
2432
|
meta: { consolidatedAt: 0, version: 1 }
|
|
2433
2433
|
}));
|
|
2434
|
-
const hfEvents = await
|
|
2434
|
+
const hfEvents = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
|
|
2435
2435
|
const hfEventKeys = new Set(hfEvents.map((e) => `${e.ts}_${e.clientId}`));
|
|
2436
2436
|
const localOnlyEvents = allEventsRef.current.filter(
|
|
2437
2437
|
(e) => !hfEventKeys.has(`${e.ts}_${e.clientId}`)
|
|
@@ -2449,14 +2449,14 @@ function useHFState(token, namespace) {
|
|
|
2449
2449
|
const failed = [];
|
|
2450
2450
|
for (const evt of buffer) {
|
|
2451
2451
|
try {
|
|
2452
|
-
await
|
|
2452
|
+
await _chunkVSHSZEGVjs.writeHFEvent.call(void 0, namespace, token, evt.type, evt.payload, evt.prevTs);
|
|
2453
2453
|
} catch (e5) {
|
|
2454
2454
|
failed.push(evt);
|
|
2455
2455
|
}
|
|
2456
2456
|
}
|
|
2457
2457
|
writeOfflineBuffer(failed);
|
|
2458
2458
|
setPendingBufferCount(failed.length);
|
|
2459
|
-
const freshEvents = await
|
|
2459
|
+
const freshEvents = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
|
|
2460
2460
|
freshEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
2461
2461
|
setState((prev) => prev ? applyNewEvents(base, freshEvents) : prev);
|
|
2462
2462
|
}
|
|
@@ -2469,7 +2469,7 @@ function useHFState(token, namespace) {
|
|
|
2469
2469
|
const pollNew = _react.useCallback.call(void 0, async () => {
|
|
2470
2470
|
if (!token || !namespace || !state) return;
|
|
2471
2471
|
try {
|
|
2472
|
-
const events = await
|
|
2472
|
+
const events = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, state.meta.consolidatedAt, knownFilePaths.current);
|
|
2473
2473
|
const newEvents = events.filter((e) => !knownEventPaths.current.has(`${e.ts}_${e.clientId}`));
|
|
2474
2474
|
if (!newEvents.length) return;
|
|
2475
2475
|
newEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
@@ -2494,7 +2494,7 @@ function useHFState(token, namespace) {
|
|
|
2494
2494
|
await pollNew();
|
|
2495
2495
|
try {
|
|
2496
2496
|
console.log("[HF] writeHFEvent start, path will be:", `${namespace}events/...`);
|
|
2497
|
-
const event = await
|
|
2497
|
+
const event = await _chunkVSHSZEGVjs.writeHFEvent.call(void 0, namespace, token, type, payload, prevTs);
|
|
2498
2498
|
console.log("[HF] writeHFEvent success:", event.ts);
|
|
2499
2499
|
knownEventPaths.current.add(`${event.ts}_${event.clientId}`);
|
|
2500
2500
|
const confirmedKey = `${event.ts}_${event.clientId}`;
|
|
@@ -2511,7 +2511,7 @@ function useHFState(token, namespace) {
|
|
|
2511
2511
|
type,
|
|
2512
2512
|
ts: Date.now(),
|
|
2513
2513
|
prevTs,
|
|
2514
|
-
clientId:
|
|
2514
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2515
2515
|
payload
|
|
2516
2516
|
};
|
|
2517
2517
|
writeOfflineBuffer([...buffer, offline]);
|
|
@@ -2544,11 +2544,11 @@ function useHFState(token, namespace) {
|
|
|
2544
2544
|
var _jszip = require('jszip'); var _jszip2 = _interopRequireDefault(_jszip);
|
|
2545
2545
|
var CURRENT_TAG_EVENT_VERSION = { major: 1, minor: 0 };
|
|
2546
2546
|
async function loadTagBase(namespace, token) {
|
|
2547
|
-
const files = await
|
|
2547
|
+
const files = await _chunkVSHSZEGVjs.hfListDir.call(void 0, namespace, "", token);
|
|
2548
2548
|
const tagBaseFiles = files.filter((f) => f.type === "file" && /^tags-state-[\dT\-]+Z\.zip$/.test(f.path.split("/").pop() || "")).sort((a, b) => b.path.localeCompare(a.path));
|
|
2549
2549
|
if (!tagBaseFiles.length) return null;
|
|
2550
2550
|
const newestPath = tagBaseFiles[0].path;
|
|
2551
|
-
const zipBytes = await
|
|
2551
|
+
const zipBytes = await _chunkVSHSZEGVjs.hfDownloadBinaryByPath.call(void 0, newestPath, token);
|
|
2552
2552
|
const zip = await _jszip2.default.loadAsync(zipBytes);
|
|
2553
2553
|
const [usersStr, contextsStr, tagsStr, metaStr] = await Promise.all([
|
|
2554
2554
|
_optionalChain([zip, 'access', _50 => _50.file, 'call', _51 => _51("users.json"), 'optionalAccess', _52 => _52.async, 'call', _53 => _53("string")]),
|
|
@@ -2573,14 +2573,14 @@ async function writeTagEvent(namespace, token, event) {
|
|
|
2573
2573
|
const uuid = crypto.randomUUID().slice(0, 8);
|
|
2574
2574
|
const filename = `${tsToFilename(event.ts)}_${uuid}.json`;
|
|
2575
2575
|
const repoPath = `${namespace}tag-events/${filename}`;
|
|
2576
|
-
await
|
|
2576
|
+
await _chunkVSHSZEGVjs.hfUploadSmallFile.call(void 0, repoPath, JSON.stringify(event, null, 2), token, `TagEvent: ${event.type}`);
|
|
2577
2577
|
}
|
|
2578
2578
|
function createTagCreatedEvent(baseVersion, userId, payload) {
|
|
2579
2579
|
return {
|
|
2580
2580
|
v: CURRENT_TAG_EVENT_VERSION,
|
|
2581
2581
|
type: "tag_created",
|
|
2582
2582
|
ts: Date.now(),
|
|
2583
|
-
clientId:
|
|
2583
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2584
2584
|
baseVersion,
|
|
2585
2585
|
userId,
|
|
2586
2586
|
payload
|
|
@@ -2591,7 +2591,7 @@ function createTagUpdatedEvent(baseVersion, userId, id, delta) {
|
|
|
2591
2591
|
v: CURRENT_TAG_EVENT_VERSION,
|
|
2592
2592
|
type: "tag_updated",
|
|
2593
2593
|
ts: Date.now(),
|
|
2594
|
-
clientId:
|
|
2594
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2595
2595
|
baseVersion,
|
|
2596
2596
|
userId,
|
|
2597
2597
|
payload: { id, delta }
|
|
@@ -5465,7 +5465,7 @@ function ServerTab({ serverBaseUrl }) {
|
|
|
5465
5465
|
function FlowWorkspacePicker({
|
|
5466
5466
|
tagBase,
|
|
5467
5467
|
selectedUserId,
|
|
5468
|
-
message,
|
|
5468
|
+
message: message2,
|
|
5469
5469
|
onSelectUser,
|
|
5470
5470
|
onSelectContext
|
|
5471
5471
|
}) {
|
|
@@ -5489,7 +5489,7 @@ function FlowWorkspacePicker({
|
|
|
5489
5489
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: "FineArt Flow" }),
|
|
5490
5490
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "small", { children: step === "user" ? "Benutzer w\xE4hlen" : `Kontext f\xFCr ${_nullishCoalesce(_optionalChain([selectedUser, 'optionalAccess', _153 => _153.username]), () => ( `User ${selectedUserId}`))}` })
|
|
5491
5491
|
] }),
|
|
5492
|
-
|
|
5492
|
+
message2 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "flow-workspace-picker__warning", children: message2 }),
|
|
5493
5493
|
step === "user" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flow-workspace-picker__choices", "aria-label": "Benutzer w\xE4hlen", children: [
|
|
5494
5494
|
tagBase.users.map((user) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", onClick: () => chooseUser(user.id), children: [
|
|
5495
5495
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: user.username }),
|
|
@@ -5530,6 +5530,328 @@ function FlowWorkspacePicker({
|
|
|
5530
5530
|
] }) });
|
|
5531
5531
|
}
|
|
5532
5532
|
|
|
5533
|
+
// src/components/FlowBridgePanel.tsx
|
|
5534
|
+
|
|
5535
|
+
|
|
5536
|
+
// src/lib/flowBridgeClient.ts
|
|
5537
|
+
var FLOW_BRIDGE_REQUEST_EVENT = "fine-art-flow-bridge:request:v1";
|
|
5538
|
+
var FLOW_BRIDGE_RESPONSE_EVENT = "fine-art-flow-bridge:response:v1";
|
|
5539
|
+
var FLOW_BRIDGE_HELLO_TIMEOUT_MS = 1500;
|
|
5540
|
+
var FLOW_BRIDGE_REQUEST_TIMEOUT_MS = 15e3;
|
|
5541
|
+
function isRecord(value) {
|
|
5542
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5543
|
+
}
|
|
5544
|
+
function readError(value) {
|
|
5545
|
+
if (isRecord(value) && typeof value.code === "string" && typeof value.message === "string") {
|
|
5546
|
+
return { code: value.code, message: value.message };
|
|
5547
|
+
}
|
|
5548
|
+
return { code: "invalid-message", message: "Antwort der Flow-Bridge ohne gueltige Fehlerangabe." };
|
|
5549
|
+
}
|
|
5550
|
+
function noBridge(timeoutMs) {
|
|
5551
|
+
return {
|
|
5552
|
+
code: "no-bridge",
|
|
5553
|
+
message: `Keine Antwort der Flow-Bridge innerhalb von ${timeoutMs} ms \u2014 Extension nicht installiert, deaktiviert oder fuer diesen Frame nicht freigegeben.`
|
|
5554
|
+
};
|
|
5555
|
+
}
|
|
5556
|
+
var nullableNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5557
|
+
var nextId = 0;
|
|
5558
|
+
function createFlowBridgeClient({
|
|
5559
|
+
target = document,
|
|
5560
|
+
appVersion,
|
|
5561
|
+
helloTimeoutMs = FLOW_BRIDGE_HELLO_TIMEOUT_MS,
|
|
5562
|
+
requestTimeoutMs = FLOW_BRIDGE_REQUEST_TIMEOUT_MS,
|
|
5563
|
+
clock = () => performance.now()
|
|
5564
|
+
} = {}) {
|
|
5565
|
+
function exchange(payload, timeoutMs) {
|
|
5566
|
+
nextId += 1;
|
|
5567
|
+
const id = `fb-${Date.now().toString(36)}-${nextId}`;
|
|
5568
|
+
return new Promise((resolve) => {
|
|
5569
|
+
const onResponse = (event) => {
|
|
5570
|
+
const detail = event.detail;
|
|
5571
|
+
if (typeof detail !== "string") return;
|
|
5572
|
+
let parsed;
|
|
5573
|
+
try {
|
|
5574
|
+
parsed = JSON.parse(detail);
|
|
5575
|
+
} catch (e20) {
|
|
5576
|
+
return;
|
|
5577
|
+
}
|
|
5578
|
+
if (!isRecord(parsed) || parsed.id !== id) return;
|
|
5579
|
+
cleanup();
|
|
5580
|
+
resolve(parsed);
|
|
5581
|
+
};
|
|
5582
|
+
const timer = setTimeout(() => {
|
|
5583
|
+
cleanup();
|
|
5584
|
+
resolve(null);
|
|
5585
|
+
}, timeoutMs);
|
|
5586
|
+
const cleanup = () => {
|
|
5587
|
+
clearTimeout(timer);
|
|
5588
|
+
target.removeEventListener(FLOW_BRIDGE_RESPONSE_EVENT, onResponse);
|
|
5589
|
+
};
|
|
5590
|
+
target.addEventListener(FLOW_BRIDGE_RESPONSE_EVENT, onResponse);
|
|
5591
|
+
target.dispatchEvent(new CustomEvent(FLOW_BRIDGE_REQUEST_EVENT, { detail: JSON.stringify({ id, ...payload }) }));
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
return {
|
|
5595
|
+
async status() {
|
|
5596
|
+
const started = clock();
|
|
5597
|
+
const reply = await exchange({ op: "hello", app: "flowfa", ...appVersion ? { appVersion } : {} }, helloTimeoutMs);
|
|
5598
|
+
const roundTripMs = Math.round(clock() - started);
|
|
5599
|
+
if (!reply) return { available: false, error: noBridge(helloTimeoutMs), roundTripMs };
|
|
5600
|
+
if (reply.ok !== true) return { available: false, error: readError(reply.error), roundTripMs };
|
|
5601
|
+
const bridge = reply.bridge;
|
|
5602
|
+
if (!isRecord(bridge) || typeof bridge.name !== "string" || typeof bridge.version !== "string" || typeof bridge.protocol !== "number") {
|
|
5603
|
+
return { available: false, error: { code: "invalid-message", message: "Handshake-Antwort ohne Bridge-Kennung." }, roundTripMs };
|
|
5604
|
+
}
|
|
5605
|
+
return { available: true, name: bridge.name, version: bridge.version, protocol: bridge.protocol, roundTripMs };
|
|
5606
|
+
},
|
|
5607
|
+
async request(request) {
|
|
5608
|
+
const started = clock();
|
|
5609
|
+
const tokenSuffix = "tokenSuffix" in request && request.tokenSuffix !== void 0 ? { tokenSuffix: request.tokenSuffix } : {};
|
|
5610
|
+
const reply = await exchange({ op: "request", target: request.target, method: request.method, path: request.path, ...tokenSuffix }, requestTimeoutMs);
|
|
5611
|
+
const roundTripMs = Math.round(clock() - started);
|
|
5612
|
+
if (!reply) {
|
|
5613
|
+
return { ok: false, transport: null, status: null, data: null, latencyMs: null, roundTripMs, error: noBridge(requestTimeoutMs) };
|
|
5614
|
+
}
|
|
5615
|
+
const ok = reply.ok === true;
|
|
5616
|
+
return {
|
|
5617
|
+
ok,
|
|
5618
|
+
transport: typeof reply.transport === "string" ? reply.transport : null,
|
|
5619
|
+
status: nullableNumber(reply.status),
|
|
5620
|
+
data: ok ? _nullishCoalesce(reply.data, () => ( null)) : null,
|
|
5621
|
+
latencyMs: nullableNumber(reply.latencyMs),
|
|
5622
|
+
roundTripMs,
|
|
5623
|
+
error: ok ? null : readError(reply.error)
|
|
5624
|
+
};
|
|
5625
|
+
}
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
5628
|
+
|
|
5629
|
+
// src/lib/flowProbeLoader.ts
|
|
5630
|
+
var FLOW_PROBE_REQUEST = { target: "devMcp", method: "GET", path: "/flow-app/probe-bundle" };
|
|
5631
|
+
var HF_TOKEN_SUFFIX_CHARS = 8;
|
|
5632
|
+
var FLOW_PROBE_MARKER = "__faFlowProbe";
|
|
5633
|
+
var FLOW_PROBE_METHOD = "script-blob";
|
|
5634
|
+
var FLOW_PROBE_LOAD_TIMEOUT_MS = 5e3;
|
|
5635
|
+
var CSP_SETTLE_MS = 100;
|
|
5636
|
+
function isRecord2(value) {
|
|
5637
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5638
|
+
}
|
|
5639
|
+
function hfTokenSuffix(token) {
|
|
5640
|
+
const trimmed = (_nullishCoalesce(token, () => ( ""))).trim();
|
|
5641
|
+
return trimmed.length >= HF_TOKEN_SUFFIX_CHARS ? trimmed.slice(-HF_TOKEN_SUFFIX_CHARS) : null;
|
|
5642
|
+
}
|
|
5643
|
+
function readFlowProbeBundle(data) {
|
|
5644
|
+
if (!isRecord2(data)) return null;
|
|
5645
|
+
const { version: version2, sha256, source } = data;
|
|
5646
|
+
if (typeof version2 !== "string" || !/^probe-\d{3}$/.test(version2)) return null;
|
|
5647
|
+
if (typeof sha256 !== "string" || !/^[0-9a-f]{64}$/.test(sha256)) return null;
|
|
5648
|
+
if (typeof source !== "string" || source.length === 0) return null;
|
|
5649
|
+
return { version: version2, sha256, source };
|
|
5650
|
+
}
|
|
5651
|
+
function readMarker(value) {
|
|
5652
|
+
if (!isRecord2(value) || value.executed !== true || typeof value.version !== "string") return null;
|
|
5653
|
+
return { executed: true, version: value.version, executedAt: typeof value.executedAt === "string" ? value.executedAt : null };
|
|
5654
|
+
}
|
|
5655
|
+
async function sha256Hex(text) {
|
|
5656
|
+
if (!_optionalChain([globalThis, 'access', _154 => _154.crypto, 'optionalAccess', _155 => _155.subtle])) throw new Error("crypto.subtle ist in diesem Kontext nicht verfuegbar.");
|
|
5657
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
5658
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
5659
|
+
}
|
|
5660
|
+
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
5661
|
+
var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5662
|
+
async function executeFlowProbeBundle(bundle, {
|
|
5663
|
+
win = window,
|
|
5664
|
+
doc = document,
|
|
5665
|
+
timeoutMs = FLOW_PROBE_LOAD_TIMEOUT_MS,
|
|
5666
|
+
digest = sha256Hex
|
|
5667
|
+
} = {}) {
|
|
5668
|
+
const markerHost = win;
|
|
5669
|
+
const result = {
|
|
5670
|
+
method: FLOW_PROBE_METHOD,
|
|
5671
|
+
pageOrigin: win.location.origin,
|
|
5672
|
+
hash: { expected: bundle.sha256, actual: null, matches: null, error: null },
|
|
5673
|
+
scriptEvent: "not-started",
|
|
5674
|
+
marker: null,
|
|
5675
|
+
executed: false,
|
|
5676
|
+
cspViolations: [],
|
|
5677
|
+
error: null
|
|
5678
|
+
};
|
|
5679
|
+
try {
|
|
5680
|
+
result.hash.actual = await digest(bundle.source);
|
|
5681
|
+
result.hash.matches = result.hash.actual === bundle.sha256;
|
|
5682
|
+
} catch (error) {
|
|
5683
|
+
result.hash.error = message(error);
|
|
5684
|
+
}
|
|
5685
|
+
if (result.hash.matches === false) {
|
|
5686
|
+
result.error = "SHA-256 des empfangenen Quelltexts weicht ab \u2014 Bundle nicht ausgefuehrt.";
|
|
5687
|
+
return result;
|
|
5688
|
+
}
|
|
5689
|
+
delete markerHost[FLOW_PROBE_MARKER];
|
|
5690
|
+
const onViolation = (event) => {
|
|
5691
|
+
const violation = event;
|
|
5692
|
+
result.cspViolations.push(`${violation.effectiveDirective || violation.violatedDirective}: ${violation.blockedURI || "unbekannt"}`);
|
|
5693
|
+
};
|
|
5694
|
+
doc.addEventListener("securitypolicyviolation", onViolation);
|
|
5695
|
+
let url = null;
|
|
5696
|
+
let script = null;
|
|
5697
|
+
try {
|
|
5698
|
+
url = URL.createObjectURL(new Blob([bundle.source], { type: "text/javascript" }));
|
|
5699
|
+
const element = doc.createElement("script");
|
|
5700
|
+
script = element;
|
|
5701
|
+
result.scriptEvent = await new Promise((resolve) => {
|
|
5702
|
+
const timer = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
5703
|
+
element.addEventListener("load", () => {
|
|
5704
|
+
clearTimeout(timer);
|
|
5705
|
+
resolve("load");
|
|
5706
|
+
});
|
|
5707
|
+
element.addEventListener("error", () => {
|
|
5708
|
+
clearTimeout(timer);
|
|
5709
|
+
resolve("error");
|
|
5710
|
+
});
|
|
5711
|
+
element.src = url;
|
|
5712
|
+
(_nullishCoalesce(doc.head, () => ( doc.documentElement))).appendChild(element);
|
|
5713
|
+
});
|
|
5714
|
+
} catch (error) {
|
|
5715
|
+
result.error = `Skript nicht einfuegbar: ${message(error)}`;
|
|
5716
|
+
}
|
|
5717
|
+
result.marker = readMarker(markerHost[FLOW_PROBE_MARKER]);
|
|
5718
|
+
result.executed = result.marker !== null && result.marker.version === bundle.version;
|
|
5719
|
+
if (!result.executed) await wait(CSP_SETTLE_MS);
|
|
5720
|
+
doc.removeEventListener("securitypolicyviolation", onViolation);
|
|
5721
|
+
_optionalChain([script, 'optionalAccess', _156 => _156.remove, 'call', _157 => _157()]);
|
|
5722
|
+
if (url) URL.revokeObjectURL(url);
|
|
5723
|
+
if (!result.executed && !result.error) {
|
|
5724
|
+
if (result.marker) result.error = `Marker meldet Version ${result.marker.version}, erwartet ${bundle.version}.`;
|
|
5725
|
+
else if (result.scriptEvent === "load") result.error = "script.onload ohne Marker \u2014 Ausfuehrung nicht belegt.";
|
|
5726
|
+
else if (result.scriptEvent === "error") result.error = "script.onerror \u2014 Skript nicht geladen oder blockiert.";
|
|
5727
|
+
else result.error = `Kein Skript-Ereignis innerhalb von ${timeoutMs} ms.`;
|
|
5728
|
+
}
|
|
5729
|
+
return result;
|
|
5730
|
+
}
|
|
5731
|
+
|
|
5732
|
+
// src/components/FlowBridgePanel.tsx
|
|
5733
|
+
|
|
5734
|
+
var STATUS_REQUEST = { target: "dev", method: "GET", path: "/api/status" };
|
|
5735
|
+
function hashText(execution) {
|
|
5736
|
+
if (execution.hash.matches === true) return "Hash gepr\xFCft";
|
|
5737
|
+
if (execution.hash.matches === false) return `Hash ABWEICHEND (berechnet ${_optionalChain([execution, 'access', _158 => _158.hash, 'access', _159 => _159.actual, 'optionalAccess', _160 => _160.slice, 'call', _161 => _161(0, 12)])}\u2026)`;
|
|
5738
|
+
return `Hash nicht pr\xFCfbar (${execution.hash.error})`;
|
|
5739
|
+
}
|
|
5740
|
+
function probeVerdict(run) {
|
|
5741
|
+
if (_optionalChain([run, 'access', _162 => _162.execution, 'optionalAccess', _163 => _163.executed])) return { ok: true, text: `ERGEBNIS: ausgef\xFChrt (executed: true, ${_optionalChain([run, 'access', _164 => _164.execution, 'access', _165 => _165.marker, 'optionalAccess', _166 => _166.version])})` };
|
|
5742
|
+
if (!run.response.ok) {
|
|
5743
|
+
return { ok: false, text: `ERGEBNIS: nicht ausgef\xFChrt \u2014 ${_optionalChain([run, 'access', _167 => _167.response, 'access', _168 => _168.error, 'optionalAccess', _169 => _169.code]) === "no-hf-token" ? "kein HF-Token in FlowFA." : "Bundle nicht \xFCber die Bridge erhalten."}` };
|
|
5744
|
+
}
|
|
5745
|
+
if (!run.bundle) return { ok: false, text: "ERGEBNIS: nicht ausgef\xFChrt \u2014 Antwort ohne g\xFCltiges Bundle." };
|
|
5746
|
+
return { ok: false, text: `ERGEBNIS: nicht ausgef\xFChrt \u2014 ${_optionalChain([run, 'access', _170 => _170.execution, 'optionalAccess', _171 => _171.error])}` };
|
|
5747
|
+
}
|
|
5748
|
+
var FlowBridgePanel = ({ appVersion, client, hfToken }) => {
|
|
5749
|
+
const bridge = _react.useMemo.call(void 0, () => _nullishCoalesce(client, () => ( createFlowBridgeClient({ appVersion }))), [client, appVersion]);
|
|
5750
|
+
const [status, setStatus] = _react.useState.call(void 0, null);
|
|
5751
|
+
const [response, setResponse] = _react.useState.call(void 0, null);
|
|
5752
|
+
const [probe, setProbe] = _react.useState.call(void 0, null);
|
|
5753
|
+
const [busy, setBusy] = _react.useState.call(void 0, null);
|
|
5754
|
+
const checkStatus = async () => {
|
|
5755
|
+
setBusy("status");
|
|
5756
|
+
try {
|
|
5757
|
+
setStatus(await bridge.status());
|
|
5758
|
+
} finally {
|
|
5759
|
+
setBusy(null);
|
|
5760
|
+
}
|
|
5761
|
+
};
|
|
5762
|
+
_react.useEffect.call(void 0, () => {
|
|
5763
|
+
let active = true;
|
|
5764
|
+
void bridge.status().then((result) => {
|
|
5765
|
+
if (active) setStatus(result);
|
|
5766
|
+
});
|
|
5767
|
+
return () => {
|
|
5768
|
+
active = false;
|
|
5769
|
+
};
|
|
5770
|
+
}, [bridge]);
|
|
5771
|
+
const runRequest = async () => {
|
|
5772
|
+
setBusy("request");
|
|
5773
|
+
setResponse(null);
|
|
5774
|
+
try {
|
|
5775
|
+
setResponse(await bridge.request(STATUS_REQUEST));
|
|
5776
|
+
} finally {
|
|
5777
|
+
setBusy(null);
|
|
5778
|
+
}
|
|
5779
|
+
};
|
|
5780
|
+
const runProbe = async () => {
|
|
5781
|
+
setBusy("probe");
|
|
5782
|
+
setProbe(null);
|
|
5783
|
+
try {
|
|
5784
|
+
const tokenSuffix = hfTokenSuffix(hfToken);
|
|
5785
|
+
if (!tokenSuffix) {
|
|
5786
|
+
setProbe({
|
|
5787
|
+
response: {
|
|
5788
|
+
ok: false,
|
|
5789
|
+
transport: null,
|
|
5790
|
+
status: null,
|
|
5791
|
+
data: null,
|
|
5792
|
+
latencyMs: null,
|
|
5793
|
+
roundTripMs: 0,
|
|
5794
|
+
error: { code: "no-hf-token", message: "Kein HF-Token in FlowFA gesetzt \u2014 ohne ihn kein Zugang zum Dev-MCP-Host." }
|
|
5795
|
+
},
|
|
5796
|
+
bundle: null,
|
|
5797
|
+
execution: null
|
|
5798
|
+
});
|
|
5799
|
+
return;
|
|
5800
|
+
}
|
|
5801
|
+
const response2 = await bridge.request({ ...FLOW_PROBE_REQUEST, tokenSuffix });
|
|
5802
|
+
const bundle = response2.ok ? readFlowProbeBundle(response2.data) : null;
|
|
5803
|
+
const execution = bundle ? await executeFlowProbeBundle(bundle) : null;
|
|
5804
|
+
setProbe({ response: response2, bundle, execution });
|
|
5805
|
+
} finally {
|
|
5806
|
+
setBusy(null);
|
|
5807
|
+
}
|
|
5808
|
+
};
|
|
5809
|
+
const buttonStyle = {
|
|
5810
|
+
height: 36,
|
|
5811
|
+
border: "1px solid rgba(255,255,255,0.12)",
|
|
5812
|
+
color: "rgba(255,255,255,0.7)",
|
|
5813
|
+
background: "rgba(255,255,255,0.04)"
|
|
5814
|
+
};
|
|
5815
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "details", { className: "w-full max-w-[280px] rounded-xl px-3 py-2", style: { border: "1px solid rgba(255,255,255,0.08)" }, children: [
|
|
5816
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "summary", { className: "text-white/40 text-[10px] uppercase tracking-widest font-bold cursor-pointer", children: "Flow-Bridge (Firefox)" }),
|
|
5817
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2 mt-2 text-[10px] font-mono", children: [
|
|
5818
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
|
|
5819
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: checkStatus, disabled: busy !== null, className: "rounded-lg text-[11px] font-bold disabled:opacity-40", style: buttonStyle, children: busy === "status" ? "Pr\xFCfe\u2026" : "Bridge pr\xFCfen" }),
|
|
5820
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: runRequest, disabled: busy !== null, className: "rounded-lg text-[11px] font-bold disabled:opacity-40", style: buttonStyle, children: busy === "request" ? "L\xE4uft\u2026" : "Dev /api/status" })
|
|
5821
|
+
] }),
|
|
5822
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: runProbe, disabled: busy !== null, className: "rounded-lg text-[11px] font-bold disabled:opacity-40", style: buttonStyle, children: busy === "probe" ? "L\xE4uft\u2026" : "Mini-Bundle laden & ausf\xFChren" }),
|
|
5823
|
+
status && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { role: "status", "data-testid": "flow-bridge-status", style: { color: status.available ? "#4ade80" : "#f87171" }, children: status.available ? `Bridge: verbunden \xB7 ${status.name} v${status.version} \xB7 Protokoll ${status.protocol} \xB7 ${status.roundTripMs} ms` : `Bridge: nicht verbunden \xB7 ${status.error.code}: ${status.error.message}` }),
|
|
5824
|
+
response && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-testid": "flow-bridge-response", className: "flex flex-col gap-1", children: [
|
|
5825
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { color: response.ok ? "#4ade80" : "#f87171" }, children: [
|
|
5826
|
+
`${STATUS_REQUEST.method} ${STATUS_REQUEST.path} (${STATUS_REQUEST.target}) \u2192 `,
|
|
5827
|
+
response.status !== null ? `HTTP ${response.status}` : "kein HTTP-Status",
|
|
5828
|
+
response.ok ? "" : ` \xB7 ${_optionalChain([response, 'access', _172 => _172.error, 'optionalAccess', _173 => _173.code])}: ${_optionalChain([response, 'access', _174 => _174.error, 'optionalAccess', _175 => _175.message])}`
|
|
5829
|
+
] }),
|
|
5830
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/40", children: `Transport: ${_nullishCoalesce(response.transport, () => ( "keiner"))} \xB7 Server ${_nullishCoalesce(response.latencyMs, () => ( "\u2014"))} ms \xB7 gesamt ${response.roundTripMs} ms` }),
|
|
5831
|
+
response.ok && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "pre", { className: "text-white/60 whitespace-pre-wrap break-all bg-black/30 rounded-lg p-2", children: JSON.stringify(response.data, null, 2) })
|
|
5832
|
+
] }),
|
|
5833
|
+
probe && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-testid": "flow-bridge-probe", className: "flex flex-col gap-1", children: [
|
|
5834
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { color: probe.response.ok ? "#4ade80" : "#f87171" }, children: [
|
|
5835
|
+
`${FLOW_PROBE_REQUEST.method} ${FLOW_PROBE_REQUEST.path} (${FLOW_PROBE_REQUEST.target}) \u2192 `,
|
|
5836
|
+
probe.response.status !== null ? `HTTP ${probe.response.status}` : "kein HTTP-Status",
|
|
5837
|
+
probe.response.ok ? "" : ` \xB7 ${_optionalChain([probe, 'access', _176 => _176.response, 'access', _177 => _177.error, 'optionalAccess', _178 => _178.code])}: ${_optionalChain([probe, 'access', _179 => _179.response, 'access', _180 => _180.error, 'optionalAccess', _181 => _181.message])}`
|
|
5838
|
+
] }),
|
|
5839
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/40", children: `Transport: ${_nullishCoalesce(probe.response.transport, () => ( "keiner"))} \xB7 Server ${_nullishCoalesce(probe.response.latencyMs, () => ( "\u2014"))} ms \xB7 gesamt ${probe.response.roundTripMs} ms` }),
|
|
5840
|
+
probe.bundle && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-white/60 break-all", children: [
|
|
5841
|
+
`Bundle ${probe.bundle.version} \xB7 ${probe.bundle.source.length} Zeichen \xB7 SHA-256 ${probe.bundle.sha256.slice(0, 12)}\u2026`,
|
|
5842
|
+
probe.execution ? ` \xB7 ${hashText(probe.execution)}` : ""
|
|
5843
|
+
] }),
|
|
5844
|
+
probe.execution && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
5845
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/60 break-all", children: `Ausf\xFChrung: <script src=blob:> \xB7 Ereignis ${probe.execution.scriptEvent} \xB7 Seite ${probe.execution.pageOrigin}` }),
|
|
5846
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/60 break-all", children: `Marker window.${FLOW_PROBE_MARKER}: ${probe.execution.marker ? JSON.stringify(probe.execution.marker) : "fehlt"}` }),
|
|
5847
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "break-all", style: { color: probe.execution.cspViolations.length > 0 ? "#f87171" : "rgba(255,255,255,0.4)" }, children: probe.execution.cspViolations.length > 0 ? `CSP: ${probe.execution.cspViolations.join("; ")}` : "CSP: keine Verletzung gemeldet" })
|
|
5848
|
+
] }),
|
|
5849
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { "data-testid": "flow-bridge-probe-verdict", className: "font-bold", style: { color: probeVerdict(probe).ok ? "#4ade80" : "#f87171" }, children: probeVerdict(probe).text })
|
|
5850
|
+
] })
|
|
5851
|
+
] })
|
|
5852
|
+
] });
|
|
5853
|
+
};
|
|
5854
|
+
|
|
5533
5855
|
// src/lib/flowBootstrapTarget.ts
|
|
5534
5856
|
var PROD_NAMESPACE = "app.art-by-rolands.de/";
|
|
5535
5857
|
var DEV_NAMESPACE = "dev-app.art-by-rolands.de/";
|
|
@@ -5597,7 +5919,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5597
5919
|
const [layoutChoice, setLayoutChoice] = _react.useState.call(void 0, () => {
|
|
5598
5920
|
try {
|
|
5599
5921
|
return localStorage.getItem("aa-layout") || null;
|
|
5600
|
-
} catch (
|
|
5922
|
+
} catch (e21) {
|
|
5601
5923
|
return null;
|
|
5602
5924
|
}
|
|
5603
5925
|
});
|
|
@@ -5606,7 +5928,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5606
5928
|
const [hfNamespaceLocal, setHfNamespaceLocal] = _react.useState.call(void 0, () => {
|
|
5607
5929
|
try {
|
|
5608
5930
|
return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
|
|
5609
|
-
} catch (
|
|
5931
|
+
} catch (e22) {
|
|
5610
5932
|
return DEFAULT_NAMESPACE;
|
|
5611
5933
|
}
|
|
5612
5934
|
});
|
|
@@ -5631,7 +5953,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5631
5953
|
});
|
|
5632
5954
|
const effectiveNamespace = _nullishCoalesce(bootstrapTarget.namespace, () => ( ""));
|
|
5633
5955
|
const kontextRef = _react.useRef.call(void 0, null);
|
|
5634
|
-
const szenenPort = _react.useMemo.call(void 0, () => hfToken && effectiveNamespace ?
|
|
5956
|
+
const szenenPort = _react.useMemo.call(void 0, () => hfToken && effectiveNamespace ? _chunkVSHSZEGVjs.createFlowSzenenViewPort.call(void 0, {
|
|
5635
5957
|
generateText: onGeneratePrompt,
|
|
5636
5958
|
token: hfToken,
|
|
5637
5959
|
namespace: effectiveNamespace,
|
|
@@ -5690,7 +6012,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5690
6012
|
setIsBootstrapping(true);
|
|
5691
6013
|
setBootstrapLog([]);
|
|
5692
6014
|
try {
|
|
5693
|
-
await
|
|
6015
|
+
await _chunkVSHSZEGVjs.hfBootstrapFromLegacy.call(void 0, effectiveNamespace, hfToken, (msg) => setBootstrapLog((prev) => [...prev, msg]));
|
|
5694
6016
|
setBootstrapLog((prev) => [...prev, "\u2713 Fertig"]);
|
|
5695
6017
|
setTimeout(() => refreshHF(), 1500);
|
|
5696
6018
|
} catch (e) {
|
|
@@ -5709,7 +6031,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5709
6031
|
const startApp = (choice) => {
|
|
5710
6032
|
try {
|
|
5711
6033
|
localStorage.setItem("aa-layout", choice);
|
|
5712
|
-
} catch (
|
|
6034
|
+
} catch (e23) {
|
|
5713
6035
|
}
|
|
5714
6036
|
setLayoutChoice(choice);
|
|
5715
6037
|
setTargetConfirmed(true);
|
|
@@ -5730,9 +6052,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5730
6052
|
const loadThumbnailsForEntries = _react.useCallback.call(void 0, async (entries) => {
|
|
5731
6053
|
await loadThumbnailsSequentially(entries, {
|
|
5732
6054
|
inFlight: hfInFlightRef.current,
|
|
5733
|
-
isAlreadyLoaded: (entry) => !!_optionalChain([galleryItemsRef, 'access',
|
|
6055
|
+
isAlreadyLoaded: (entry) => !!_optionalChain([galleryItemsRef, 'access', _182 => _182.current, 'access', _183 => _183.find, 'call', _184 => _184((g) => g.id === entry.id), 'optionalAccess', _185 => _185.base64]),
|
|
5734
6056
|
isKnownMissing: (entry) => hfImageNotFoundRef.current.has(entry.id),
|
|
5735
|
-
loadImage: (entry) =>
|
|
6057
|
+
loadImage: (entry) => _chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, entry.id, hfToken, effectiveNamespace, entry.filename, void 0, entry.mimeType, entry.hasThumb),
|
|
5736
6058
|
onLoaded: (entry, b64) => {
|
|
5737
6059
|
const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
|
|
5738
6060
|
setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
@@ -5749,7 +6071,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5749
6071
|
}, [hfToken, effectiveNamespace]);
|
|
5750
6072
|
_react.useEffect.call(void 0, () => {
|
|
5751
6073
|
if (!hfState) return;
|
|
5752
|
-
if (_optionalChain([hfState, 'access',
|
|
6074
|
+
if (_optionalChain([hfState, 'access', _186 => _186.tags, 'optionalAccess', _187 => _187.by_category])) setWorkspaceTags(hfState.tags);
|
|
5753
6075
|
const hfIds = new Set(hfState.metadata.map((m) => m.id));
|
|
5754
6076
|
const skeletons = hfState.metadata.map((m) => ({
|
|
5755
6077
|
id: m.id,
|
|
@@ -5795,7 +6117,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5795
6117
|
try {
|
|
5796
6118
|
const v = parseInt(localStorage.getItem("aa-image-count") || "", 10);
|
|
5797
6119
|
return v >= 1 && v <= 8 ? v : 4;
|
|
5798
|
-
} catch (
|
|
6120
|
+
} catch (e24) {
|
|
5799
6121
|
return 4;
|
|
5800
6122
|
}
|
|
5801
6123
|
});
|
|
@@ -5804,7 +6126,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5804
6126
|
setImageCount(n);
|
|
5805
6127
|
try {
|
|
5806
6128
|
localStorage.setItem("aa-image-count", String(n));
|
|
5807
|
-
} catch (
|
|
6129
|
+
} catch (e25) {
|
|
5808
6130
|
}
|
|
5809
6131
|
};
|
|
5810
6132
|
const imageCountOptions = [
|
|
@@ -5818,14 +6140,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5818
6140
|
const [leftPanelWidth, setLeftPanelWidth] = _react.useState.call(void 0, () => {
|
|
5819
6141
|
try {
|
|
5820
6142
|
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
5821
|
-
} catch (
|
|
6143
|
+
} catch (e26) {
|
|
5822
6144
|
return 260;
|
|
5823
6145
|
}
|
|
5824
6146
|
});
|
|
5825
6147
|
const [rightPanelWidth, setRightPanelWidth] = _react.useState.call(void 0, () => {
|
|
5826
6148
|
try {
|
|
5827
6149
|
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
5828
|
-
} catch (
|
|
6150
|
+
} catch (e27) {
|
|
5829
6151
|
return 320;
|
|
5830
6152
|
}
|
|
5831
6153
|
});
|
|
@@ -5834,7 +6156,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5834
6156
|
const [highContrast, setHighContrast] = _react.useState.call(void 0, () => {
|
|
5835
6157
|
try {
|
|
5836
6158
|
return localStorage.getItem("aa-contrast") === "high";
|
|
5837
|
-
} catch (
|
|
6159
|
+
} catch (e28) {
|
|
5838
6160
|
return false;
|
|
5839
6161
|
}
|
|
5840
6162
|
});
|
|
@@ -5847,14 +6169,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5847
6169
|
const [zoomOffset, setZoomOffset] = _react.useState.call(void 0, { x: 0, y: 0 });
|
|
5848
6170
|
const { historyVisible, galleryVisible } = computePrefetchVisibility({
|
|
5849
6171
|
layoutChoice,
|
|
5850
|
-
appShellVisible: !showStart && !requireWorkspaceSelection && !(isFullscreen && !!_optionalChain([currentResult, 'optionalAccess',
|
|
6172
|
+
appShellVisible: !showStart && !requireWorkspaceSelection && !(isFullscreen && !!_optionalChain([currentResult, 'optionalAccess', _188 => _188.base64])),
|
|
5851
6173
|
mobileTab,
|
|
5852
6174
|
middlePanel,
|
|
5853
6175
|
activeTab,
|
|
5854
6176
|
isRightCollapsed
|
|
5855
6177
|
});
|
|
5856
6178
|
useThumbnailPrefetch({
|
|
5857
|
-
metadata: _optionalChain([hfState, 'optionalAccess',
|
|
6179
|
+
metadata: _optionalChain([hfState, 'optionalAccess', _189 => _189.metadata]),
|
|
5858
6180
|
historyVisible,
|
|
5859
6181
|
galleryVisible,
|
|
5860
6182
|
historyVisibleCount,
|
|
@@ -5910,12 +6232,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5910
6232
|
setHighContrast(next);
|
|
5911
6233
|
try {
|
|
5912
6234
|
localStorage.setItem("aa-contrast", next ? "high" : "low");
|
|
5913
|
-
} catch (
|
|
6235
|
+
} catch (e29) {
|
|
5914
6236
|
}
|
|
5915
6237
|
};
|
|
5916
6238
|
const handleSelectReference = async () => {
|
|
5917
6239
|
const media = await onSelectMedia();
|
|
5918
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
6240
|
+
if (!_optionalChain([media, 'optionalAccess', _190 => _190.length])) return;
|
|
5919
6241
|
const first = media[0];
|
|
5920
6242
|
if (first.mediaId) {
|
|
5921
6243
|
setActiveReferenceId(first.mediaId);
|
|
@@ -5938,7 +6260,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5938
6260
|
generateImage: onGenerateImage,
|
|
5939
6261
|
saveResult: async (item) => {
|
|
5940
6262
|
const frame = item.frames[0];
|
|
5941
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
6263
|
+
if (_optionalChain([frame, 'optionalAccess', _191 => _191.base64])) {
|
|
5942
6264
|
const gen = frameToGeneration(frame, item);
|
|
5943
6265
|
setGalleryItems((prev) => [gen, ...prev]);
|
|
5944
6266
|
setHistory((prev) => [gen, ...prev]);
|
|
@@ -5956,7 +6278,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5956
6278
|
setLeftPanelWidth(w);
|
|
5957
6279
|
try {
|
|
5958
6280
|
localStorage.setItem("aa-left-width", String(w));
|
|
5959
|
-
} catch (
|
|
6281
|
+
} catch (e30) {
|
|
5960
6282
|
}
|
|
5961
6283
|
};
|
|
5962
6284
|
const onUp = () => {
|
|
@@ -5975,7 +6297,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5975
6297
|
setRightPanelWidth(w);
|
|
5976
6298
|
try {
|
|
5977
6299
|
localStorage.setItem("aa-right-width", String(w));
|
|
5978
|
-
} catch (
|
|
6300
|
+
} catch (e31) {
|
|
5979
6301
|
}
|
|
5980
6302
|
};
|
|
5981
6303
|
const onUp = () => {
|
|
@@ -6006,7 +6328,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6006
6328
|
setIsScanningImage(false);
|
|
6007
6329
|
}
|
|
6008
6330
|
};
|
|
6009
|
-
const currentIndex = _react.useMemo.call(void 0, () => history.findIndex((h) => h.id === _optionalChain([currentResult, 'optionalAccess',
|
|
6331
|
+
const currentIndex = _react.useMemo.call(void 0, () => history.findIndex((h) => h.id === _optionalChain([currentResult, 'optionalAccess', _192 => _192.id])), [history, currentResult]);
|
|
6010
6332
|
const goToPrev = _react.useCallback.call(void 0, () => {
|
|
6011
6333
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
6012
6334
|
}, [currentIndex, history]);
|
|
@@ -6017,10 +6339,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6017
6339
|
setCurrentResult(g);
|
|
6018
6340
|
setMobileTab("stage");
|
|
6019
6341
|
if (g.hasThumb && g.filename && hfToken && !g.fullBase64) {
|
|
6020
|
-
|
|
6342
|
+
_chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, g.id, hfToken, effectiveNamespace, g.filename, void 0, g.mimeType, false).then((b64) => {
|
|
6021
6343
|
if (!b64) return;
|
|
6022
6344
|
const full = `data:${g.mimeType || "image/jpeg"};base64,${b64}`;
|
|
6023
|
-
setCurrentResult((prev) => _optionalChain([prev, 'optionalAccess',
|
|
6345
|
+
setCurrentResult((prev) => _optionalChain([prev, 'optionalAccess', _193 => _193.id]) === g.id ? { ...prev, fullBase64: full } : prev);
|
|
6024
6346
|
setGalleryItems((prev) => prev.map((item) => item.id === g.id ? { ...item, fullBase64: full } : item));
|
|
6025
6347
|
}).catch(() => {
|
|
6026
6348
|
});
|
|
@@ -6036,13 +6358,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6036
6358
|
}
|
|
6037
6359
|
}, [hfToken, effectiveNamespace, hfWriteEvent]);
|
|
6038
6360
|
const currentGroup = _react.useMemo.call(void 0, () => {
|
|
6039
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6361
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _194 => _194.prompt])) return [];
|
|
6040
6362
|
const groups = groupByPrompt(galleryItems.filter((g) => g.status === "done" && !!g.base64));
|
|
6041
6363
|
const group = groups.find((gr) => gr.prompt === currentResult.prompt);
|
|
6042
6364
|
return group ? group.items : [];
|
|
6043
|
-
}, [galleryItems, _optionalChain([currentResult, 'optionalAccess',
|
|
6365
|
+
}, [galleryItems, _optionalChain([currentResult, 'optionalAccess', _195 => _195.prompt])]);
|
|
6044
6366
|
_react.useEffect.call(void 0, () => {
|
|
6045
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6367
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _196 => _196.prompt]) || !hfToken || !effectiveNamespace || !hfState) return;
|
|
6046
6368
|
const siblings = galleryItemsRef.current.filter(
|
|
6047
6369
|
(g) => g.prompt === currentResult.prompt && !g.base64 && !hfImageNotFoundRef.current.has(g.id)
|
|
6048
6370
|
);
|
|
@@ -6052,7 +6374,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6052
6374
|
const meta = hfState.metadata.find((m) => m.id === sib.id);
|
|
6053
6375
|
if (!meta) continue;
|
|
6054
6376
|
try {
|
|
6055
|
-
const b64 = await
|
|
6377
|
+
const b64 = await _chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, sib.id, hfToken, effectiveNamespace, meta.filename, void 0, meta.mimeType, meta.hasThumb);
|
|
6056
6378
|
if (!b64) {
|
|
6057
6379
|
hfImageNotFoundRef.current.set(sib.id, Date.now());
|
|
6058
6380
|
continue;
|
|
@@ -6060,12 +6382,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6060
6382
|
const prefix = `data:${meta.mimeType || "image/jpeg"};base64,`;
|
|
6061
6383
|
setGalleryItems((prev) => prev.map((g) => g.id === sib.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
6062
6384
|
setHistory((prev) => prev.map((g) => g.id === sib.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
6063
|
-
} catch (
|
|
6385
|
+
} catch (e32) {
|
|
6064
6386
|
hfImageNotFoundRef.current.set(sib.id, Date.now());
|
|
6065
6387
|
}
|
|
6066
6388
|
}
|
|
6067
6389
|
})();
|
|
6068
|
-
}, [_optionalChain([currentResult, 'optionalAccess',
|
|
6390
|
+
}, [_optionalChain([currentResult, 'optionalAccess', _197 => _197.id]), _optionalChain([currentResult, 'optionalAccess', _198 => _198.prompt])]);
|
|
6069
6391
|
const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
|
|
6070
6392
|
const runningBadge = activeGenerationsCount > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
6071
6393
|
"div",
|
|
@@ -6124,7 +6446,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6124
6446
|
console.log("[HF] handleGenerateImage \u2014 condition check:", { hfToken: !!hfToken, base64: !!base64, effectiveNamespace });
|
|
6125
6447
|
if (hfToken && base64 && effectiveNamespace) {
|
|
6126
6448
|
setImageUploadStatus((m) => new Map(m).set(genId, "uploading"));
|
|
6127
|
-
|
|
6449
|
+
_chunkVSHSZEGVjs.hfUploadImage.call(void 0, base64, genId, hfToken).then(() => setImageUploadStatus((m) => new Map(m).set(genId, "done"))).catch((e) => {
|
|
6128
6450
|
console.error("[HF] hfUploadImage failed:", e);
|
|
6129
6451
|
setImageUploadStatus((m) => new Map(m).set(genId, "failed"));
|
|
6130
6452
|
});
|
|
@@ -6146,7 +6468,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6146
6468
|
const errorGen = { ...newGen, status: "error", error: { message: err.message || "Unbekannter Fehler", details: err.toString() } };
|
|
6147
6469
|
setHistory((prev) => prev.map((g) => g.id === genId ? errorGen : g));
|
|
6148
6470
|
setGalleryItems((prev) => prev.filter((g) => g.id !== genId));
|
|
6149
|
-
if (!options.silent || _optionalChain([currentResult, 'optionalAccess',
|
|
6471
|
+
if (!options.silent || _optionalChain([currentResult, 'optionalAccess', _199 => _199.id]) === genId) setCurrentResult(errorGen);
|
|
6150
6472
|
} finally {
|
|
6151
6473
|
setActiveGenerationsCount((prev) => Math.max(0, prev - 1));
|
|
6152
6474
|
}
|
|
@@ -6181,7 +6503,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6181
6503
|
timestamp: Date.now(),
|
|
6182
6504
|
mimeType: "image/jpeg"
|
|
6183
6505
|
};
|
|
6184
|
-
await
|
|
6506
|
+
await _chunkVSHSZEGVjs.hfUploadImage.call(void 0, base64, genId, hfToken);
|
|
6185
6507
|
await hfWriteEvent("image_added", entry);
|
|
6186
6508
|
return [genId];
|
|
6187
6509
|
} catch (e) {
|
|
@@ -6202,7 +6524,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6202
6524
|
setActivePrompt(prompt);
|
|
6203
6525
|
setFocusedNodeId(nodeId);
|
|
6204
6526
|
if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
|
|
6205
|
-
} catch (
|
|
6527
|
+
} catch (e33) {
|
|
6206
6528
|
setActivePrompt("Synthese-Fehler");
|
|
6207
6529
|
} finally {
|
|
6208
6530
|
setIsSynthesizing(false);
|
|
@@ -6275,14 +6597,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6275
6597
|
const { prompt, feedback } = parsePromptResponse(raw);
|
|
6276
6598
|
setActivePrompt(prompt);
|
|
6277
6599
|
setPromptFeedback(feedback);
|
|
6278
|
-
} catch (
|
|
6600
|
+
} catch (e34) {
|
|
6279
6601
|
setActivePrompt("Synthese-Fehler");
|
|
6280
6602
|
} finally {
|
|
6281
6603
|
setIsPromptTabGenerating(false);
|
|
6282
6604
|
}
|
|
6283
6605
|
};
|
|
6284
6606
|
const handleDownloadSingle = async () => {
|
|
6285
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6607
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _200 => _200.base64])) return;
|
|
6286
6608
|
try {
|
|
6287
6609
|
const downloadSrc = currentResult.fullBase64 || currentResult.base64;
|
|
6288
6610
|
const base64Data = downloadSrc.split(",")[1];
|
|
@@ -6298,9 +6620,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6298
6620
|
const reader = new FileReader();
|
|
6299
6621
|
reader.onload = (ev) => {
|
|
6300
6622
|
try {
|
|
6301
|
-
const root = JSON.parse(_optionalChain([ev, 'access',
|
|
6623
|
+
const root = JSON.parse(_optionalChain([ev, 'access', _201 => _201.target, 'optionalAccess', _202 => _202.result]));
|
|
6302
6624
|
const rawTags = root.tags || root;
|
|
6303
|
-
if (!_optionalChain([rawTags, 'optionalAccess',
|
|
6625
|
+
if (!_optionalChain([rawTags, 'optionalAccess', _203 => _203.by_category])) return;
|
|
6304
6626
|
const filtered = {};
|
|
6305
6627
|
const EXCLUDED2 = ["pdf-export", "book.micro-edit-rules"];
|
|
6306
6628
|
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
@@ -6317,7 +6639,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6317
6639
|
};
|
|
6318
6640
|
const handleHfInitialSync = async (onProgress) => {
|
|
6319
6641
|
if (!hfToken || !effectiveNamespace) return;
|
|
6320
|
-
const existingIds = new Set((_optionalChain([hfState, 'optionalAccess',
|
|
6642
|
+
const existingIds = new Set((_optionalChain([hfState, 'optionalAccess', _204 => _204.metadata]) || []).map((m) => m.id));
|
|
6321
6643
|
const gens = galleryItems.filter((g) => g.base64 && g.status === "done" && !existingIds.has(g.id));
|
|
6322
6644
|
const total = gens.length;
|
|
6323
6645
|
onProgress(0, total);
|
|
@@ -6325,7 +6647,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6325
6647
|
for (const gen of gens) {
|
|
6326
6648
|
const raw = gen.base64.includes(",") ? gen.base64.split(",")[1] : gen.base64;
|
|
6327
6649
|
const mimeType = gen.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
|
|
6328
|
-
await
|
|
6650
|
+
await _chunkVSHSZEGVjs.hfUploadImage.call(void 0, raw, gen.id, hfToken, mimeType).catch(() => {
|
|
6329
6651
|
});
|
|
6330
6652
|
const entry = {
|
|
6331
6653
|
id: gen.id,
|
|
@@ -6343,7 +6665,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6343
6665
|
}
|
|
6344
6666
|
};
|
|
6345
6667
|
const mergeWorkspaceTags = (local, remote) => {
|
|
6346
|
-
if (!_optionalChain([remote, 'optionalAccess',
|
|
6668
|
+
if (!_optionalChain([remote, 'optionalAccess', _205 => _205.by_category])) return local;
|
|
6347
6669
|
const merged = {};
|
|
6348
6670
|
const allCategories = /* @__PURE__ */ new Set([...Object.keys(local.by_category), ...Object.keys(remote.by_category)]);
|
|
6349
6671
|
for (const cat of allCategories) {
|
|
@@ -6353,7 +6675,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6353
6675
|
const localValues = new Set(localTags.map((t) => t.value));
|
|
6354
6676
|
const mergedLocal = localTags.map((t) => {
|
|
6355
6677
|
const remote2 = remoteMap.get(t.value);
|
|
6356
|
-
return _optionalChain([remote2, 'optionalAccess',
|
|
6678
|
+
return _optionalChain([remote2, 'optionalAccess', _206 => _206.is_deleted]) ? { ...t, is_deleted: true } : t;
|
|
6357
6679
|
});
|
|
6358
6680
|
const onlyInRemote = remoteTags.filter((t) => !localValues.has(t.value));
|
|
6359
6681
|
merged[cat] = [...mergedLocal, ...onlyInRemote];
|
|
@@ -6361,7 +6683,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6361
6683
|
const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
|
|
6362
6684
|
return { by_category: merged, all };
|
|
6363
6685
|
};
|
|
6364
|
-
if (isFullscreen && _optionalChain([currentResult, 'optionalAccess',
|
|
6686
|
+
if (isFullscreen && _optionalChain([currentResult, 'optionalAccess', _207 => _207.base64])) {
|
|
6365
6687
|
const fsRaw = currentResult.fullBase64 || currentResult.base64;
|
|
6366
6688
|
const fsBase64 = fsRaw.startsWith("data:") ? fsRaw : `data:image/png;base64,${fsRaw}`;
|
|
6367
6689
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
@@ -6475,7 +6797,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6475
6797
|
setHfNamespaceLocal(ns);
|
|
6476
6798
|
try {
|
|
6477
6799
|
localStorage.setItem("aa-hf-namespace", ns);
|
|
6478
|
-
} catch (
|
|
6800
|
+
} catch (e35) {
|
|
6479
6801
|
}
|
|
6480
6802
|
},
|
|
6481
6803
|
className: "px-3 py-1 rounded-lg text-[11px] font-bold transition-colors",
|
|
@@ -6511,7 +6833,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6511
6833
|
)) }),
|
|
6512
6834
|
layoutChoice === "mobile-desktop" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
|
|
6513
6835
|
layoutChoice === "tablet-landscape" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
|
|
6514
|
-
] })
|
|
6836
|
+
] }),
|
|
6837
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, FlowBridgePanel, { appVersion: version, hfToken })
|
|
6515
6838
|
] });
|
|
6516
6839
|
}
|
|
6517
6840
|
if (requireWorkspaceSelection) {
|
|
@@ -6556,7 +6879,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6556
6879
|
);
|
|
6557
6880
|
}
|
|
6558
6881
|
}
|
|
6559
|
-
const szenenPane = szenenPort ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6882
|
+
const szenenPane = szenenPort ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVSHSZEGVjs.SzenenView, { port: szenenPort, contextId: szenenKontextId }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane flow-szenen-pane--empty", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { children: [
|
|
6560
6883
|
"Szenen brauchen einen HF-Token f\xFCr Namespace ",
|
|
6561
6884
|
effectiveNamespace || "(noch nicht bestimmt)",
|
|
6562
6885
|
" \u2014 auf der Flow-Startseite setzen."
|
|
@@ -6575,7 +6898,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6575
6898
|
}, children: [
|
|
6576
6899
|
mobileTab === "labs" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LabsTab, { services: labServices, onResult: (item) => {
|
|
6577
6900
|
const frame = item.frames[0];
|
|
6578
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
6901
|
+
if (_optionalChain([frame, 'optionalAccess', _208 => _208.base64])) {
|
|
6579
6902
|
setCurrentResult(frameToGeneration(frame, item));
|
|
6580
6903
|
setMobileTab("stage");
|
|
6581
6904
|
}
|
|
@@ -6599,7 +6922,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6599
6922
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
6600
6923
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
|
|
6601
6924
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
|
|
6602
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
6925
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _209 => _209.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
6603
6926
|
runningBadge,
|
|
6604
6927
|
activeReferenceThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
|
|
6605
6928
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
@@ -6650,21 +6973,21 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6650
6973
|
setTouchStartX(null);
|
|
6651
6974
|
},
|
|
6652
6975
|
children: [
|
|
6653
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6976
|
+
_optionalChain([currentResult, 'optionalAccess', _210 => _210.status]) === "processing" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-3 opacity-40", children: [
|
|
6654
6977
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
|
|
6655
6978
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[11px] uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
6656
6979
|
] }),
|
|
6657
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6980
|
+
_optionalChain([currentResult, 'optionalAccess', _211 => _211.status]) === "error" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
|
|
6658
6981
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
|
|
6659
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/50 text-[13px]", children: _optionalChain([currentResult, 'access',
|
|
6982
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/50 text-[13px]", children: _optionalChain([currentResult, 'access', _212 => _212.error, 'optionalAccess', _213 => _213.message]) }),
|
|
6660
6983
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleGenerateImage(currentResult.prompt), className: "px-4 py-2 rounded-lg border border-white/20 text-[13px] text-white/70 active:bg-white/10", children: "Erneut versuchen" })
|
|
6661
6984
|
] }),
|
|
6662
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6985
|
+
_optionalChain([currentResult, 'optionalAccess', _214 => _214.status]) === "done" && currentResult.base64 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: currentResult.fullBase64 || currentResult.base64, className: "w-full h-full object-contain" }),
|
|
6663
6986
|
!currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
6664
6987
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
|
|
6665
6988
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
6666
6989
|
] }),
|
|
6667
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6990
|
+
_optionalChain([currentResult, 'optionalAccess', _215 => _215.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: openFullscreen, className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-full bg-black/60 border border-white/10 z-10", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
|
|
6668
6991
|
history.length > 1 && currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
6669
6992
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToPrev, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
6670
6993
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
@@ -6677,7 +7000,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6677
7000
|
]
|
|
6678
7001
|
}
|
|
6679
7002
|
),
|
|
6680
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7003
|
+
_optionalChain([currentResult, 'optionalAccess', _216 => _216.status]) === "done" && currentGroup.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-2 flex gap-1.5 overflow-x-auto pb-1", style: { scrollbarWidth: "none" }, children: currentGroup.map((item) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
6681
7004
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6682
7005
|
"div",
|
|
6683
7006
|
{
|
|
@@ -6720,7 +7043,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6720
7043
|
}
|
|
6721
7044
|
)
|
|
6722
7045
|
] }, item.id)) }),
|
|
6723
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7046
|
+
_optionalChain([currentResult, 'optionalAccess', _217 => _217.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-2 mt-3", children: [
|
|
6724
7047
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { onClick: () => setActivePrompt(currentResult.prompt || ""), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
|
|
6725
7048
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
|
|
6726
7049
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] text-white/60", children: "Prompt" })
|
|
@@ -6742,14 +7065,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6742
7065
|
hfToken && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => refreshHF(), disabled: isHfRefreshing, className: "w-12 flex items-center justify-center text-white/20 active:text-white transition-colors disabled:opacity-30", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `material-symbols-outlined text-[20px]${isHfRefreshing ? " animate-spin" : ""}`, children: "sync" }) })
|
|
6743
7066
|
] }),
|
|
6744
7067
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 overflow-hidden relative", children: [
|
|
6745
|
-
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
7068
|
+
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _218 => _218.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
|
|
6746
7069
|
activeTab === "gallery" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6747
7070
|
MediaLibrary,
|
|
6748
7071
|
{
|
|
6749
7072
|
items: galleryItems,
|
|
6750
7073
|
onImport: async () => {
|
|
6751
7074
|
const media = await onSelectMedia();
|
|
6752
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
7075
|
+
if (!_optionalChain([media, 'optionalAccess', _219 => _219.length])) return;
|
|
6753
7076
|
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
6754
7077
|
},
|
|
6755
7078
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
@@ -6897,7 +7220,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6897
7220
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
6898
7221
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
|
|
6899
7222
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1 } }),
|
|
6900
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
7223
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _220 => _220.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
6901
7224
|
runningBadge,
|
|
6902
7225
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
6903
7226
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
|
|
@@ -6926,7 +7249,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6926
7249
|
]
|
|
6927
7250
|
}
|
|
6928
7251
|
) }),
|
|
6929
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
7252
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _221 => _221.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }) })
|
|
6930
7253
|
] }),
|
|
6931
7254
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
|
|
6932
7255
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -6942,21 +7265,21 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6942
7265
|
setTouchStartX(null);
|
|
6943
7266
|
},
|
|
6944
7267
|
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { height: "100%", width: "100%", borderRadius: 20, border: "1px solid rgba(255,255,255,0.05)", background: "rgba(0,0,0,0.4)", position: "relative", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }, children: [
|
|
6945
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7268
|
+
_optionalChain([currentResult, 'optionalAccess', _222 => _222.status]) === "processing" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12, opacity: 0.4 }, children: [
|
|
6946
7269
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 36 }, children: "hourglass_top" }),
|
|
6947
7270
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { fontSize: 10, color: "rgba(255,255,255,0.6)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
|
|
6948
7271
|
] }),
|
|
6949
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7272
|
+
_optionalChain([currentResult, 'optionalAccess', _223 => _223.status]) === "error" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
6950
7273
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
|
|
6951
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: _optionalChain([currentResult, 'access',
|
|
7274
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: _optionalChain([currentResult, 'access', _224 => _224.error, 'optionalAccess', _225 => _225.message]) }),
|
|
6952
7275
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleGenerateImage(currentResult.prompt), style: { padding: "8px 16px", borderRadius: 8, border: "1px solid rgba(255,255,255,0.2)", fontSize: 11, color: "rgba(255,255,255,0.7)", background: "none", cursor: "pointer", fontFamily: "inherit" }, children: "Erneut versuchen" })
|
|
6953
7276
|
] }),
|
|
6954
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7277
|
+
_optionalChain([currentResult, 'optionalAccess', _226 => _226.status]) === "done" && currentResult.base64 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: currentResult.fullBase64 || currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
|
|
6955
7278
|
!currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
|
|
6956
7279
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
|
|
6957
7280
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
|
|
6958
7281
|
] }),
|
|
6959
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7282
|
+
_optionalChain([currentResult, 'optionalAccess', _227 => _227.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: openFullscreen, style: { position: "absolute", top: 8, right: 8, width: 32, height: 32, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
|
|
6960
7283
|
history.length > 1 && currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
6961
7284
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToPrev, disabled: currentIndex <= 0, style: { position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex <= 0 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
|
|
6962
7285
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, style: { position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex >= history.length - 1 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
|
|
@@ -6969,7 +7292,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6969
7292
|
] })
|
|
6970
7293
|
}
|
|
6971
7294
|
),
|
|
6972
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7295
|
+
_optionalChain([currentResult, 'optionalAccess', _228 => _228.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
|
|
6973
7296
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { onClick: () => setActivePrompt(currentResult.prompt || ""), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
|
|
6974
7297
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
|
|
6975
7298
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Prompt" })
|
|
@@ -7091,7 +7414,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7091
7414
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Ref" })
|
|
7092
7415
|
] }),
|
|
7093
7416
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
7094
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
7417
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _229 => _229.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
7095
7418
|
runningBadge,
|
|
7096
7419
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PillButton, { variant: "solid", icon: "bolt", disabled: !activePrompt.trim(), onClick: () => handleGenerateBatch(), children: "Generieren" })
|
|
7097
7420
|
] })
|
|
@@ -7103,7 +7426,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7103
7426
|
] }) }),
|
|
7104
7427
|
middlePanel === "szenen" ? szenenPane : middlePanel === "labs" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LabsTab, { services: labServices, onResult: (item) => {
|
|
7105
7428
|
const frame = item.frames[0];
|
|
7106
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
7429
|
+
if (_optionalChain([frame, 'optionalAccess', _230 => _230.base64])) setCurrentResult(frameToGeneration(frame, item));
|
|
7107
7430
|
} }) }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 overflow-hidden flex flex-col", children: [
|
|
7108
7431
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-4 opacity-40", children: [
|
|
7109
7432
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
|
|
@@ -7112,7 +7435,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7112
7435
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
7113
7436
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
|
|
7114
7437
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
7115
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/60 text-[12px] leading-relaxed", children: _optionalChain([currentResult, 'access',
|
|
7438
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/60 text-[12px] leading-relaxed", children: _optionalChain([currentResult, 'access', _231 => _231.error, 'optionalAccess', _232 => _232.message]) })
|
|
7116
7439
|
] }),
|
|
7117
7440
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
7118
7441
|
] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
@@ -7126,7 +7449,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7126
7449
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
7127
7450
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
7128
7451
|
] }) }) }),
|
|
7129
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7452
|
+
_optionalChain([currentResult, 'optionalAccess', _233 => _233.status]) === "done" && currentGroup.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-6 pb-4 shrink-0 flex gap-2 overflow-x-auto", style: { scrollbarWidth: "none" }, children: currentGroup.map((item) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
7130
7453
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
7131
7454
|
"div",
|
|
7132
7455
|
{
|
|
@@ -7207,14 +7530,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7207
7530
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
|
|
7208
7531
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
|
|
7209
7532
|
] }) }),
|
|
7210
|
-
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
7533
|
+
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _234 => _234.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
|
|
7211
7534
|
activeTab === "gallery" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
7212
7535
|
MediaLibrary,
|
|
7213
7536
|
{
|
|
7214
7537
|
items: galleryItems,
|
|
7215
7538
|
onImport: async () => {
|
|
7216
7539
|
const media = await onSelectMedia();
|
|
7217
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
7540
|
+
if (!_optionalChain([media, 'optionalAccess', _235 => _235.length])) return;
|
|
7218
7541
|
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
7219
7542
|
},
|
|
7220
7543
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
@@ -7265,7 +7588,7 @@ function FaApp({
|
|
|
7265
7588
|
});
|
|
7266
7589
|
}, [serverBaseUrl]);
|
|
7267
7590
|
const wrappedPrompt = _react.useMemo.call(void 0,
|
|
7268
|
-
() =>
|
|
7591
|
+
() => _chunkVSHSZEGVjs.alsFlowTextZugang.call(void 0, onGeneratePrompt),
|
|
7269
7592
|
[onGeneratePrompt]
|
|
7270
7593
|
);
|
|
7271
7594
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -7370,7 +7693,7 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7370
7693
|
};
|
|
7371
7694
|
};
|
|
7372
7695
|
const applyWriteResult = (sliceId, result, savedData, signal) => {
|
|
7373
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7696
|
+
if (_optionalChain([signal, 'optionalAccess', _236 => _236.aborted])) {
|
|
7374
7697
|
patchMeta(sliceId, { saveState: "idle" });
|
|
7375
7698
|
return result;
|
|
7376
7699
|
}
|
|
@@ -7398,8 +7721,8 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7398
7721
|
const requestId = _nullishCoalesce(externalRequestId, () => ( nextRequestId()));
|
|
7399
7722
|
patchMeta(sliceId, { loadRequestId: requestId, saveState: "restoring" });
|
|
7400
7723
|
const result = await persistence.load(workspaceId, descriptor, _nullishCoalesce(signal, () => ( new AbortController().signal)));
|
|
7401
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7402
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7724
|
+
if (_optionalChain([signal, 'optionalAccess', _237 => _237.aborted]) || _optionalChain([get, 'call', _238 => _238(), 'access', _239 => _239.meta, 'access', _240 => _240[sliceId], 'optionalAccess', _241 => _241.loadRequestId]) !== requestId) {
|
|
7725
|
+
if (_optionalChain([signal, 'optionalAccess', _242 => _242.aborted]) && _optionalChain([get, 'call', _243 => _243(), 'access', _244 => _244.meta, 'access', _245 => _245[sliceId], 'optionalAccess', _246 => _246.loadRequestId]) === requestId) {
|
|
7403
7726
|
patchMeta(sliceId, { saveState: "idle", loadRequestId: null });
|
|
7404
7727
|
}
|
|
7405
7728
|
return result;
|
|
@@ -7434,7 +7757,7 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7434
7757
|
},
|
|
7435
7758
|
async resetSlice(sliceId, signal, options) {
|
|
7436
7759
|
const contract = requireContract(sliceId);
|
|
7437
|
-
if (get().meta[sliceId].dirty && !_optionalChain([options, 'optionalAccess',
|
|
7760
|
+
if (get().meta[sliceId].dirty && !_optionalChain([options, 'optionalAccess', _247 => _247.confirmed])) {
|
|
7438
7761
|
throw new Error(`Reset for slice ${sliceId} requires confirmation while unsaved changes exist`);
|
|
7439
7762
|
}
|
|
7440
7763
|
const defaultData = contract.createDefault();
|
|
@@ -7487,7 +7810,7 @@ function createInMemoryWorkspacePersistence(now = () => Date.now()) {
|
|
|
7487
7810
|
}
|
|
7488
7811
|
const saved = {
|
|
7489
7812
|
...clone(slice),
|
|
7490
|
-
revision: (_nullishCoalesce(_optionalChain([current, 'optionalAccess',
|
|
7813
|
+
revision: (_nullishCoalesce(_optionalChain([current, 'optionalAccess', _248 => _248.revision]), () => ( 0))) + 1,
|
|
7491
7814
|
updatedAt: now(),
|
|
7492
7815
|
...resetAt !== void 0 ? { resetAt } : {}
|
|
7493
7816
|
};
|
|
@@ -7568,7 +7891,7 @@ function createPersistenceCoordinator({
|
|
|
7568
7891
|
if (disposed) return;
|
|
7569
7892
|
const runtime = runtimeOf(sliceId);
|
|
7570
7893
|
const meta = store.getState().meta[sliceId];
|
|
7571
|
-
if (!_optionalChain([meta, 'optionalAccess',
|
|
7894
|
+
if (!_optionalChain([meta, 'optionalAccess', _249 => _249.dirty])) return;
|
|
7572
7895
|
if (meta.saveState === "restoring" || meta.saveState === "saving") {
|
|
7573
7896
|
runtime.pendingSave = true;
|
|
7574
7897
|
return;
|
|
@@ -7596,7 +7919,7 @@ function createPersistenceCoordinator({
|
|
|
7596
7919
|
return {
|
|
7597
7920
|
async load(sliceId) {
|
|
7598
7921
|
const runtime = runtimeOf(sliceId);
|
|
7599
|
-
_optionalChain([runtime, 'access',
|
|
7922
|
+
_optionalChain([runtime, 'access', _250 => _250.loadController, 'optionalAccess', _251 => _251.abort, 'call', _252 => _252()]);
|
|
7600
7923
|
runtime.loadController = new AbortController();
|
|
7601
7924
|
const controller = runtime.loadController;
|
|
7602
7925
|
try {
|
|
@@ -7624,8 +7947,8 @@ function createPersistenceCoordinator({
|
|
|
7624
7947
|
disposed = true;
|
|
7625
7948
|
for (const runtime of runtimes.values()) {
|
|
7626
7949
|
clearTimer(runtime);
|
|
7627
|
-
_optionalChain([runtime, 'access',
|
|
7628
|
-
_optionalChain([runtime, 'access',
|
|
7950
|
+
_optionalChain([runtime, 'access', _253 => _253.loadController, 'optionalAccess', _254 => _254.abort, 'call', _255 => _255()]);
|
|
7951
|
+
_optionalChain([runtime, 'access', _256 => _256.saveController, 'optionalAccess', _257 => _257.abort, 'call', _258 => _258()]);
|
|
7629
7952
|
runtime.pendingSave = false;
|
|
7630
7953
|
}
|
|
7631
7954
|
runtimes.clear();
|
|
@@ -7729,7 +8052,7 @@ function parseLegacyLibraryFilters(source, knownTagIds) {
|
|
|
7729
8052
|
return null;
|
|
7730
8053
|
}).filter((id) => id !== null && knownTagIds.has(id));
|
|
7731
8054
|
}
|
|
7732
|
-
} catch (
|
|
8055
|
+
} catch (e36) {
|
|
7733
8056
|
tagIds = [];
|
|
7734
8057
|
}
|
|
7735
8058
|
}
|
|
@@ -7740,7 +8063,7 @@ function parseLegacyLibraryFilters(source, knownTagIds) {
|
|
|
7740
8063
|
if (Array.isArray(parsed)) {
|
|
7741
8064
|
recentFilterTagIds = parsed.filter((entry) => typeof entry === "string" || typeof entry === "number").map((entry) => String(entry)).filter((id) => knownTagIds.has(id)).slice(0, 5);
|
|
7742
8065
|
}
|
|
7743
|
-
} catch (
|
|
8066
|
+
} catch (e37) {
|
|
7744
8067
|
recentFilterTagIds = [];
|
|
7745
8068
|
}
|
|
7746
8069
|
}
|
|
@@ -7779,9 +8102,9 @@ function hatNavigationsziele(zugehoerigkeit) {
|
|
|
7779
8102
|
var kennung = (wert) => typeof wert === "string" && wert.trim().length > 0;
|
|
7780
8103
|
var kurz = (id) => id.slice(0, 8);
|
|
7781
8104
|
function zugehoerigkeitOf(item) {
|
|
7782
|
-
const runId = _optionalChain([item, 'optionalAccess',
|
|
8105
|
+
const runId = _optionalChain([item, 'optionalAccess', _259 => _259.szenen, 'optionalAccess', _260 => _260.prompt_run_id]);
|
|
7783
8106
|
if (!kennung(runId)) return null;
|
|
7784
|
-
const links = _nullishCoalesce(_optionalChain([item, 'optionalAccess',
|
|
8107
|
+
const links = _nullishCoalesce(_optionalChain([item, 'optionalAccess', _261 => _261.szenen_links]), () => ( null));
|
|
7785
8108
|
if (!links || links.prompt_run_id !== runId) {
|
|
7786
8109
|
return {
|
|
7787
8110
|
run: null,
|
|
@@ -7812,15 +8135,15 @@ function zugehoerigkeitOf(item) {
|
|
|
7812
8135
|
return { run, scene, hinweis: null };
|
|
7813
8136
|
}
|
|
7814
8137
|
function zugehoerigkeitenOf(item) {
|
|
7815
|
-
const szenen = _optionalChain([item, 'optionalAccess',
|
|
8138
|
+
const szenen = _optionalChain([item, 'optionalAccess', _262 => _262.szenen]);
|
|
7816
8139
|
if (!szenen) return [];
|
|
7817
8140
|
const laeufe = [];
|
|
7818
8141
|
const merken = (id) => {
|
|
7819
8142
|
if (kennung(id) && !laeufe.includes(id)) laeufe.push(id);
|
|
7820
8143
|
};
|
|
7821
8144
|
merken(szenen.prompt_run_id);
|
|
7822
|
-
for (const run of _nullishCoalesce(szenen.runs, () => ( []))) merken(_optionalChain([run, 'optionalAccess',
|
|
7823
|
-
const linkFuer = (runId) => _nullishCoalesce((_nullishCoalesce(_optionalChain([item, 'optionalAccess',
|
|
8145
|
+
for (const run of _nullishCoalesce(szenen.runs, () => ( []))) merken(_optionalChain([run, 'optionalAccess', _263 => _263.prompt_run_id]));
|
|
8146
|
+
const linkFuer = (runId) => _nullishCoalesce((_nullishCoalesce(_optionalChain([item, 'optionalAccess', _264 => _264.szenen_run_links]), () => ( []))).find((l) => l.prompt_run_id === runId), () => ( (_optionalChain([item, 'optionalAccess', _265 => _265.szenen_links]) && item.szenen_links.prompt_run_id === runId ? item.szenen_links : null)));
|
|
7824
8147
|
const ergebnis = [];
|
|
7825
8148
|
for (const runId of laeufe) {
|
|
7826
8149
|
const z = zugehoerigkeitOf({ szenen: { prompt_run_id: runId }, szenen_links: linkFuer(runId) });
|
|
@@ -7966,7 +8289,7 @@ function parseLegacyRecentTags(raw) {
|
|
|
7966
8289
|
}
|
|
7967
8290
|
return null;
|
|
7968
8291
|
}).filter((entry) => entry !== null).slice(0, 10);
|
|
7969
|
-
} catch (
|
|
8292
|
+
} catch (e38) {
|
|
7970
8293
|
return [];
|
|
7971
8294
|
}
|
|
7972
8295
|
}
|
|
@@ -8093,4 +8416,10 @@ async function runTagsLegacyImport(options) {
|
|
|
8093
8416
|
|
|
8094
8417
|
|
|
8095
8418
|
|
|
8096
|
-
|
|
8419
|
+
|
|
8420
|
+
|
|
8421
|
+
|
|
8422
|
+
|
|
8423
|
+
|
|
8424
|
+
|
|
8425
|
+
exports.AvatarArchitectApp = AvatarArchitectApp; exports.CURRENT_TAG_EVENT_VERSION = CURRENT_TAG_EVENT_VERSION; exports.CollapsibleCard = CollapsibleCard; exports.CompactDropdown = CompactDropdown; exports.FLOW_PROBE_MARKER = FLOW_PROBE_MARKER; exports.FLOW_PROBE_REQUEST = FLOW_PROBE_REQUEST; exports.FaApp = FaApp; exports.FaToolsBadge = FaToolsBadge; exports.FlowBridgePanel = FlowBridgePanel; exports.FlowWorkspacePicker = FlowWorkspacePicker; exports.GLOBAL_STYLES = GLOBAL_STYLES; exports.HfMediaSyncTab = HfMediaSyncTab; exports.HistoryPanel = HistoryPanel; exports.InspectPanel = InspectPanel; exports.LIBRARY_CUTOVER_MARKER = LIBRARY_CUTOVER_MARKER; exports.LIBRARY_SLICE_SCHEMA_VERSION = LIBRARY_SLICE_SCHEMA_VERSION; exports.LIB_VERSION = version; exports.LabBlend = LabBlend; exports.LabCompare = LabCompare; exports.LabFrameExtractor = LabFrameExtractor; exports.LabImagePicker = LabImagePicker; exports.LabLoop = LabLoop; exports.LabRemix = LabRemix; exports.LabsTab = LabsTab; exports.LibraryView = LibraryView; exports.ListView = ListView; exports.MediaLibrary = MediaLibrary; exports.PillButton = PillButton; exports.PromptTab = PromptTab; exports.SCOPE_MAP = SCOPE_MAP; exports.SectionLabel = SectionLabel; exports.ServerTab = ServerTab; exports.SetupPanel = SetupPanel; exports.TAGS_CUTOVER_MARKER = TAGS_CUTOVER_MARKER; exports.TAGS_SLICE_SCHEMA_VERSION = TAGS_SLICE_SCHEMA_VERSION; exports.TagBaseSection = TagBaseSection; exports.TagManager = TagManager; exports.TagManagerPanel = TagManagerPanel; exports.ZugehoerigkeitLinks = ZugehoerigkeitLinks; exports.autoLabel = autoLabel; exports.buildBlendInstruction = buildBlendInstruction; exports.buildCompareInstruction = buildCompareInstruction; exports.buildFallbackPrompt = buildFallbackPrompt; exports.buildGenerationPrompt = buildGenerationPrompt; exports.buildImageGenerationOptions = buildImageGenerationOptions; exports.buildLoopInstruction = buildLoopInstruction; exports.buildPromptTabPayload = buildPromptTabPayload; exports.buildReferenceImageMediaIds = buildReferenceImageMediaIds; exports.buildRemixInstruction = buildRemixInstruction; exports.buildScanInstruction = buildScanInstruction; exports.cleanAiResponse = cleanAiResponse; exports.createFaStore = createFaStore; exports.createFlowBridgeClient = createFlowBridgeClient; exports.createFlowServices = createFlowServices; exports.createInMemoryLibraryDataSource = createInMemoryLibraryDataSource; exports.createInMemoryWorkspacePersistence = createInMemoryWorkspacePersistence; exports.createLibraryDefault = createLibraryDefault; exports.createPersistenceCoordinator = createPersistenceCoordinator; exports.createTagCreatedEvent = createTagCreatedEvent; exports.createTagUpdatedEvent = createTagUpdatedEvent; exports.createTagsDefault = createTagsDefault; exports.deriveTagBaseWorkspaceTags = deriveTagBaseWorkspaceTags; exports.deriveTagViewModel = deriveTagViewModel; exports.executeFlowProbeBundle = executeFlowProbeBundle; exports.formatTreeToMarkdown = formatTreeToMarkdown; exports.frameToGeneration = frameToGeneration; exports.getFormattedTimestamp = getFormattedTimestamp; exports.getHFToken = _chunkVSHSZEGVjs.getHFToken; exports.getSessionClientId = _chunkVSHSZEGVjs.getSessionClientId; exports.groupGenerationsToLabItems = groupGenerationsToLabItems; exports.hatNavigationsziele = hatNavigationsziele; exports.hfBatchArchive = _chunkVSHSZEGVjs.hfBatchArchive; exports.hfBootstrapFromLegacy = _chunkVSHSZEGVjs.hfBootstrapFromLegacy; exports.hfListDir = _chunkVSHSZEGVjs.hfListDir; exports.hfLoadImageAsBase64 = _chunkVSHSZEGVjs.hfLoadImageAsBase64; exports.hfUploadImage = _chunkVSHSZEGVjs.hfUploadImage; exports.hfUploadSmallFile = _chunkVSHSZEGVjs.hfUploadSmallFile; exports.injectXMPMetadata = injectXMPMetadata; exports.interpretSdkError = interpretSdkError; exports.libraryContract = libraryContract; exports.libraryReactDescriptor = libraryReactDescriptor; exports.listCategories = listCategories; exports.loadHFState = _chunkVSHSZEGVjs.loadHFState; exports.loadPendingEvents = _chunkVSHSZEGVjs.loadPendingEvents; exports.loadTagBase = loadTagBase; exports.parseLegacyLibraryFilters = parseLegacyLibraryFilters; exports.parseLegacyRecentTags = parseLegacyRecentTags; exports.parsePromptFile = parsePromptFile; exports.parsePromptResponse = parsePromptResponse; exports.readFlowProbeBundle = readFlowProbeBundle; exports.runLegacyMigration = runLegacyMigration; exports.runLibraryLegacyImport = runLibraryLegacyImport; exports.runTagsLegacyImport = runTagsLegacyImport; exports.setHFToken = _chunkVSHSZEGVjs.setHFToken; exports.tagsContract = tagsContract; exports.tagsReactDescriptor = tagsReactDescriptor; exports.tsFromEventPath = _chunkVSHSZEGVjs.tsFromEventPath; exports.useFaSlice = useFaSlice; exports.useFaSliceMeta = useFaSliceMeta; exports.useHFState = useHFState; exports.useKeyboardNavigation = useKeyboardNavigation; exports.useOnClickOutside = useOnClickOutside; exports.useTagBase = useTagBase; exports.validateTagBaseSelection = validateTagBaseSelection; exports.writeHFEvent = _chunkVSHSZEGVjs.writeHFEvent; exports.writeTagEvent = writeTagEvent; exports.zugehoerigkeitOf = zugehoerigkeitOf; exports.zugehoerigkeitenOf = zugehoerigkeitenOf;
|