diff --git a/assets/official-signature-placeholder.png b/assets/official-signature-placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..74a60188d4ec6dca162549dd63919a5a3a506e1b
Binary files /dev/null and b/assets/official-signature-placeholder.png differ
diff --git a/rollup.config.js b/rollup.config.js
index db470c6b5d7c06de5f3f4806ec2758b07a67de11..2befe42b7faecde74c150285dc9c7f472c1511e4 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -256,7 +256,7 @@ Dependencies:
                 {src: 'node_modules/vpu-common/src/spinner.js', dest: 'dist/local/' + pkg.name, rename: 'spinner.js'},
                 {src: 'node_modules/vpu-common/misc/browser-check.js', dest: 'dist/local/' + pkg.name, rename: 'browser-check.js'},
                 {src: 'assets/icon-*.png', dest: 'dist/local/' + pkg.name},
-                {src: 'assets/signature-placeholder.png', dest: 'dist/local/' + pkg.name},
+                {src: 'assets/*-placeholder.png', dest: 'dist/local/' + pkg.name},
                 {src: 'assets/manifest.json', dest: 'dist', rename: pkg.name + '.manifest.json'},
                 {src: 'assets/*.metadata.json', dest: 'dist'},
                 {src: 'node_modules/vpu-common/assets/icons/*.svg', dest: 'dist/local/vpu-common/icons'},
diff --git a/src/i18n/de/translation.json b/src/i18n/de/translation.json
index eab8194ad5e737f6c413cf3cc9888618cbaaf588..eebc71a6a136da980ce571c960058881d04ec542 100644
--- a/src/i18n/de/translation.json
+++ b/src/i18n/de/translation.json
@@ -2,6 +2,22 @@
   "official-pdf-upload": {
     "upload-field-label": "PDF-Dokumente zum Signieren hochladen",
     "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente per Drag & Drop oder per Direktauswahl hochladen",
+    "current-signing-process-label": "Aktueller Signaturprozess",
+    "queued-files-label": "Dokumente in der Warteschlange",
+    "queued-files-empty1": "Kein Dokument in der Warteschlange",
+    "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen",
+    "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen",
+    "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen",
+    "clear-all": "Alle entfernen",
+    "start-signing-process-button": "Signatur starten",
+    "stop-signing-process-button": "Signieren unterbrechen",
+    "show-preview": "Dokument anzeigen",
+    "positioning-automatic": "Automatisch",
+    "positioning-manual": "Manuell",
+    "close-preview": "Dokumentansicht schließen",
+    "preview-label": "Dokumentenansicht",
+    "start-signing-process-button-running-title": "Signaturvorgang läuft gerade",
+    "remove-current-file-button-title": "Aktuellen Signaturprozess abbrechen",
     "signed-files-label": "Signierte Dokumente",
     "download-zip-button": "Als ZIP Datei herunterladen",
     "download-zip-button-tooltip": "Alle signierten Dokumente als ZIP Datei herunterladen",
@@ -11,7 +27,11 @@
     "re-upload-file-button-title": "Erneut hochladen",
     "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verarbeitet...",
     "re-upload-all-button": "Alle erneut hochladen",
-    "re-upload-all-button-title": "Alle fehlgeschlagen Uploads erneut hochladen"
+    "re-upload-all-button-title": "Alle fehlgeschlagen Uploads erneut hochladen",
+    "signature-placement-label": "Signatur platzieren",
+    "positioning": "Positionierung",
+    "file-label": "Dokument",
+    "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit."
   },
   "qualified-pdf-upload": {
     "upload-field-label": "PDF-Dokumente zum Signieren hochladen",
diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json
index 60d33f23528b6fbd4145480db8e5ac67c813c42a..b2036da7294dcdc4e37caa14d61e5ec44b857ff4 100644
--- a/src/i18n/en/translation.json
+++ b/src/i18n/en/translation.json
@@ -2,6 +2,22 @@
   "official-pdf-upload": {
     "upload-field-label": "Upload PDF-files to sign",
     "upload-area-text": "In this area you can upload PDF-files via Drag & Drop or by selecting them directly",
+    "current-signing-process-label": "Current signing process",
+    "queued-files-label": "Queued documents",
+    "queued-files-empty1": "No queued documents",
+    "queued-files-empty2": "You can now upload more documents",
+    "remove-failed-file-button-title": "Remove failed document",
+    "remove-queued-file-button-title": "Remove document from queue",
+    "clear-all": "Clear all",
+    "start-signing-process-button": "Start signing",
+    "stop-signing-process-button": "Stop signing",
+    "show-preview": "Show document",
+    "positioning-automatic": "Automatic",
+    "positioning-manual": "Manual",
+    "close-preview": "Close preview",
+    "preview-label": "Document view",
+    "start-signing-process-button-running-title": "Signing process running",
+    "remove-current-file-button-title": "Cancel current signing process",
     "signed-files-label": "Signed files",
     "download-zip-button": "Download ZIP",
     "download-zip-button-tooltip": "Download all signed files as ZIP file",
@@ -11,7 +27,11 @@
     "re-upload-file-button-title": "Upload again",
     "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...",
     "re-upload-all-button": "Upload all",
-    "re-upload-all-button-title": "Upload all failed uploads again"
+    "re-upload-all-button-title": "Upload all failed uploads again",
+    "signature-placement-label": "Place signature",
+    "positioning": "Positioning",
+    "file-label": "document",
+    "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded."
   },
   "qualified-pdf-upload": {
     "upload-field-label": "Upload PDF-documents to sign",
diff --git a/src/vpu-official-signature-pdf-upload.js b/src/vpu-official-signature-pdf-upload.js
index 69c07d2c754039fa00bf39381d6448d6148b44c0..2a1274521613b6544f7570c218cb68608323f64e 100644
--- a/src/vpu-official-signature-pdf-upload.js
+++ b/src/vpu-official-signature-pdf-upload.js
@@ -3,15 +3,16 @@ import {humanFileSize} from 'vpu-common/i18next.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import VPUSignatureLitElement from "./vpu-signature-lit-element";
+import {PdfPreview} from "./vpu-pdf-preview";
 import * as commonUtils from 'vpu-common/utils';
-import {Icon, MiniSpinner, Button} from 'vpu-common';
 import * as utils from './utils';
-import JSZip from 'jszip/dist/jszip.js';
+import {Icon, MiniSpinner, Button} from 'vpu-common';
 import FileSaver from 'file-saver';
 import * as commonStyles from 'vpu-common/styles';
 import {classMap} from 'lit-html/directives/class-map.js';
 import {FileUpload} from 'vpu-file-upload';
 import JSONLD from "vpu-common/jsonld";
+import {TextSwitch} from './textswitch.js';
 
 const i18n = createI18nInstance();
 
@@ -20,24 +21,45 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
         super();
         this.lang = i18n.language;
         this.entryPointUrl = commonUtils.getAPiUrl();
+
         this.signedFiles = [];
         this.signedFilesCount = 0;
         this.errorFiles = [];
         this.errorFilesCount = 0;
         this.uploadInProgress = false;
+        this.queueingInProgress = false;
         this.uploadStatusFileName = "";
         this.uploadStatusText = "";
+        this.currentFile = {};
+        this.currentFileName = "";
+        this.currentFilePlacementMode = "";
+        this.currentFileSignaturePlacement = {};
+        this.queueBlockEnabled = false;
+        this.queuedFiles = [];
+        this.queuedFilesCount = 0;
+        this.signingProcessEnabled = false;
+        this.signingProcessActive = false;
+        this.signaturePlacementInProgress = false;
+        this.withSigBlock = false;
+        this.queuedFilesSignaturePlacements = [];
+        this.queuedFilesPlacementModes = [];
+        this.currentPreviewQueueKey = '';
 
         // will be set in function update
+
         this.signingUrl = "";
+
+
     }
 
     static get scopedElements() {
         return {
           'vpu-icon': Icon,
           'vpu-fileupload': FileUpload,
+          'vpu-pdf-preview': PdfPreview,
           'vpu-mini-spinner': MiniSpinner,
           'vpu-button': Button,
+          'vpu-textswitch': TextSwitch,
         };
     }
 
@@ -47,31 +69,300 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
             entryPointUrl: { type: String, attribute: 'entry-point-url' },
             signedFiles: { type: Array, attribute: false },
             signedFilesCount: { type: Number, attribute: false },
+            queuedFilesCount: { type: Number, attribute: false },
             errorFiles: { type: Array, attribute: false },
             errorFilesCount: { type: Number, attribute: false },
             uploadInProgress: { type: Boolean, attribute: false },
+            queueingInProgress: { type: Boolean, attribute: false },
             uploadStatusFileName: { type: String, attribute: false },
             uploadStatusText: { type: String, attribute: false },
+
+            signingProcessEnabled: { type: Boolean, attribute: false },
+            signingProcessActive: { type: Boolean, attribute: false },
+            queueBlockEnabled: { type: Boolean, attribute: false },
+            currentFile: { type: Object, attribute: false },
+            currentFileName: { type: String, attribute: false },
+            signaturePlacementInProgress: { type: Boolean, attribute: false },
+            withSigBlock: { type: Boolean, attribute: false },
+            isSignaturePlacement: { type: Boolean, attribute: false },
         };
     }
 
     connectedCallback() {
         super.connectedCallback();
+        // needs to be called in a function to get the variable scope of "this"
+        setInterval(() => { this.handleQueuedFiles(); }, 1000);
+
+
+
+
+
+
+
+
+    }
+
+    /* disconnectedCallback()
+
+
+
+
+
+    */
+
+    onQueuedFilesChanged(ev) {
+        const detail = ev.detail;
+        if (!this.queueBlockEnabled && detail.queuedFilesCount)
+            this.queueBlockEnabled = true;
+        this.queuedFiles = detail.queuedFiles;
+        this.queuedFilesCount = detail.queuedFilesCount;
+    }
+
+    /**
+     * Processes queued files
+     */
+    async handleQueuedFiles() {
+
+        this.endSigningProcessIfQueueEmpty();
+
+        if (this.queuedFilesCount === 0) {
+            // reset signingProcessEnabled button
+            this.signingProcessEnabled = false;
+
+            return;
+        }
+
+        if (!this.signingProcessEnabled || this.uploadInProgress) {
+            return;
+        }
+
+        this.signaturePlacementInProgress = false;
+
+        const key = Object.keys(this.queuedFiles)[0];
+
+        // take the file off the queue
+        let file = this.takeFileFromQueue(key);
+        this.currentFile = file;
+
+        // set placement mode and parameters to restore them when canceled
+        this.currentFilePlacementMode = this.queuedFilesPlacementModes[key];
+        this.currentFileSignaturePlacement = this.queuedFilesSignaturePlacements[key];
+
+        this.uploadInProgress = true;
+        let params = {};
+
+        // prepare parameters to tell PDF-AS where and how the signature should be placed
+        if (this.queuedFilesPlacementModes[key] === "manual") {
+            const data = this.queuedFilesSignaturePlacements[key];
+
+            if (data !== undefined) {
+                let angle = data.angle;
+                let bottom = data.bottom;
+                let left = data.left;
+
+                if (angle !== 0) {
+                    // attempt to adapt positioning in the rotated states to fit PDF-AS
+                    switch (angle) {
+                        case 90:
+                            // 321 / 118;
+                            bottom += data.width / 2.72034;
+                            left -= data.width / 2.72034;
+                            break;
+                        case 180:
+                            // 321 / 237;
+                            bottom += data.width / 1.3544;
+                            break;
+                        case 270:
+                            left += data.height;
+                            bottom += data.height;
+                            break;
+                    }
+
+                    // adapt rotation to fit PDF-AS
+                    const rotations = {0: 0, 90: 270, 180: 180, 270: 90};
+                    angle = rotations[data.angle];
+                }
+
+                params = {
+                    y: Math.round(bottom),
+                    x: Math.round(left),
+                    r: angle,
+                    w: Math.round(data.width), // only width, no "height" allowed in PDF-AS
+                    p: data.currentPage
+                };
+            }
+        }
+
+        await this._("#file-upload").uploadFile(file, params);
+        this.uploadInProgress = false;
+    }
+
+    storePDFData(event) {
+        const data = event.detail;
+
+        this.queuedFilesSignaturePlacements[this.currentPreviewQueueKey] = data;
+        this.signaturePlacementInProgress = false;
+    }
+
+    /**
+     * Called when preview is "canceled"
+     *
+     * @param event
+     */
+    hidePDF(event) {
+        // reset placement mode to "auto" if no placement was confirmed previously
+        if (this.queuedFilesSignaturePlacements[this.currentPreviewQueueKey] === undefined) {
+            this.queuedFilesPlacementModes[this.currentPreviewQueueKey] = "auto";
+        }
+
+        this.signaturePlacementInProgress = false;
+    }
+
+    queuePlacementSwitch(key, name) {
+        this.queuedFilesPlacementModes[key] = name;
+        console.log(name);
+
+        if (name === "manual") {
+            this.showPreview(key, true);
+        } else if (this.currentPreviewQueueKey === key) {
+            this.signaturePlacementInProgress = false;
+        }
+    }
+
+    /**
+     * Decides if the "beforeunload" event needs to be canceled
+     *
+     * @param event
+     */
+    onReceiveBeforeUnload(event) {
+        // we don't need to stop if there are no signed files
+        if (this.signedFilesCount === 0) {
+            return;
+        }
+
+        // we need to handle custom events ourselves
+        if (!event.isTrusted) {
+            // note that this only works with custom event since calls of "confirm" are ignored
+            // in the non-custom event, see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
+            const result = confirm(i18n.t('official-pdf-upload.confirm-page-leave'));
+
+            // don't stop the page leave if the user wants to leave
+            if (result) {
+                return;
+            }
+        }
+
+        // Cancel the event as stated by the standard
+        event.preventDefault();
+
+        // Chrome requires returnValue to be set
+        event.returnValue = '';
+    }
+
+    /* onReceiveIframeMessage(event)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    */
+
+    endSigningProcessIfQueueEmpty() {
+        if (this.queuedFilesCount === 0 && this.signingProcessActive) {
+            this.signingProcessActive = false;
+        }
     }
 
     /**
      * @param ev
      */
     onAllUploadStarted(ev) {
-        console.log("Start upload process!");
-        this.uploadInProgress = true;
+        console.log("Start queuing process!");
+        this.queueingInProgress = true;
+    }
+
+    /**
+     * @param ev
+     */
+    onAllUploadFinished(ev) {
+        console.log("Finished queuing process!");
+        this.queueingInProgress = false;
     }
 
     /**
      * @param ev
      */
     onFileUploadStarted(ev) {
-        console.log(ev);
         this.uploadStatusFileName = ev.detail.fileName;
         this.uploadStatusText = i18n.t('official-pdf-upload.upload-status-file-text', {
             fileName: ev.detail.fileName,
@@ -79,29 +370,41 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
         });
     }
 
+    addToErrorFiles(file) {
+        this.endSigningProcessIfQueueEmpty();
+
+        // this doesn't seem to trigger an update() execution
+        this.errorFiles[Math.floor(Math.random() * 1000000)] = file;
+        // this triggers the correct update() execution
+        this.errorFilesCount++;
+
+        if (window._paq !== undefined) {
+            window._paq.push(['trackEvent', 'officiallySigning', 'SigningFailed', file.json["hydra:description"]]);
+        }
+    }
+
     /**
      * @param ev
      */
     onFileUploadFinished(ev) {
         if (ev.detail.status !== 201) {
-            // this doesn't seem to trigger an update() execution
-            this.errorFiles[Math.floor(Math.random() * 1000000)] = ev.detail;
-            // this triggers the correct update() execution
-            this.errorFilesCount++;
+            this.addToErrorFiles(ev.detail);
         } else if (ev.detail.json["@type"] === "http://schema.org/MediaObject" ) {
             // this doesn't seem to trigger an update() execution
             this.signedFiles.push(ev.detail.json);
             // this triggers the correct update() execution
             this.signedFilesCount++;
-        }
-    }
 
-    /**
-     * @param ev
-     */
-    onAllUploadFinished(ev) {
-        console.log("Finished upload process!");
-        this.uploadInProgress = false;
+
+            const entryPoint = data.json;
+            this.currentFileName = entryPoint.name;
+
+
+
+
+
+            this.endSigningProcessIfQueueEmpty();
+        }
     }
 
     update(changedProperties) {
@@ -113,12 +416,13 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
                 case "entryPointUrl":
                     JSONLD.initialize(this.entryPointUrl, (jsonld) => {
                         const apiUrlBase = jsonld.getApiUrlForEntityName("OfficiallySignedDocument");
+
                         this.signingUrl = apiUrlBase + "/sign";
                     });
                     break;
             }
 
-            console.log(propName, oldValue);
+            // console.log(propName, oldValue);
         });
 
         super.update(changedProperties);
@@ -131,8 +435,9 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
     /**
      * Download signed pdf-files as zip
      */
-    zipDownloadClickHandler() {
+    async zipDownloadClickHandler() {
         // see: https://stuk.github.io/jszip/
+        let JSZip = (await import('jszip/dist/jszip.js')).default;
         let zip = new JSZip();
         const that = this;
         let fileNames = [];
@@ -150,12 +455,9 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
             zip.file(fileName, utils.getPDFFileBase64Content(file), {base64: true});
         });
 
-        zip.generateAsync({type:"blob"})
-            .then(function(content) {
-                FileSaver.saveAs(content, "signed-documents.zip");
-
-                that._("#zip-download-button").stop();
-            });
+        let content = await zip.generateAsync({type:"blob"});
+        FileSaver.saveAs(content, "signed-documents.zip");
+        that._("#zip-download-button").stop();
     }
 
     /**
@@ -189,17 +491,82 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
     }
 
     /**
-     * Uploads a failed pdf-file again
+     * Queues a failed pdf-file again
      *
      * @param file
      * @param id
      */
-    async fileUploadClickHandler(file, id) {
-        this.uploadInProgress = true;
-        this.errorFiles.splice(id, 1);
+    async fileQueueingClickHandler(file, id) {
+        this.takeFailedFileFromQueue(id);
+
+        return this._("#file-upload").queueFile(file);
+    }
+
+    /**
+     * Shows the preview
+     *
+     * @param key
+     * @param withSigBlock
+     */
+    async showPreview(key, withSigBlock=false) {
+        if (this.signingProcessEnabled) {
+            return;
+        }
+
+        const file = this._("#file-upload").getQueuedFile(key);
+        this.currentFile = file;
+        this.currentPreviewQueueKey = key;
+        console.log(file);
+        // start signature placement process
+        this.signaturePlacementInProgress = true;
+        this.withSigBlock = withSigBlock;
+
+        const previewTag = this.constructor.getScopedTagName("vpu-pdf-preview");
+        await this._(previewTag).showPDF(
+            file,
+            withSigBlock, //this.queuedFilesPlacementModes[key] === "manual",
+            this.queuedFilesSignaturePlacements[key]);
+    }
+
+    /**
+     * Takes a file off of the queue
+     *
+     * @param key
+     */
+    takeFileFromQueue(key) {
+        return this._("#file-upload").takeFileFromQueue(key);
+    }
+
+    /**
+     * Takes a failed file off of the queue
+     *
+     * @param key
+     */
+    takeFailedFileFromQueue(key) {
+        const file = this.errorFiles.splice(key, 1);
         this.errorFilesCount = Object.keys(this.errorFiles).length;
-        await this._("#file-upload").uploadFile(file);
-        this.uploadInProgress = false;
+
+        return file;
+    }
+
+    clearQueuedFiles() {
+        this.queuedFilesSignaturePlacements = [];
+        this.queuedFilesPlacementModes = [];
+        this._("#file-upload").clearQueuedFiles();
+    }
+
+    clearSignedFiles() {
+        this.signedFiles = [];
+        this.signedFilesCount = 0;
+    }
+
+    clearErrorFiles() {
+        this.errorFiles = [];
+        this.errorFilesCount = 0;
+    }
+
+    isUserInterfaceDisabled() {
+        return this.signaturePlacementInProgress || this.externalAuthInProgress || this.uploadInProgress;
     }
 
     static get styles() {
@@ -210,14 +577,46 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
             ${commonStyles.getButtonCSS()}
             ${commonStyles.getNotificationCSS()}
 
+            #pdf-preview {
+                min-width: 320px;
+            }
+
+            h2:first-child {
+                margin-top: 0;
+            }
+
+            h2 {
+                margin-bottom: 10px;
+            }
+
             strong {
                 font-weight: 600;
             }
 
+            #pdf-preview .box-header {
+                border: 1px solid #000;
+                border-bottom-width: 0;
+                padding: 0.5em 0.5em 0 0.5em;
+            }
+
             .hidden {
                 display: none;
             }
 
+
+
+
+
+
+
+
+
+
+
+            .files-block.field:not(:last-child) {
+                margin-bottom: 40px;
+            }
+
             .files-block .file {
                 margin: 10px 0;
             }
@@ -247,84 +646,453 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(VPUSignatureLitElem
                 margin-right: 5px;
             }
 
-            .error {
+            .error, #cancel-signing-process {
                 color: #e4154b;
             }
+            
+            #cancel-signing-process:hover {
+                color: white;
+            }
+
+            /* using vpu-icon doesn't work */
+            button > [name=close], a > [name=close] {
+                font-size: 0.8em;
+            }
+
+            a > [name=close] {
+                color: red;
+            }
+
+            .empty-queue {
+                margin: 10px 0;
+            }
+
+            #grid-container {
+                display: flex;
+                flex-flow: row wrap;
+            }
+
+            #grid-container > div {
+                margin-right: 20px;
+            }
+
+            #grid-container > div:last-child {
+                margin-right: 0;
+                flex: 1 0;
+            }
+
+            .file-block {
+                max-width: 320px;
+            }
+
+            .file-block, .box {
+                border: solid 1px black;
+                padding: 10px;
+            }
+
+            .file-block, .box .file {
+                margin-top: 0;
+            }
+
+            .file-block {
+                margin-bottom: 10px;
+            }
+
+            .file-block .header {
+                display: grid;
+                align-items: center;
+                grid-template-columns: auto 40px;
+                grid-gap: 10px;
+            }
+
+            .file-block.error .header {
+                grid-template-columns: auto 80px;
+            }
+
+            .file-block.error .header .buttons {
+                white-space: nowrap;
+            }
+
+            .file-block div.bottom-line {
+                display: grid;
+                align-items: center;
+                grid-template-columns: auto 190px;
+                grid-gap: 10px;
+                margin-top: 10px;
+            }
+
+            .file-block.error div.bottom-line {
+                display: block;
+            }
+
+            .file-block div.bottom-line .headline {
+                text-align: right;
+            }
+
+            .file-block .filename, .file-block div.bottom-line .headline {
+                text-overflow: ellipsis;
+                overflow: hidden;
+            }
+
+            .file-block .filename {
+                white-space: nowrap;
+            }
+
+            #pdf-preview .button.is-cancel, #external-auth .button.is-cancel {
+                color: #e4154b;
+            }
+
+            #external-auth iframe {
+                margin-top: 0.5em;
+            }
+
+            .is-right {
+                float: right;
+            }
+
+            .error-files .header {
+                color: black;
+            }
+
+            /* prevent hovering of disabled default button */
+            .button[disabled]:not(.is-primary):hover {
+                background-color: inherit;
+                color: inherit;
+            }
+
+            .is-disabled, .is-disabled.button[disabled] {
+                opacity: 0.2;
+                pointer-events: none;
+            }
+
+            #pdf-preview .box-header, #external-auth .box-header {
+                display: flex;
+                justify-content: space-between;
+                align-items: start;
+            }
+
+            #pdf-preview .box-header .filename, #external-auth .box-header .filename {
+                overflow: hidden;
+                text-overflow: ellipsis;
+                margin-right: 0.5em;
+            }
+
+            /* Handling for small displays (like mobile devices) */
+            @media (max-width: 680px) {
+                /* Modal preview, upload and external auth */
+                div.right-container > * {
+                    position: fixed;
+                    padding: 10px;
+                    top: 0;
+                    left: 0;
+                    right: 0;
+                    bottom: 0;
+                    background-color: white;
+                    overflow-y: scroll;
+                }
+
+                /* Don't use the whole screen for the upload progress */
+                #upload-progress {
+                    top: 10px;
+                    left: 10px;
+                    right: 10px;
+                    bottom: inherit;
+                }
+
+                #grid-container > div {
+                    margin-right: 0;
+                    width: 100%;
+                }
+
+                .file-block {
+                    max-width: inherit;
+                }
+            }
         `;
     }
 
+    /**
+     * Returns the list of queued files
+     *
+     * @returns {*[]}
+     */
+    getQueuedFilesHtml() {
+        const ids = Object.keys(this.queuedFiles);
+        let results = [];
+
+        ids.forEach((id) => {
+            const file = this.queuedFiles[id];
+
+            results.push(html`
+                <div class="file-block">
+                    <div class="header">
+                        <span class="filename"><strong>${file.name}</strong> (${humanFileSize(file.size)})</span>
+                        <button class="button close"
+                            ?disabled="${this.signingProcessEnabled}"
+                            title="${i18n.t('official-pdf-upload.remove-queued-file-button-title')}"
+                            @click="${() => { this.takeFileFromQueue(id); }}">
+                            <vpu-icon name="trash"></vpu-icon></button>
+                    </div>
+                    <div class="bottom-line">
+                        <div></div>
+                        <button class="button"
+                            ?disabled="${this.signingProcessEnabled}"
+                            @click="${() => { this.showPreview(id); }}">${i18n.t('official-pdf-upload.show-preview')}</button>
+                        <span class="headline">${i18n.t('official-pdf-upload.positioning')}:</span>
+                        <vpu-textswitch name1="auto"
+                            name2="manual"
+                            name="${this.queuedFilesPlacementModes[id] || "auto"}"
+                            class="switch"
+                            value1="${i18n.t('official-pdf-upload.positioning-automatic')}"
+                            value2="${i18n.t('official-pdf-upload.positioning-manual')}"
+                            ?disabled="${this.signingProcessEnabled}"
+                            @change=${ (e) => this.queuePlacementSwitch(id, e.target.name) }></vpu-textswitch>
+                    </div>
+                </div>
+            `);
+        });
+
+        return results;
+    }
+
+    /**
+     * Returns the list of successfully signed files
+     *
+     * @returns {*[]}
+     */
     getSignedFilesHtml() {
-        return this.signedFiles.map(file => html`
-            <div class="file">
-                <a class="is-download"
-                    title="${i18n.t('official-pdf-upload.download-file-button-title')}"
-                    @click="${() => {this.fileDownloadClickHandler(file);}}">
-                    <strong>${file.name}</strong> (${humanFileSize(file.contentSize)}) <vpu-icon name="download"></vpu-icon></a>
-            </div>
-        `);
+        const ids = Object.keys(this.signedFiles);
+        let results = [];
+
+        ids.forEach((id) => {
+            const file = this.signedFiles[id];
+
+            results.push(html`
+                <div class="file-block">
+                    <div class="header">
+                        <span class="filename"><strong>${file.name}</strong> (${humanFileSize(file.contentSize)})</span>
+                        <button class="button close"
+                            title="${i18n.t('official-pdf-upload.download-file-button-title')}"
+                            @click="${() => { this.fileDownloadClickHandler(file); }}">
+                            <vpu-icon name="download"></vpu-icon></button>
+                    </div>
+                </div>
+            `);
+        });
+
+        return results;
     }
 
+    /**
+     * Returns the list of files of failed signature processes
+     *
+     * @returns {*[]}
+     */
     getErrorFilesHtml() {
-        return this.errorFiles.map((data, id) => html`
-            <div class="file">
-                <div class="button-box">
-                    <button class="button is-small"
-                            title="${i18n.t('official-pdf-upload.re-upload-file-button-title')}"
-                            @click="${() => {this.fileUploadClickHandler(data.file, id);}}"><vpu-icon name="reload"></vpu-icon></button>
-                </div>
-                <div class="info">
-                    <strong>${data.file.name}</strong> (${humanFileSize(data.file.size)})
-                    <strong class="error">${data.json["hydra:description"]}</strong>
+        const ids = Object.keys(this.errorFiles);
+        let results = [];
+
+        ids.forEach((id) => {
+            const data = this.errorFiles[id];
+
+            results.push(html`
+                <div class="file-block error">
+                    <div class="header">
+                        <span class="filename"><strong>${data.file.name}</strong> (${humanFileSize(data.file.size)})</span>
+                        <div class="buttons">
+                            <button class="button"
+                                    title="${i18n.t('official-pdf-upload.re-upload-file-button-title')}"
+                                    @click="${() => {this.fileQueueingClickHandler(data.file, id);}}"><vpu-icon name="reload"></vpu-icon></button>
+                            <button class="button"
+                                title="${i18n.t('official-pdf-upload.remove-failed-file-button-title')}"
+                                @click="${() => { this.takeFailedFileFromQueue(id); }}">
+                                <vpu-icon name="trash"></vpu-icon></button>
+                        </div>
+                    </div>
+                    <div class="bottom-line">
+                        <strong class="error">${data.json["hydra:description"]}</strong>
+                    </div>
                 </div>
-            </div>
-        `);
+            `);
+        });
+
+        return results;
     }
 
     hasSignaturePermissions() {
         return this._hasSignaturePermissions('ROLE_SCOPE_OFFICIAL-SIGNATURE');
     }
 
+    /* stopSigningProcess()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+     */
+
     render() {
         return html`
             <div class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading()})}">
                 <div class="field">
                     <h2>${i18n.t('official-pdf-upload.upload-field-label')}</h2>
                     <div class="control">
-                        <vpu-fileupload id="file-upload" lang="${this.lang}" url="${this.signingUrl}" accept="application/pdf"
+                        <vpu-fileupload id="file-upload"
+                            allowed-mime-types="application/pdf"
+                            decompress-zip
+                            always-send-file
+                            deferred
+                            lang="${this.lang}"
+                            url="${this.signingUrl}"
+                            ?disabled="${this.signingProcessActive}"
                             text="${i18n.t('official-pdf-upload.upload-area-text')}"
                             button-label="${i18n.t('official-pdf-upload.upload-button-label')}"
                             @vpu-fileupload-all-start="${this.onAllUploadStarted}"
                             @vpu-fileupload-file-start="${this.onFileUploadStarted}"
                             @vpu-fileupload-file-finished="${this.onFileUploadFinished}"
                             @vpu-fileupload-all-finished="${this.onAllUploadFinished}"
+                            @vpu-fileupload-queued-files-changed="${this.onQueuedFilesChanged}"
                             ></vpu-fileupload>
                     </div>
                 </div>
-                <div class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}">
-                    <vpu-mini-spinner></vpu-mini-spinner>
-                    <strong>${this.uploadStatusFileName}</strong>
-                    ${this.uploadStatusText}
-                </div>
-                <div class="files-block field ${classMap({hidden: this.signedFilesCount === 0})}">
-                    <h2>${i18n.t('official-pdf-upload.signed-files-label')}</h2>
-                    <div class="control">
-                        ${this.getSignedFilesHtml()}
+                           <div id="grid-container">
+                    <div class="left-container">
+                        <div class="files-block field ${classMap({hidden: !this.queueBlockEnabled})}">
+                            <!-- Queued files headline and queueing spinner -->
+                            <h2 class="${classMap({"is-disabled": this.isUserInterfaceDisabled()})}">
+                                ${i18n.t('official-pdf-upload.queued-files-label')}
+                                <vpu-mini-spinner id="queueing-in-progress-spinner"
+                                                  style="font-size: 0.7em"
+                                                  class="${classMap({hidden: !this.queueingInProgress})}"></vpu-mini-spinner>
+                            </h2>
+                            <!-- Buttons to start/stop signing process and clear queue -->
+                            <div class="control field">
+                                <button @click="${this.clearQueuedFiles}"
+                                        ?disabled="${this.queuedFilesCount === 0 || this.signingProcessActive || this.isUserInterfaceDisabled()}"
+                                        class="button ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}">
+                                    ${i18n.t('official-pdf-upload.clear-all')}
+                                </button>
+                                <button @click="${() => { this.signingProcessEnabled = true; this.signingProcessActive = true; }}"
+                                        ?disabled="${this.queuedFilesCount === 0}"
+                                        class="button is-right is-primary ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}">
+                                    ${i18n.t('official-pdf-upload.start-signing-process-button')}
+                                </button>
+                                <!-- -->
+                                <button @click="${this.stopSigningProcess}"
+                                        ?disabled="${this.uploadInProgress}"
+                                        id="cancel-signing-process"
+                                        class="button is-right ${classMap({hidden: !this.signingProcessActive})}">
+                                    ${i18n.t('official-pdf-upload.stop-signing-process-button')}
+                                </button>
+                                <!-- -->
+                            </div>
+                            <!-- List of queued files -->
+                            <div class="control file-list ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}">
+                                ${this.getQueuedFilesHtml()}
+                            </div>
+                            <!-- Text "queue empty" -->
+                            <div class="empty-queue control ${classMap({hidden: this.queuedFilesCount !== 0, "is-disabled": this.isUserInterfaceDisabled()})}">
+                                ${i18n.t('official-pdf-upload.queued-files-empty1')}<br />
+                                ${i18n.t('official-pdf-upload.queued-files-empty2')}
+                            </div>
+                        </div>
+                        <!-- List of signed PDFs -->
+                        <div class="files-block field ${classMap({hidden: this.signedFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}">
+                            <h2>${i18n.t('official-pdf-upload.signed-files-label')}</h2>
+                            <!-- Button to download all signed PDFs -->
+                            <div class="field ${classMap({hidden: this.signedFilesCount === 0})}">
+                                <div class="control">
+                                    <button @click="${this.clearSignedFiles}"
+                                            class="button">
+                                        ${i18n.t('official-pdf-upload.clear-all')}
+                                    </button>
+                                    <vpu-button id="zip-download-button"
+                                                value="${i18n.t('official-pdf-upload.download-zip-button')}"
+                                                title="${i18n.t('official-pdf-upload.download-zip-button-tooltip')}"
+                                                class="is-right"
+                                                @click="${this.zipDownloadClickHandler}"
+                                                type="is-primary"></vpu-button>
+                                </div>
+                            </div>
+                            <div class="control">
+                                ${this.getSignedFilesHtml()}
+                            </div>
+                        </div>
+                        <!-- List of errored files -->
+                        <div class="files-block error-files field ${classMap({hidden: this.errorFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}">
+                            <h2>${i18n.t('official-pdf-upload.error-files-label')}</h2>
+                            <!-- Button to upload errored files again -->
+                            <div class="field ${classMap({hidden: this.errorFilesCount === 0})}">
+                                <div class="control">
+                                    <button @click="${this.clearErrorFiles}"
+                                            class="button">
+                                        ${i18n.t('official-pdf-upload.clear-all')}
+                                    </button>
+                                    <vpu-button id="re-upload-all-button"
+                                                ?disabled="${this.uploadInProgress}"
+                                                value="${i18n.t('official-pdf-upload.re-upload-all-button')}"
+                                                title="${i18n.t('official-pdf-upload.re-upload-all-button-title')}"
+                                                class="is-right"
+                                                @click="${this.reUploadAllClickHandler}"
+                                                type="is-primary"></vpu-button>
+                                </div>
+                            </div>
+                            <div class="control">
+                                ${this.getErrorFilesHtml()}
+                            </div>
+                        </div>
                     </div>
-                </div>
-                <div class="field ${classMap({hidden: this.signedFilesCount === 0})}">
-                    <div class="control">
-                        <vpu-button id="zip-download-button" value="${i18n.t('official-pdf-upload.download-zip-button')}" title="${i18n.t('official-pdf-upload.download-zip-button-tooltip')}" @click="${this.zipDownloadClickHandler}" type="is-primary"></vpu-button>
-                    </div>
-                </div>
-                <div class="files-block error-files field ${classMap({hidden: this.errorFilesCount === 0})}">
-                    <h2 class="error">${i18n.t('official-pdf-upload.error-files-label')}</h2>
-                    <div class="control">
-                        ${this.getErrorFilesHtml()}
-                    </div>
-                </div>
-                <div class="field ${classMap({hidden: this.errorFilesCount === 0})}">
-                    <div class="control">
-                        <vpu-button id="re-upload-all-button" ?disabled="${this.uploadInProgress}" value="${i18n.t('official-pdf-upload.re-upload-all-button')}" title="${i18n.t('official-pdf-upload.re-upload-all-button-title')}" @click="${this.reUploadAllClickHandler}" type="is-primary"></vpu-button>
+                    <div class="right-container">
+                        <!-- PDF preview -->
+                        <div id="pdf-preview" class="field ${classMap({hidden: !this.signaturePlacementInProgress})}">
+                            <h2>${this.withSigBlock ? i18n.t('official-pdf-upload.signature-placement-label') : i18n.t('official-pdf-upload.preview-label')}</h2>
+                            <div class="box-header">
+                                <div class="filename">
+                                    <strong>${this.currentFile.name}</strong> (${humanFileSize(this.currentFile !== undefined ? this.currentFile.size : 0)})
+                                </div>
+                                <button class="button is-cancel"
+                                    @click="${this.hidePDF}"><vpu-icon name="close"></vpu-icon></button>
+                            </div>
+                            <vpu-pdf-preview lang="${this.lang}"
+                                             signature-placeholder-image="official-signature-placeholder.png"
+                                             signature-width="147"
+                                             signature-height="29"
+                                             @vpu-pdf-preview-accept="${this.storePDFData}"
+                                             @vpu-pdf-preview-cancel="${this.hidePDF}"></vpu-pdf-preview>
+                        </div>
+                        <!-- File upload progress -->
+                        <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}">
+                            <vpu-mini-spinner></vpu-mini-spinner>
+                            <strong>${this.uploadStatusFileName}</strong>
+                            ${this.uploadStatusText}
+                        </div>
+                        <!-- External auth -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
                     </div>
                 </div>
             </div>
diff --git a/src/vpu-pdf-preview.js b/src/vpu-pdf-preview.js
index ea9e2cf47e2fbf9393cac34f0dfcd0991749a0db..76445cf02250c84462a2fa461f3ef81b8a71a8b4 100644
--- a/src/vpu-pdf-preview.js
+++ b/src/vpu-pdf-preview.js
@@ -29,6 +29,9 @@ export class PdfPreview extends ScopedElementsMixin(VPULitElement) {
         this.fabricCanvas = null;
         this.canvasToPdfScale = 1.0;
         this.currentPageOriginalHeight = 0;
+        this.placeholder = 'signature-placeholder.png';
+        this.signature_width = 80;
+        this.signature_height = 29;
 
         this._onWindowResize = this._onWindowResize.bind(this);
     }
@@ -51,6 +54,9 @@ export class PdfPreview extends ScopedElementsMixin(VPULitElement) {
             isPageRenderingInProgress: { type: Boolean, attribute: false },
             isPageLoaded: { type: Boolean, attribute: false },
             isShowPlacement: { type: Boolean, attribute: false },
+            placeholder: { type: String, attribute: 'signature-placeholder-image' },
+            signature_width: { type: Number, attribute: 'signature-width' },
+            signature_height: { type: Number, attribute: 'signature-height' },
         };
     }
 
@@ -99,7 +105,7 @@ export class PdfPreview extends ScopedElementsMixin(VPULitElement) {
             });
 
             // add signature image
-            fabric.Image.fromURL(commonUtils.getAssetURL('local/vpu-signature/signature-placeholder.png'), function(image) {
+            fabric.Image.fromURL(commonUtils.getAssetURL('local/vpu-signature/' + this.placeholder), function(image) {
                 // add a red border around the signature placeholder
                 image.set({stroke: "#e4154b", strokeWidth: 8});
 
@@ -288,7 +294,7 @@ export class PdfPreview extends ScopedElementsMixin(VPULitElement) {
 
                 // set the initial position of the signature
                 if (initSignature) {
-                    const sigSizeMM = {width: 80, height: 29};
+                    const sigSizeMM = {width: this.signature_width, height: this.signature_height};
                     const sigPosMM = {top: 5, left: 5};
 
                     const inchPerMM = 0.03937007874;
@@ -369,7 +375,7 @@ export class PdfPreview extends ScopedElementsMixin(VPULitElement) {
     }
 
     /**
-     * Rotates the signature clock-wise in 90� steps
+     * Rotates the signature clock-wise in 90� steps
      */
     async rotateSignature() {
         let signature = this.getSignatureRect();