From 22af79a279e026d5937ac7b744b1dc209f198c81 Mon Sep 17 00:00:00 2001 From: Omar Ahmed Hassan <98468609+omar-ahmed42@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:38:44 +0200 Subject: [PATCH] Feature: Support manual redaction (#2433) # Description ## Manual Redaction: - ### Text Selection-based redaction: - ![image](https://github.com/user-attachments/assets/e59c5e6c-ef52-4f54-a98e-fc26e3226c8e) - Users can now redact currently selected text by selecting the text then clicking `ctrl + s` shortcut or by pressing on **apply/save/disk icon** in the toolbar. - Users can delete/cancel the redacted area by clicking on the box containing the text, then clicking on `delete/trash` icon or by using the shortcut `delete`. - Users can customize the color of the redacted area/text (after the redaction was applied) by simply clicking on the box containing the text/area then clicking on the `color palette` icon and choosing the color they want. - Users can choose to select the color of redaction before redacting text or applying changes (this only affects newly created redaction areas, to change the color of an existing one; check the previous bullet point). - ### Draw/Area-based redaction: - ![image](https://github.com/user-attachments/assets/e2968ae3-ebaf-497e-b3bd-0c8c8f4ee157) - Users can now redact an area in the page by selecting the then clicking `ctrl + s` shortcut or by pressing on **apply/save/disk icon** in the toolbar. - Users can delete/cancel the redacted area by clicking on the drawn box, then clicking on `delete/trash` icon or by using the shortcut `delete` (requires temporarily turning off drawing mode). - Users can customize the color of the redacted area (after the redaction was applied) by simply clicking on the box containing the area then clicking on the `color palette` icon and choosing the color they want. - Users can choose to select the color of redaction before drawing the box or applying changes (this only affects newly created redaction areas, to change the color of an existing one; check the previous bullet point). - ### Page-based redaction: - ![image](https://github.com/user-attachments/assets/aba59432-23e7-4fe6-aa28-872c23a91242) - Users can now redact **ENTIRE** pages by specifying the page number(s), range(s) or functions. - Users can customize the color of page-based redaction (doesn't affect text-based nor draw-based redactions). ### Redaction modes: There are three modes of redaction/operation currently supported - Text Selection-based redaction (TEXT) - Draw/Area-based redaction (DRAWING) - None - by simply not choosing any of the above modes (NONE). ## How to use: - **Text Selection-based redaction:** click on this icon in the toolbar ![image](https://github.com/user-attachments/assets/52cc31ef-6946-482c-84a2-1ddb79646dd8) to enable `text-selection redaction mode` then select the text you want to redact then press `ctrl + s` or click on the disk/save icon ![image](https://github.com/user-attachments/assets/f2bdf2f2-ee07-4682-bb9a-95e13a1004cf). - **Draw/Area-based redaction:** click on this icon in the toolbar ![image](https://github.com/user-attachments/assets/fe00dca9-761e-47a0-a748-2041830dc73e) to enable `draw/area-based redaction` then `left mouse click (LMB)` on the starting point of the rectangle, then once you are satisfied with the rectangle's placement/dimensions then `left mouse click (LMB)` again to apply the redaction. - **Example:** `Left mouse click (LMB)` then move mouse to the right then bottom then `Left mouse click (LMB)`. - Note: Red box/rectangle borders indicate that you have not yet saved (you need to left click on the page to save) ![image](https://github.com/user-attachments/assets/5ce5f789-9d6f-4984-8555-e8fef2a3e3cc) once saved the borders will become green ![image](https://github.com/user-attachments/assets/85cabb9f-e7ee-4268-90cd-80493b625466) (they also become clickable/hover-able when drawing mode is off). - **Page-based redactions:**: Insert the page number(s), range(s) and/or functions (separated by `,`) then select your preferred color and click on `Redact` to submit. ![image](https://github.com/user-attachments/assets/ed8a0a98-32b2-4ae1-a3c7-c54bfe0fea66) - **Color Customizations:** - You can change the redaction color for new redactions by clicking on this icon in the toolbar ![image](https://github.com/user-attachments/assets/bad573ee-0545-4329-b131-2022f970f134). - You can change the redaction color for existing redactions by hovering over the redaction box then clicking on it (`Left mouse click LMB`) then clicking on color palette (highlighted in red in the picture) ![image](https://github.com/user-attachments/assets/22281a81-2cd9-4771-9a93-a75b6dd93433) then select your preferred color. - **Deletions:** - You can delete a redacted area by hovering over the redaction box then clicking on it (`Left mouse click LMB`) then clicking on the trash icon (highlighted in red in the picture) ![image](https://github.com/user-attachments/assets/f0347279-8211-4b1c-a91d-c1fcb929cc5d). ## Card in the home page: ![image](https://github.com/user-attachments/assets/b3fb16eb-5ff0-4548-9f22-b1b8fe162c8b) Closes #465 ## Checklist - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have performed a self-review of my own code - [x] I have attached images of the change if it is UI based - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [ ] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> --- .../SPDF/config/EndpointConfiguration.java | 2 + .../api/security/RedactController.java | 111 + .../controller/web/SecurityWebController.java | 6 + .../api/security/ManualRedactPdfRequest.java | 21 + .../model/api/security/RedactionArea.java | 23 + .../StringToArrayListPropertyEditor.java | 37 + src/main/resources/messages_en_GB.properties | 14 + src/main/resources/static/css/redact.css | 322 ++ src/main/resources/static/js/redact.js | 1206 ++++ .../static/pdfjs-legacy/css/viewer-redact.css | 5084 +++++++++++++++++ .../resources/static/pdfjs-legacy/pdf.mjs | 18 +- .../resources/templates/fragments/navbar.html | 3 + src/main/resources/templates/home.html | 3 + .../resources/templates/security/redact.html | 708 +++ 14 files changed, 7549 insertions(+), 9 deletions(-) create mode 100644 src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java create mode 100644 src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java create mode 100644 src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java create mode 100644 src/main/resources/static/css/redact.css create mode 100644 src/main/resources/static/js/redact.js create mode 100644 src/main/resources/static/pdfjs-legacy/css/viewer-redact.css create mode 100644 src/main/resources/templates/security/redact.html diff --git a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index fdbc7015..07ebadb1 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -135,6 +135,7 @@ public class EndpointConfiguration { addEndpointToGroup("Security", "remove-cert-sign"); addEndpointToGroup("Security", "sanitize-pdf"); addEndpointToGroup("Security", "auto-redact"); + addEndpointToGroup("Security", "redact"); // Adding endpoints to "Other" group addEndpointToGroup("Other", "ocr-pdf"); @@ -234,6 +235,7 @@ public class EndpointConfiguration { addEndpointToGroup("Java", "markdown-to-pdf"); addEndpointToGroup("Java", "show-javascript"); addEndpointToGroup("Java", "auto-redact"); + addEndpointToGroup("Java", "redact"); addEndpointToGroup("Java", "pdf-to-csv"); addEndpointToGroup("Java", "split-by-size-or-count"); addEndpointToGroup("Java", "overlay-pdf"); diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java index b5220454..d123e2ef 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java @@ -3,13 +3,18 @@ package stirling.software.SPDF.controller.api.security; import java.awt.*; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Collections; import java.util.List; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,12 +26,17 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; + import stirling.software.SPDF.model.PDFText; +import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest; import stirling.software.SPDF.model.api.security.RedactPdfRequest; +import stirling.software.SPDF.model.api.security.RedactionArea; import stirling.software.SPDF.pdf.TextFinder; import stirling.software.SPDF.service.CustomPDDocumentFactory; +import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.WebResponseUtils; +import stirling.software.SPDF.utils.propertyeditor.StringToArrayListPropertyEditor; @RestController @RequestMapping("/api/v1/security") @@ -41,6 +51,107 @@ public class RedactController { this.pdfDocumentFactory = pdfDocumentFactory; } + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(List.class, "redactions", new StringToArrayListPropertyEditor()); + } + + @PostMapping(value = "/redact", consumes = "multipart/form-data") + @Operation(summary = "Redacts areas and pages in a PDF document", description = "This operation takes an input PDF file with a list of areas, page number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF, Type:SISO") + public ResponseEntity redactPDF(@ModelAttribute ManualRedactPdfRequest request) throws IOException { + MultipartFile file = request.getFileInput(); + List redactionAreas = request.getRedactions(); + + PDDocument document = pdfDocumentFactory.load(file); + + PDPageTree allPages = document.getDocumentCatalog().getPages(); + + redactPages(request, document, allPages); + redactAreas(redactionAreas, document, allPages); + + if (request.isConvertPDFToImage()) { + PDDocument convertedPdf = PdfUtils.convertPdfToPdfImage(document); + document.close(); + document = convertedPdf; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + document.save(baos); + document.close(); + + byte[] pdfContent = baos.toByteArray(); + return WebResponseUtils.bytesToWebResponse( + pdfContent, + Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "") + + "_redacted.pdf"); + } + + private void redactAreas(List redactionAreas, PDDocument document, PDPageTree allPages) + throws IOException { + Color redactColor = null; + for (RedactionArea redactionArea : redactionAreas) { + if (redactionArea.getPage() == null || redactionArea.getPage() <= 0 + || redactionArea.getHeight() == null || redactionArea.getHeight() <= 0.0D + || redactionArea.getWidth() == null || redactionArea.getWidth() <= 0.0D) + continue; + PDPage page = allPages.get(redactionArea.getPage() - 1); + + PDPageContentStream contentStream = new PDPageContentStream( + document, page, PDPageContentStream.AppendMode.APPEND, true, true); + redactColor = decodeOrDefault(redactionArea.getColor(), Color.BLACK); + contentStream.setNonStrokingColor(redactColor); + + float x = redactionArea.getX().floatValue(); + float y = redactionArea.getY().floatValue(); + float width = redactionArea.getWidth().floatValue(); + float height = redactionArea.getHeight().floatValue(); + + PDRectangle box = page.getBBox(); + + contentStream.addRect(x, box.getHeight() - y - height, width, height); + contentStream.fill(); + contentStream.close(); + } + } + + private void redactPages(ManualRedactPdfRequest request, PDDocument document, PDPageTree allPages) + throws IOException { + Color redactColor = decodeOrDefault(request.getPageRedactionColor(), Color.BLACK); + List pageNumbers = getPageNumbers(request, allPages.getCount()); + for (Integer pageNumber : pageNumbers) { + PDPage page = allPages.get(pageNumber); + + PDPageContentStream contentStream = new PDPageContentStream( + document, page, PDPageContentStream.AppendMode.APPEND, true, true); + contentStream.setNonStrokingColor(redactColor); + + PDRectangle box = page.getBBox(); + + contentStream.addRect(0, 0, box.getWidth(), box.getHeight()); + contentStream.fill(); + contentStream.close(); + } + } + + private Color decodeOrDefault(String hex, Color defaultColor) { + Color color = null; + try { + color = Color.decode(hex); + } catch (Exception e) { + color = defaultColor; + } + + return color; + } + + private List getPageNumbers(ManualRedactPdfRequest request, int pagesCount) { + String pageNumbersInput = request.getPageNumbers(); + String[] parsedPageNumbers = pageNumbersInput != null ? pageNumbersInput.split(",") : new String[0]; + List pageNumbers = GeneralUtils.parsePageList(parsedPageNumbers, pagesCount, false); + Collections.sort(pageNumbers); + return pageNumbers; + } + @PostMapping(value = "/auto-redact", consumes = "multipart/form-data") @Operation( summary = "Redacts listOfText in a PDF document", diff --git a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java index 5793fa4e..eb7245e5 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java @@ -18,6 +18,12 @@ public class SecurityWebController { return "security/auto-redact"; } + @GetMapping("/redact") + public String redactForm(Model model) { + model.addAttribute("currentPage", "redact"); + return "security/redact"; + } + @GetMapping("/add-password") @Hidden public String addPasswordForm(Model model) { diff --git a/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java b/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java new file mode 100644 index 00000000..cb98499e --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/api/security/ManualRedactPdfRequest.java @@ -0,0 +1,21 @@ +package stirling.software.SPDF.model.api.security; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import stirling.software.SPDF.model.api.PDFWithPageNums; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ManualRedactPdfRequest extends PDFWithPageNums { + @Schema(description = "A list of areas that should be redacted") + private List redactions; + + @Schema(description = "Convert the redacted PDF to an image", defaultValue = "false") + private boolean convertPDFToImage; + + @Schema(description = "The color used to fully redact certain pages") + private String pageRedactionColor; +} diff --git a/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java b/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java new file mode 100644 index 00000000..5157d415 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/api/security/RedactionArea.java @@ -0,0 +1,23 @@ +package stirling.software.SPDF.model.api.security; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class RedactionArea { + @Schema(description = "The left edge point of the area to be redacted.") + private Double x; + @Schema(description = "The top edge point of the area to be redacted.") + private Double y; + + @Schema(description = "The height of the area to be redacted.") + private Double height; + @Schema(description = "The width of the area to be redacted.") + private Double width; + + @Schema(description = "The page on which the area should be redacted.") + private Integer page; + + @Schema(description = "The color used to redact the specified area.") + private String color; +} diff --git a/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java b/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java new file mode 100644 index 00000000..cbcb6172 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/propertyeditor/StringToArrayListPropertyEditor.java @@ -0,0 +1,37 @@ +package stirling.software.SPDF.utils.propertyeditor; + +import java.beans.PropertyEditorSupport; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.api.security.RedactionArea; + +@Slf4j +public class StringToArrayListPropertyEditor extends PropertyEditorSupport { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void setAsText(String text) throws IllegalArgumentException { + if (text == null || text.trim().isEmpty()) { + setValue(new ArrayList<>()); + return; + } + try { + objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + TypeReference> typeRef = new TypeReference>() { + }; + List list = objectMapper.readValue(text, typeRef); + setValue(list); + } catch (Exception e) { + log.error("Exception while converting {}", e); + throw new IllegalArgumentException( + "Failed to convert java.lang.String to java.util.List"); + } + } +} diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index a14cc332..4a27fa77 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -82,6 +82,7 @@ pages=Pages loading=Loading... addToDoc=Add to Document reset=Reset +apply=Apply legal.privacy=Privacy Policy legal.terms=Terms and Conditions @@ -474,6 +475,10 @@ home.autoRedact.title=Auto Redact home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text autoRedact.tags=Redact,Hide,black out,black,marker,hidden +home.redact.title=Manual Redaction +home.redact.desc=Redacts a PDF based on selected text, drawn shapes and/or selected page(s) +redact.tags=Redact,Hide,black out,black,marker,hidden,manual + home.tableExtraxt.title=PDF to CSV home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV tableExtraxt.tags=CSV,Table Extraction,extract,convert @@ -579,6 +584,15 @@ autoRedact.customPaddingLabel=Custom Extra Padding autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box) autoRedact.submitButton=Submit +#redact +redact.title=Manual Redaction +redact.header=Manual Redaction +redact.submit=Redact +redact.pageBasedRedaction=Page-based Redaction +redact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box) +redact.pageRedactionNumbers.title=Pages +redact.pageRedactionNumbers.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1) +redact.redactionColor.title=Redaction Color #showJS showJS.title=Show Javascript diff --git a/src/main/resources/static/css/redact.css b/src/main/resources/static/css/redact.css new file mode 100644 index 00000000..4c9a8d74 --- /dev/null +++ b/src/main/resources/static/css/redact.css @@ -0,0 +1,322 @@ +:root { + --page-redaction-color: #000000; +} + +.textLayer span::selection, +.textLayer span::-moz-selection { + background-color: rgba(0, 100, 0, 0.26); +} + +.selected-wrapper { + position: absolute; + outline: 2px solid darkgreen; + outline-offset: -2px; + z-index: 10; +} + +.selected-wrapper:hover:not(:has(.redaction-overlay:hover)) { + outline-color: var(--palette-color, #000000); + background-color: var(--palette-color, #000000); + z-index: 10; + transition: background-color 0.065s linear; + + cursor: pointer; +} + +.redaction-overlay { + display: flex; + position: absolute; + + left: 50%; + top: 100%; + + min-width: 25px; + max-width: 90px; + + min-height: 25px; + + flex-wrap: nowrap; + + column-gap: 5px; + row-gap: 2px; + + border-radius: 2px; + padding: 2px; + + box-sizing: border-box; + + background-color: rgb(0 96 170); + outline: 1px solid gray; + translate: -50% -100%; +} + +.redaction-overlay svg { + height: 25px; + width: 25px; + + max-width: 35px; + max-height: 35px; + + fill: rgba(255, 255, 255, 0.904); + user-select: none; +} + +.redaction-overlay svg:hover { + cursor: pointer; + background-color: rgb(3, 63, 109); + fill: rgba(226, 226, 226, 0.904); +} + +.textLayer div, +.textLayer div > * { + user-select: none; +} + +.rectangle { + border: 2px solid #ff0000; + position: absolute; +} + +html { + --textLayer-pointer-events: auto; + --textLayer-user-select: auto; +} + +.textLayer * { + pointer-events: var(--textLayer-pointer-events); + user-select: var(--textLayer-user-select); +} + +#showMoreBtnIcon::before { + left: 5px; + top: 5px; +} + +#showMoreBtn { + display: flex; + justify-content: center; + align-items: center; +} + +#man-text-select-redact, #man-shape-redact, #downloadBtn, #uploadBtn, #pageBasedRedactionBtn, #pdfToImageBtn, #showMoreBtn { + height: var(--toolButton-height); + width: var(--toolButton-width); + + border-radius: var(--toolButton-border-radius); + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + user-select: none; +} + +#text-selection, #shape-selection, #downloadBtnIcon, #uploadBtnIcon, #pageBasedRedactionBtnIcon, #pdfToImageBtnIcon, #showMoreBtnIcon { + position: relative; + font-size: var(--toolButton-icon-font-size); +} + +:is(#man-shape-redact, #man-text-select-redact, #sidebarToggle, #viewThumbnail, #viewOutline, #showMoreBtn).toggled { + background-color: rgb(50, 159, 243); + color: rgb(255 255 255); + outline:rgb(50, 159, 243) !important; + border-color: rgb(50, 159, 243) !important; +} + +:is(#man-shape-redact, #man-text-select-redact, #redactionsPaletteContainer, #downloadBtn, #uploadBtn, #pageBasedRedactionBtn, #pdfToImageBtn, #showMoreBtn):hover { + background-color: rgba(6, 114, 197, 0.82); + color: rgb(255 255 255); + outline:rgba(6, 114, 197, 0.82) !important; + border-color: rgba(6, 114, 197, 0.82) !important; +} + +#redactionsPaletteContainer { + height: var(--toolButton-height); + width: var(--toolButton-width); + + border-radius: var(--toolButton-border-radius); + overflow: hidden; +} + +#redactionsPaletteContainer *, #showMoreBtn * { + user-select: none; + pointer-events: none; +} + +#redactions-palette { + display: inline; + position: relative; + + border-bottom: 8px solid var(--palette-color); + border-radius: inherit; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + font-size: var(--toolButton-icon-font-size); +} + +#redactions-palette::before { + position: absolute; + content: ''; + height: 6px; + width: 100%; + left: 0; + bottom: 0px; + background-color: var(--palette-color); +} + +#redactions-palette > input[type=color] { + visibility: hidden; + position: absolute; + left: 0; + top: var(--toolButton-height); + height: 0; +} + +#apply-redaction { + height: var(--toolButton-height); + width: var(--toolButton-width); + + border-radius: var(--toolButton-border-radius); +} + +#apply-redaction[disabled=true], #apply-redaction:disabled:not([disabled=false]) { + color: rgb(147, 149, 153); + box-shadow: none !important; +} + +#apply-redaction:is(:hover):not([disabled=true], :disabled:not([disabled=false])) { + cursor: pointer; + background-color: rgba(6, 114, 197, 0.82); + color: rgb(255 255 255); + outline:rgba(6, 114, 197, 0.82) !important; + border-color: rgba(6, 114, 197, 0.82) !important; +} + +.toolbar-btn-hover:hover { + cursor: pointer; + background-color: rgba(6, 114, 197, 0.82) !important; + color: rgb(255 255 255) !important; + outline:rgba(6, 114, 197, 0.82) !important; + border-color: rgba(6, 114, 197, 0.82) !important; +} + +#apply-redaction-icon { + font-size: var(--toolButton-icon-font-size); +} + +#apply-redaction > span { + user-select: none; + pointer-events: none; +} + +#pageRedactColor, input[data-for=pageRedactColor] { + flex: 1; + padding: 1px; +} + +#pageRedactColor:is(:hover, :focus-within), input[data-for=pageRedactColor]:is(:hover, :focus-within) { + cursor: pointer; +} + +.palette-color { + border-bottom: 3px solid var(--palette-color); +} + +.palette-color:is(:hover, :focus-within) { + cursor: pointer; + background-color: var(--button-hover-color); +} + +.splitToolbarButton > .btn-primary, .splitToolbarButton > .btn-secondary, .splitToolbarButton > .toolbarButton { + margin-left: 3px; + margin-right: 3px; +} + +.spin-animation { + -webkit-animation: spin 2s linear infinite; /* Safari */ + -moz-animation: spin 2s linear infinite; + -o-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} + +@-moz-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} + +@-o-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.active-redaction { + z-index: 30 !important; +} + +#pageBasedRedactionOverlay { + position: absolute; + left: 50%; + top: 50%; + background-color: var(--md-sys-color-surface); + color: var(--md-sys-color-on-surface); + border-radius: 3rem; + z-index: 100; + transform: translate(-50%, -50%); +} + +.list-styling { + display: list-item !important; + margin-left: 15px; + list-style-type: disc; +} + +.redacted-page { + --page-redaction-color: none; +} + +.redacted-page-preview { + border: 2px solid blue; +} + +.redacted-page-preview:hover { + background-color: var(--page-redaction-color) !important; +} + +.redacted-page-preview * { + user-select: none; + pointer-events: none; +} + +.overlay-colorpicker-window { + position: absolute; + left: 0; + top: 24px; + height: 0; + visibility: hidden; +} + +.redacted-thumbnail-image-preview { + border: 2px solid blue; +} + +.redacted-thumbnail-preview { + position: relative; +} + +.redacted-thumbnail-preview:hover::after { + content: ''; + background-color: var(--page-redaction-color); + + position: absolute; + left: 0; + top: 0; + + height: var(--thumbnail-height); + width: var(--thumbnail-width); +} diff --git a/src/main/resources/static/js/redact.js b/src/main/resources/static/js/redact.js new file mode 100644 index 00000000..3fdc4c3f --- /dev/null +++ b/src/main/resources/static/js/redact.js @@ -0,0 +1,1206 @@ +import { PDFViewerApplication } from "../pdfjs-legacy/js/viewer.mjs"; +import UUID from "./uuid.js"; + +let zoomScaleValue = 1.0; + +let activeOverlay; +let drawingLayer = null; + +const doNothing = () => {}; + +function addRedactedPagePreview(pagesSelector) { + document.querySelectorAll(pagesSelector).forEach((page) => { + let textLayer = page.querySelector(".textLayer"); + if (textLayer) textLayer.classList.add("redacted-page-preview"); + }); +} + +function addRedactedThumbnailPreview(sidebarPagesSelector) { + document.querySelectorAll(sidebarPagesSelector).forEach((thumbnail) => { + thumbnail.classList.add("redacted-thumbnail-preview"); + let thumbnailImage = thumbnail.querySelector(".thumbnailImage"); + if (thumbnailImage) + thumbnailImage.classList.add("redacted-thumbnail-image-preview"); + }); +} + +function removeRedactedPagePreview() { + document + .querySelectorAll(".textLayer") + .forEach((textLayer) => + textLayer.classList.remove("redacted-page-preview") + ); + document + .querySelectorAll("#thumbnailView > a > div.thumbnail") + .forEach((thumbnail) => { + thumbnail.classList.remove("redacted-thumbnail-preview"); + let thumbnailImage = thumbnail.querySelector(".thumbnailImage"); + if (thumbnailImage) + thumbnailImage.classList.remove("redacted-thumbnail-image-preview"); + }); +} + +function extractPagesDetailed(pagesInput, totalPageCount) { + let parts = pagesInput.split(",").filter((s) => s); + let pagesDetailed = { + numbers: new Set(), + functions: new Set(), + ranges: new Set(), + all: false, + }; + for (let part of parts) { + let trimmedPart = part.trim(); + if ("all" == trimmedPart) { + pagesDetailed.all = true; + return pagesDetailed; + } else if (isValidFunction(trimmedPart)) { + pagesDetailed.functions.add(formatNFunction(trimmedPart)); + } else if (trimmedPart.includes("-")) { + let range = trimmedPart + .replaceAll(" ", "") + .split("-") + .filter((s) => s); + if ( + range && + range.length == 2 && + range[0].trim() > 0 && + range[1].trim() > 0 + ) + pagesDetailed.ranges.add({ + low: range[0].trim(), + high: range[1].trim(), + }); + } else if (isPageNumber(trimmedPart)) { + pagesDetailed.numbers.add( + trimmedPart <= totalPageCount ? trimmedPart : totalPageCount + ); + } + } + + return pagesDetailed; +} + +function formatNFunction(expression) { + let result = insertMultiplicationBeforeN(expression.replaceAll(" ", "")); + let multiplyByOpeningRoundBracketPattern = /([0-9n)])\(/g; // example: n(n-1), 9(n-1), (n-1)(n-2) + result = result.replaceAll(multiplyByOpeningRoundBracketPattern, "$1*("); + + let multiplyByClosingRoundBracketPattern = /\)([0-9n)])/g; // example: (n-1)n, (n-1)9, (n-1)(n-2) + result = result.replaceAll(multiplyByClosingRoundBracketPattern, ")*$1"); + return result; +} + +function insertMultiplicationBeforeN(expression) { + let result = expression.replaceAll(/(\d)n/g, "$1*n"); + while (result.match(/nn/)) { + result = result.replaceAll(/nn/g, "n*n"); // From nn -> n*n + } + return result; +} + +function validatePages(pages) { + let parts = pages.split(",").filter((s) => s); + let errors = []; + for (let part of parts) { + let trimmedPart = part.trim(); + if ("all" == trimmedPart) continue; + else if (trimmedPart.includes("n")) { + if (!isValidFunction(trimmedPart)) + errors.push( + `${trimmedPart} is an invalid function, it should consist of digits 0-9, n, *, -, /, (, ), \\.` + ); + } else if (trimmedPart.includes("-")) { + let range = trimmedPart.split("-").filter((s) => s); + if (!range || range.length != 2) + errors.push( + `${trimmedPart} is an invalid range, it should consist of from-to, example: 1-5` + ); + else if (range[0].trim() <= 0 || range[1].trim() <= 0) + errors.push( + `${trimmedPart} has invalid range(s), page numbers should be positive.` + ); + } else if (!isPageNumber(trimmedPart)) { + errors.push( + `${trimmedPart} is invalid, it should either be a function, page number or a range.` + ); + } + } + + return { errors }; +} + +function isPageNumber(page) { + return /^[0-9]*$/.test(page); +} + +function isValidFunction(part) { + return part.includes("n") && /[0-9n+\-*/() ]+$/.test(part); +} + +function hideContainer(container) { + container?.classList.add("d-none"); +} + +const RedactionModes = Object.freeze({ + DRAWING: Symbol("drawing"), + TEXT: Symbol("text"), + NONE: Symbol("none"), +}); + +function removePDFJSButtons() { + document.getElementById("print")?.remove(); + document.getElementById("download")?.remove(); + document.getElementById("editorStamp")?.remove(); + document.getElementById("editorFreeText")?.remove(); + document.getElementById("editorInk")?.remove(); + document.getElementById("secondaryToolbarToggle")?.remove(); + document.getElementById("openFile")?.remove(); +} + +function hideInitialPage() { + document.body.style.overflowY = "hidden"; + let redactionsFormContainer = document.getElementById( + "redactionFormContainer" + ); + for ( + let el = redactionsFormContainer.previousElementSibling; + el && el instanceof HTMLBRElement; + el = el.previousElementSibling + ) { + el.classList.add("d-none"); + } + redactionsFormContainer.classList.add("d-none"); + document.getElementsByTagName("footer")[0].classList.add("d-none"); +} + +window.addEventListener("load", (e) => { + let isChromium = + !!window.chrome || + (!!navigator.userAgentData && + navigator.userAgentData.brands.some((data) => data.brand == "Chromium")); + + let isSafari = + /constructor/i.test(window.HTMLElement) || + (function (p) { + return p.toString() === "[object SafariRemoteNotification]"; + })( + !window["safari"] || + (typeof safari !== "undefined" && window["safari"].pushNotification) + ); + let isWebkit = navigator.userAgent.search(/webkit/i) > 0; + let isGecko = navigator.userAgent.search(/gecko/i) > 0; + let isFirefox = typeof InstallTrigger !== "undefined"; + + let hiddenInput = document.getElementById("fileInput"); + let outerContainer = document.getElementById("outerContainer"); + let printContainer = document.getElementById("printContainer"); + + let toolbarViewerRight = document.getElementById("toolbarViewerRight"); + let showMoreBtn = document.getElementById("showMoreBtn"); + + window.onresize = (e) => { + if (window.innerWidth > 1125 && showMoreBtn.classList.contains("toggled")) { + showMoreBtn.click(); + } else if ( + window.innerWidth > 1125 && + toolbarViewerRight.hasAttribute("style") + ) { + toolbarViewerRight.style.removeProperty("display"); + } + }; + + showMoreBtn.onclick = (e) => { + if (showMoreBtn.classList.contains("toggled")) { + toolbarViewerRight.style.display = "none"; + showMoreBtn.classList.remove("toggled"); + } else { + toolbarViewerRight.style.display = "flex"; + showMoreBtn.classList.add("toggled"); + } + }; + + let viewer = document.getElementById("viewer"); + + hiddenInput.files = undefined; + let redactionMode = RedactionModes.NONE; + + let redactions = []; + + let redactionsInput = document.getElementById("redactions-input"); + + let redactionsPalette = document.getElementById("redactions-palette"); + let redactionsPaletteInput = redactionsPalette.querySelector("input"); + + let redactionsPaletteContainer = document.getElementById( + "redactionsPaletteContainer" + ); + + let applyRedactionBtn = document.getElementById("apply-redaction"); + + let redactedPagesDetails = { + numbers: new Set(), + ranges: new Set(), + functions: new Set(), + all: false, + }; + let pageBasedRedactionBtn = document.getElementById("pageBasedRedactionBtn"); + let pageBasedRedactionOverlay = document.getElementById( + "pageBasedRedactionOverlay" + ); + pageBasedRedactionBtn.onclick = (e) => + pageBasedRedactionOverlay.classList.remove("d-none"); + + pageBasedRedactionOverlay.querySelector("input[type=text]").onchange = ( + e + ) => { + let input = e.target; + let parentElement = input.parentElement; + + resetFieldFeedbackMessages(input, parentElement); + + let value = input.value.trim(); + let { errors } = validatePages(value); + if (errors && errors.length > 0) { + applyPageRedactionBtn.disabled = "true"; + displayFieldErrorMessages(input, errors); + } else { + applyPageRedactionBtn.removeAttribute("disabled"); + input.classList.add("is-valid"); + } + }; + + let applyPageRedactionBtn = document.getElementById("applyPageRedactionBtn"); + applyPageRedactionBtn.onclick = (e) => { + pageBasedRedactionOverlay.querySelectorAll("input").forEach((input) => { + const id = input.getAttribute("data-for"); + if (id == "pageNumbers") { + let { errors } = validatePages(input.value); + + resetFieldFeedbackMessages(input, input.parentElement); + + if (errors?.length > 0) { + applyPageRedactionBtn.disabled = true; + displayFieldErrorMessages(input, errors); + } else { + pageBasedRedactionOverlay.classList.add("d-none"); + applyRedactionBtn.removeAttribute("disabled"); + input.classList.remove("is-valid"); + + let totalPagesCount = PDFViewerApplication.pdfViewer.pagesCount; + let pagesDetailed = extractPagesDetailed( + input.value, + totalPagesCount + ); + redactedPagesDetails = pagesDetailed; + addPageRedactionPreviewToPages(pagesDetailed, totalPagesCount); + } + } else if (id == "pageRedactColor") setPageRedactionColor(input.value); + let formInput = document.getElementById(id); + if (formInput) formInput.value = input.value; + }); + }; + + let closePageRedactionBtn = document.getElementById("closePageRedactionBtn"); + closePageRedactionBtn.onclick = (e) => { + pageBasedRedactionOverlay.classList.add("d-none"); + pageBasedRedactionOverlay.querySelectorAll("input").forEach((input) => { + const id = input.getAttribute("data-for"); + if (id == "pageNumbers") { + resetFieldFeedbackMessages(input, input.parentElement); + } + let formInput = document.getElementById(id); + if (formInput) input.value = formInput.value; + }); + }; + + let pdfToImageCheckbox = document.getElementById("convertPDFToImage"); + + let pdfToImageBtn = document.getElementById("pdfToImageBtn"); + pdfToImageBtn.onclick = (e) => { + pdfToImageBtn.classList.toggle("btn-success"); + pdfToImageBtn.classList.toggle("btn-danger"); + pdfToImageCheckbox.checked = !pdfToImageCheckbox.checked; + }; + + let fileChooser = document.getElementsByClassName("custom-file-chooser")[0]; + let fileChooserInput = fileChooser.querySelector( + `#${fileChooser.getAttribute("data-bs-element-id")}` + ); + + let uploadButton = document.getElementById("uploadBtn"); + uploadButton.onclick = (e) => fileChooserInput.click(); + + document.addEventListener("file-input-change", (e) => { + redactions = []; + _setRedactionsInput(redactions); + }); + + let submitBtn = document.getElementById("submitBtn"); + + let downloadBtn = document.getElementById("downloadBtn"); + let downloadBtnIcon = document.getElementById("downloadBtnIcon"); + + downloadBtn.onclick = (e) => { + submitBtn.click(); + setTimeout(_showOrHideLoadingSpinner, 100); // wait 100 milliseconds so that submitBtn would be disabled + }; + + function _showOrHideLoadingSpinner() { + if (!submitBtn.disabled) { + downloadBtnIcon.innerHTML = "download"; + downloadBtnIcon.classList.remove("spin-animation"); + return; + } + + downloadBtnIcon.innerHTML = "progress_activity"; + downloadBtnIcon.classList.add("spin-animation"); + setTimeout(_showOrHideLoadingSpinner, 500); + } + + redactionsPaletteContainer.onclick = (e) => redactionsPalette.click(); + + viewer.onmouseup = (e) => { + if (redactionMode !== RedactionModes.TEXT) return; + const containsText = + window.getSelection() && window.getSelection().toString() != ""; + applyRedactionBtn.disabled = !containsText; + }; + + applyRedactionBtn.onclick = (e) => { + if (redactionMode !== RedactionModes.TEXT) { + applyRedactionBtn.disabled = true; + return; + } + redactTextSelection(); + applyRedactionBtn.disabled = true; + }; + + redactionsPaletteInput.onchange = (e) => { + let color = e.target.value; + redactionsPalette.style.setProperty("--palette-color", color); + }; + + document.addEventListener("file-input-change", (e) => { + let fileChooser = document.getElementsByClassName("custom-file-chooser")[0]; + let fileChooserInput = fileChooser.querySelector( + `#${fileChooser.getAttribute("data-bs-element-id")}` + ); + + hiddenInput.files = fileChooserInput.files; + if (!hiddenInput.files || hiddenInput.files.length === 0) { + hideContainer(outerContainer); + hideContainer(printContainer); + } else { + outerContainer?.classList.remove("d-none"); + printContainer?.classList.remove("d-none"); + hideInitialPage(); + } + + hiddenInput.dispatchEvent(new Event("change", { bubbles: true })); + }); + + PDFViewerApplication.downloadOrSave = doNothing; + PDFViewerApplication.triggerPrinting = doNothing; + + let redactionContainersDivs = {}; + PDFViewerApplication.eventBus.on("pagerendered", (e) => { + removePDFJSButtons(); + + let textSelectionRedactionBtn = document.getElementById( + "man-text-select-redact" + ); + let drawRedactionBtn = document.getElementById("man-shape-redact"); + + textSelectionRedactionBtn.onclick = _handleTextSelectionRedactionBtnClick; + drawRedactionBtn.onclick = _handleDrawRedactionBtnClick; + + let layer = e.source.textLayer.div; + layer.setAttribute("data-page", e.pageNumber); + if ( + redactedPagesDetails.all || + redactedPagesDetails.numbers.has(e.pageNumber) + ) { + layer.classList.add("redacted-page-preview"); + } else { + layer.classList.remove("redacted-page-preview"); + } + + zoomScaleValue = e.source.scale ? e.source.scale : e.source.pageScale; + document.documentElement.style.setProperty("--zoom-scale", zoomScaleValue); + + let redactionsContainer = document.getElementById( + `redactions-container-${e.pageNumber}` + ); + if (!redactionsContainer && !redactionContainersDivs[`${e.pageNumber}`]) { + redactionsContainer = document.createElement("div"); + redactionsContainer.style.position = "relative"; + redactionsContainer.style.height = "100%"; + redactionsContainer.style.width = "100%"; + redactionsContainer.id = `redactions-container-${e.pageNumber}`; + redactionsContainer.style.setProperty("z-index", "unset"); + + layer.appendChild(redactionsContainer); + redactionContainersDivs[`${e.pageNumber}`] = redactionsContainer; + } else if ( + !redactionsContainer && + redactionContainersDivs[`${e.pageNumber}`] + ) { + redactionsContainer = redactionContainersDivs[`${e.pageNumber}`]; + + layer.appendChild(redactionsContainer); + // Dispatch event to update text layer references for elements' events + redactionsContainer + .querySelectorAll(".selected-wrapper") + .forEach((area) => + area.dispatchEvent( + new CustomEvent("textLayer-reference-changed", { + bubbles: true, + detail: { textLayer: layer }, + }) + ) + ); + } + + document.onpointerup = (e) => { + if (drawingLayer && e.target != drawingLayer && e.button == 0) + drawingLayer.dispatchEvent(new Event("external-pointerup")); + }; + + initDraw(layer, redactionsContainer); + + function _handleTextSelectionRedactionBtnClick(e) { + if (textSelectionRedactionBtn.classList.contains("toggled")) { + resetTextSelection(); + } else { + resetDrawRedactions(); + textSelectionRedactionBtn.classList.add("toggled"); + redactionMode = RedactionModes.TEXT; + const containsText = + window.getSelection() && window.getSelection().toString() != ""; + applyRedactionBtn.disabled = !containsText; + applyRedactionBtn.classList.remove("d-none"); + } + } + + function resetTextSelection() { + textSelectionRedactionBtn.classList.remove("toggled"); + redactionMode = RedactionModes.NONE; + clearSelection(); + applyRedactionBtn.disabled = true; + applyRedactionBtn.classList.add("d-none"); + } + + function clearSelection() { + if (window.getSelection) { + if (window.getSelection().empty) { + // Chrome + window.getSelection().empty(); + } else if (window.getSelection().removeAllRanges) { + // Firefox + window.getSelection().removeAllRanges(); + } + } else if (document.selection) { + // IE? + document.selection.empty(); + } + } + + function _handleDrawRedactionBtnClick(e) { + if (drawRedactionBtn.classList.contains("toggled")) { + resetDrawRedactions(); + } else { + resetTextSelection(); + drawRedactionBtn.classList.add("toggled"); + document.documentElement.style.setProperty( + "--textLayer-pointer-events", + "none" + ); + document.documentElement.style.setProperty( + "--textLayer-user-select", + "none" + ); + redactionMode = RedactionModes.DRAWING; + } + } + + function resetDrawRedactions() { + redactionMode = RedactionModes.NONE; + drawRedactionBtn.classList.remove("toggled"); + document.documentElement.style.setProperty( + "--textLayer-pointer-events", + "auto" + ); + document.documentElement.style.setProperty( + "--textLayer-user-select", + "auto" + ); + window.dispatchEvent(new CustomEvent("reset-drawing", { bubbles: true })); + } + + function initDraw(canvas, redactionsContainer) { + let mouse = { + x: 0, + y: 0, + startX: 0, + startY: 0, + }; + let element = null; + let drawnRedaction = null; + + window.addEventListener("reset-drawing", (e) => { + _clearDrawing(); + canvas.style.cursor = "default"; + document.documentElement.style.setProperty( + "--textLayer-pointer-events", + "auto" + ); + document.documentElement.style.setProperty( + "--textLayer-user-select", + "auto" + ); + }); + + window.addEventListener("drawing-entered", (e) => { + let target = e.detail?.target; + if (canvas === target) return; + _clearDrawing(); + }); + + window.addEventListener("cancel-drawing", (e) => { + _clearDrawing(); + canvas.style.cursor = "default"; + }); + + function setMousePosition(e) { + if (isChromium || isSafari || isWebkit) { + mouse.x = e.offsetX; + mouse.y = e.offsetY; + } else if (isFirefox || isGecko) { + mouse.x = e.layerX; + mouse.y = e.layerY; + } else { + let rect = (e.target || e.srcElement).getBoundingClientRect(); + mouse.x = e.clientX - rect.left; + mouse.y = e.clientY - rect.top; + } + } + + window.onkeydown = (e) => { + if (e.key === "Escape" && redactionMode === RedactionModes.DRAWING) { + window.dispatchEvent( + new CustomEvent("cancel-drawing", { bubbles: true }) + ); + } + }; + + canvas.onpointerenter = (e) => { + window.dispatchEvent( + new CustomEvent("drawing-entered", { + bubbles: true, + detail: { target: canvas }, + }) + ); + }; + + canvas.onpointerup = (e) => { + let isLeftClick = e.button == 0; + if (!isLeftClick) return; + + if (element !== null) { + _saveAndResetDrawnRedaction(); + console.log("finished."); + } + }; + + canvas.addEventListener("external-pointerup", (e) => { + if (element != null) { + _saveAndResetDrawnRedaction(); + } + }); + + canvas.onpointerleave = (e) => { + let ev = copyEvent(e, "pointerleave"); + let { left, top } = calculateMouseCoordinateToRotatedBox(canvas, e); + + ev.layerX = left; + ev.offsetX = left; + + ev.layerY = top; + ev.offsetY = top; + + setMousePosition(ev); + if (element !== null) { + draw(); + } + }; + + canvas.onpointerdown = (e) => { + let isLeftClick = e.button == 0; + if (!isLeftClick) return; + + if (element == null) { + if (redactionMode !== RedactionModes.DRAWING) { + console.warn( + "Drawing attempt when redaction mode is", + redactionMode.description + ); + return; + } + console.log("begun."); + _captureAndDrawStartingPointOfDrawnRedaction(); + } + }; + + canvas.onpointermove = function (e) { + setMousePosition(e); + if (element !== null) { + draw(); + } + }; + + function draw() { + let scaleFactor = _getScaleFactor(); + + let width = Math.abs(mouse.x - mouse.startX); + element.style.width = _toCalcZoomPx(_scaleToDisplay(width)); + + let height = Math.abs(mouse.y - mouse.startY); + element.style.height = _toCalcZoomPx(_scaleToDisplay(height)); + + let left = mouse.x - mouse.startX < 0 ? mouse.x : mouse.startX; + element.style.left = _toCalcZoomPx(_scaleToDisplay(left)); + + let top = mouse.y - mouse.startY < 0 ? mouse.y : mouse.startY; + element.style.top = _toCalcZoomPx(_scaleToDisplay(top)); + + if (drawnRedaction) { + drawnRedaction.left = _scaleToPDF(left, scaleFactor); + drawnRedaction.top = _scaleToPDF(top, scaleFactor); + drawnRedaction.width = _scaleToPDF(width, scaleFactor); + drawnRedaction.height = _scaleToPDF(height, scaleFactor); + } + } + + function _clearDrawing() { + if (element) element.remove(); + if (drawingLayer == canvas) drawingLayer = null; + element = null; + drawnRedaction = null; + } + + function _saveAndResetDrawnRedaction() { + if (!element) return; + if ( + !element.style.height || + element.style.height.includes("(0px * var") || + !element.style.width || + element.style.width.includes("(0px * var") + ) { + element.remove(); + } else { + element.classList.add("selected-wrapper"); + element.classList.remove("rectangle"); + + addRedactionOverlay(element, drawnRedaction, canvas); + redactions.push(drawnRedaction); + _setRedactionsInput(redactions); + } + drawingLayer = null; + element = null; + drawnRedaction = null; + canvas.style.cursor = "default"; + } + + function _captureAndDrawStartingPointOfDrawnRedaction() { + mouse.startX = mouse.x; + mouse.startY = mouse.y; + + element = document.createElement("div"); + element.className = "rectangle"; + drawingLayer = canvas; + + let left = mouse.x; + let top = mouse.y; + + element.style.left = _toCalcZoomPx(_scaleToDisplay(left)); + element.style.top = _toCalcZoomPx(_scaleToDisplay(top)); + + let scaleFactor = _getScaleFactor(); + let color = redactionsPalette.style.getPropertyValue("--palette-color"); + + element.style.setProperty("--palette-color", color); + + drawnRedaction = { + left: _scaleToPDF(left, scaleFactor), + top: _scaleToPDF(top, scaleFactor), + width: 0.0, + height: 0.0, + color: color, + pageNumber: parseInt(canvas.getAttribute("data-page")), + element: element, + id: UUID.uuidv4(), + }; + + redactionsContainer.appendChild(element); + canvas.style.cursor = "crosshair"; + } + } + }); + + PDFViewerApplication.eventBus.on("rotationchanging", (e) => { + if (!activeOverlay) return; + hideOverlay(); + }); + + function _getScaleFactor() { + return parseFloat(viewer.style.getPropertyValue("--scale-factor")); + } + + function getTextLayer(element) { + let current = element; + while (current) { + if ( + current instanceof HTMLDivElement && + current.classList.contains("textLayer") + ) + return current; + current = current.parentElement; + } + + return current; + } + + document.onclick = (e) => { + if ( + (e.target && + e.target.classList.contains("selected-wrapper") && + e.target.firstChild == activeOverlay) || + e.target == activeOverlay + ) + return; + if (activeOverlay) hideOverlay(); + }; + + document.addEventListener("keydown", (e) => { + if (e.key === "Delete" && activeOverlay) { + activeOverlay + .querySelector(".delete-icon") + ?.dispatchEvent(new Event("click", { bubbles: true })); + return; + } + const isRedactionShortcut = + e.ctrlKey && (e.key == "s" || e.key == "S" || e.code == "KeyS"); + if (!isRedactionShortcut || redactionMode !== RedactionModes.TEXT) return; + + redactTextSelection(); + }); + + function rotateTextBox(rect, textLayerRect, angle) { + let left, top, width, height; + if (!angle || angle == 0) { + left = rect.left - textLayerRect.left; + top = rect.top - textLayerRect.top; + width = rect.width; + height = rect.height; + } else if (angle == 90) { + left = rect.top - textLayerRect.top; + top = textLayerRect.right - rect.right; + width = rect.height; + height = rect.width; + } else if (angle == 180) { + left = textLayerRect.right - rect.right; + top = textLayerRect.bottom - rect.bottom; + width = rect.width; + height = rect.height; + } else if (angle == 270) { + left = textLayerRect.bottom - rect.bottom; + top = rect.left - textLayerRect.left; + width = rect.height; + height = rect.width; + } + + return { left, top, width, height }; + } + + function redactTextSelection() { + let selection = window.getSelection(); + if (!selection || selection.rangeCount <= 0) return; + let range = selection.getRangeAt(0); + + let textLayer = getTextLayer(range.startContainer); + if (!textLayer) return; + + const pageNumber = textLayer.getAttribute("data-page"); + let redactionsArea = textLayer.querySelector( + `#redactions-container-${pageNumber}` + ); + let textLayerRect = textLayer.getBoundingClientRect(); + + let rects = range.getClientRects(); + let scaleFactor = _getScaleFactor(); + + let color = redactionsPalette.style.getPropertyValue("--palette-color"); + + let angle = textLayer.getAttribute("data-main-rotation"); + for (const rect of rects) { + if (!rect || !rect.width || !rect.height) continue; + let redactionElement = document.createElement("div"); + redactionElement.classList.add("selected-wrapper"); + + let { left, top, width, height } = rotateTextBox( + rect, + textLayerRect, + angle + ); + + let leftDisplayScaled = _scaleToDisplay(left); + let topDisplayScaled = _scaleToDisplay(top); + let widthDisplayScaled = _scaleToDisplay(width); + let heightDisplayScaled = _scaleToDisplay(height); + + let redactionInfo = { + left: _scaleToPDF(left, scaleFactor), + top: _scaleToPDF(top, scaleFactor), + width: _scaleToPDF(width, scaleFactor), + height: _scaleToPDF(height, scaleFactor), + pageNumber: parseInt(pageNumber), + color: color, + element: redactionElement, + id: UUID.uuidv4(), + }; + + redactions.push(redactionInfo); + + redactionElement.style.left = _toCalcZoomPx(leftDisplayScaled); + redactionElement.style.top = _toCalcZoomPx(topDisplayScaled); + + redactionElement.style.width = _toCalcZoomPx(widthDisplayScaled); + redactionElement.style.height = _toCalcZoomPx(heightDisplayScaled); + redactionElement.style.setProperty("--palette-color", color); + + redactionsArea.appendChild(redactionElement); + + addRedactionOverlay(redactionElement, redactionInfo, textLayer); + } + + _setRedactionsInput(redactions); + applyRedactionBtn.disabled = true; + } + + function _scaleToDisplay(value) { + return value / zoomScaleValue; + } + + function _scaleToPDF(value, scaleFactor) { + if (!scaleFactor) + scaleFactor = document.documentElement.getPropertyValue("--scale-factor"); + return value / scaleFactor; + } + + function _toCalcZoomPx(val) { + return `calc(${val}px * var(--zoom-scale))`; + } + + function _setRedactionsInput(redactions) { + let stringifiedRedactions = JSON.stringify( + redactions.filter(_nonEmptyRedaction).map((red) => ({ + x: red.left, + y: red.top, + width: red.width, + height: red.height, + color: red.color, + page: red.pageNumber, + })) + ); + redactionsInput.value = stringifiedRedactions; + } + + function addRedactionOverlay(redactionElement, redactionInfo, textLayer) { + let redactionOverlay = document.createElement("div"); + + let deleteBtn = $( + `` + )[0]; + + deleteBtn.onclick = (e) => { + redactions = redactions.filter((red) => redactionInfo.id != red.id); + redactionElement.remove(); + _setRedactionsInput(redactions); + activeOverlay = null; + }; + + let colorPaletteLabel = $( + `` + )[0]; + + let colorPaletteInput = $(` + + `)[0]; + + colorPaletteLabel.appendChild(colorPaletteInput); + + colorPaletteLabel.onclick = (e) => { + if (colorPaletteLabel === e.target) { + e.stopPropagation(); + } + }; + + colorPaletteInput.onchange = (e) => { + let color = e.target.value; + redactionElement.style.setProperty("--palette-color", color); + let redactionIdx = redactions.findIndex( + (red) => redactionInfo.id === red.id + ); + if (redactionIdx < 0) return; + redactions[redactionIdx].color = color; + _setRedactionsInput(redactions); + }; + + redactionOverlay.appendChild(deleteBtn); + redactionOverlay.appendChild(colorPaletteLabel); + + redactionOverlay.classList.add("redaction-overlay"); + redactionOverlay.style.display = "none"; + + redactionElement.addEventListener("textLayer-reference-changed", (e) => { + textLayer = e.detail.textLayer; + }); + + redactionElement.onclick = (e) => { + if (e.target != redactionElement) return; + if (activeOverlay) hideOverlay(); + redactionElement.classList.add("active-redaction"); + activeOverlay = redactionOverlay; + _adjustActiveOverlayCoordinates(); + }; + + redactionElement.appendChild(redactionOverlay); + + // Adjust active overlay coordinates to avoid placing the overlay out of page bounds + function _adjustActiveOverlayCoordinates() { + activeOverlay.style.visibility = "hidden"; + activeOverlay.style.display = "flex"; + textLayer = textLayer || getTextLayer(redactionElement); + let angle = parseInt(textLayer.getAttribute("data-main-rotation")); + if (textLayer) + redactionOverlay.style.transform = `rotate(${angle * -1}deg)`; + + activeOverlay.style.removeProperty("left"); + activeOverlay.style.removeProperty("top"); + + let textRect = textLayer.getBoundingClientRect(); + let overlayRect = redactionOverlay.getBoundingClientRect(); + + let leftOffset = 0, + topOffset = 0; + if (overlayRect.right > textRect.right) { + leftOffset = textRect.right - overlayRect.right; + } else if (overlayRect.left < textRect.left) { + leftOffset = textRect.left - overlayRect.left; + } + + if (overlayRect.top < textRect.top) { + topOffset = textRect.top - overlayRect.top; + } else if (overlayRect.bottom > textRect.bottom) { + topOffset = textRect.bottom - overlayRect.bottom; + } + + switch (angle) { + case 90: + [leftOffset, topOffset] = [topOffset, -leftOffset]; + break; + case 180: + [leftOffset, topOffset] = [-leftOffset, -topOffset]; + break; + case 270: + [leftOffset, topOffset] = [-topOffset, leftOffset]; + break; + } + + if (leftOffset != 0) + activeOverlay.style.left = `calc(50% + ${leftOffset}px`; + if (topOffset != 0) + activeOverlay.style.top = `calc(100% + ${topOffset}px`; + activeOverlay.style.visibility = "unset"; + } + } +}); + +function calculateMouseCoordinateToRotatedBox(canvas, e) { + let textRect = canvas.getBoundingClientRect(); + let left, + top = 0; + let angle = parseInt(canvas.getAttribute("data-main-rotation")); + switch (angle) { + case 0: + left = clamp(e.pageX - textRect.left, 0, textRect.width); + top = clamp(e.pageY - textRect.top, 0, textRect.height); + break; + + case 90: + left = clamp(e.pageY - textRect.top, 0, textRect.height); + top = clamp(textRect.right - e.pageX, 0, textRect.width); + break; + case 180: + left = clamp(textRect.right - e.pageX, 0, textRect.width); + top = clamp(textRect.bottom - e.pageY, 0, textRect.width); + break; + case 270: + left = clamp(textRect.bottom - e.pageY, 0, textRect.height); + top = clamp(e.pageX - textRect.left, 0, textRect.width); + break; + } + return { left, top }; +} + +function clamp(value, min, max) { + return Math.max(min, Math.min(value, max)); +} + +function addPageRedactionPreviewToPages(pagesDetailed, totalPagesCount) { + if (pagesDetailed.all) { + addRedactedPagePreview("#viewer > .page"); + addRedactedThumbnailPreview("#thumbnailView > a > div.thumbnail"); + } else { + removeRedactedPagePreview(); + + setPageNumbersFromRange(pagesDetailed, totalPagesCount); + setPageNumbersFromNFunctions(pagesDetailed, totalPagesCount); + + let pageNumbers = Array.from(pagesDetailed.numbers); + if (pageNumbers?.length > 0) { + let pagesSelector = pageNumbers + .map((number) => `#viewer > .page[data-page-number="${number}"]`) + .join(","); + addRedactedPagePreview(pagesSelector); + let thumbnailSelector = pageNumbers + .map( + (number) => + `#thumbnailView > a > div.thumbnail[data-page-number="${number}"]` + ) + .join(","); + addRedactedThumbnailPreview(thumbnailSelector); + } + } +} + +function resetFieldFeedbackMessages(input, parentElement) { + if (parentElement) + parentElement + .querySelectorAll(".invalid-feedback") + .forEach((feedback) => feedback.remove()); + if (input) { + input.classList.remove("is-invalid"); + input.classList.remove("is-valid"); + } +} + +function displayFieldErrorMessages(input, errors) { + input.classList.add("is-invalid"); + errors.forEach((error) => { + let element = document.createElement("div"); + element.classList.add("invalid-feedback"); + element.classList.add("list-styling"); + element.textContent = error; + input.parentElement.appendChild(element); + }); +} + +function setPageRedactionColor(color) { + document.documentElement.style.setProperty("--page-redaction-color", color); +} + +function setPageNumbersFromNFunctions(pagesDetailed, totalPagesCount) { + pagesDetailed.functions.forEach((fun) => { + if (!isValidFunction(fun)) return; + for (let n = 1; n <= totalPagesCount; n++) { + let pageNumber = eval(fun); + if (!pageNumber || pageNumber <= 0 || pageNumber > totalPagesCount) + continue; + pagesDetailed.numbers.add(pageNumber); + } + }); +} + +function setPageNumbersFromRange(pagesDetailed, totalPagesCount) { + pagesDetailed.ranges.forEach((range) => { + for (let i = range.low; i <= range.high && i <= totalPagesCount; i++) { + pagesDetailed.numbers.add(i); + } + }); +} + +function hideOverlay() { + activeOverlay.style.display = "none"; + activeOverlay.parentElement.classList.remove("active-redaction"); + activeOverlay = null; +} + +function _isEmptyRedaction(redaction) { + return ( + redaction.left == null || + redaction.top == null || + redaction.width == null || + redaction.height == null || + redaction.pageNumber == null + ); +} + +function _nonEmptyRedaction(redaction) { + return !_isEmptyRedaction(redaction); +} + +function copyEvent(e, type) { + if (type == "pointerleave") + return { + layerX: e.layerX, + layerY: e.layerY, + pageX: e.pageX, + pageY: e.pageY, + clientX: e.clientX, + clientY: e.clientY, + button: e.button, + height: e.height, + width: e.width, + offsetX: e.offsetX, + offsetY: e.offsetY, + pointerId: e.pointerId, + pointerType: e.pointerType, + type: e.type, + screenX: e.screenX, + screenY: e.screenY, + tiltX: e.tiltX, + tiltY: e.tiltY, + x: e.x, + y: e.y, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + isPrimary: e.isPrimary, + isTrusted: e.isTrusted, + metaKey: e.metaKey, + pressure: e.pressure, + returnValue: e.returnValue, + shiftKey: e.shiftKey, + timeStamp: e.timeStamp, + which: e.which, + twist: e.twist, + tangentialPressure: e.tangentialPressure, + target: e.target, + srcElement: e.srcElement, + relatedTarget: e.relatedTarget, + rangeOffset: e.rangeOffset, + rangeParent: e.rangeParent, + explicitOriginalTarget: e.explicitOriginalTarget, + eventPhase: e.eventPhase, + detail: e.detail, + defaultPrevented: e.defaultPrevented, + currentTarget: e.currentTarget, + buttons: e.buttons, + azimuthAngle: e.azimuthAngle, + altitudeAngle: e.altitudeAngle, + }; + + return {}; +} diff --git a/src/main/resources/static/pdfjs-legacy/css/viewer-redact.css b/src/main/resources/static/pdfjs-legacy/css/viewer-redact.css new file mode 100644 index 00000000..c8ba631f --- /dev/null +++ b/src/main/resources/static/pdfjs-legacy/css/viewer-redact.css @@ -0,0 +1,5084 @@ +/* Copyright 2014 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.dialog { + --dialog-bg-color: white; + --dialog-border-color: white; + --dialog-shadow: 0 2px 14px 0 rgb(58 57 68 / 0.2); + --text-primary-color: #15141a; + --text-secondary-color: #5b5b66; + --hover-filter: brightness(0.9); + --focus-ring-color: #0060df; + --focus-ring-outline: 2px solid var(--focus-ring-color); + + --textarea-border-color: #8f8f9d; + --textarea-bg-color: white; + --textarea-fg-color: var(--text-secondary-color); + + --radio-bg-color: #f0f0f4; + --radio-checked-bg-color: #fbfbfe; + --radio-border-color: #8f8f9d; + --radio-checked-border-color: #0060df; + + --button-secondary-bg-color: #f0f0f4; + --button-secondary-fg-color: var(--text-primary-color); + --button-secondary-border-color: var(--button-secondary-bg-color); + --button-secondary-hover-bg-color: var(--button-secondary-bg-color); + --button-secondary-hover-fg-color: var(--button-secondary-fg-color); + --button-secondary-hover-border-color: var(--button-secondary-hover-bg-color); + + --button-primary-bg-color: #0060df; + --button-primary-fg-color: #fbfbfe; + --button-primary-hover-bg-color: var(--button-primary-bg-color); + --button-primary-hover-fg-color: var(--button-primary-fg-color); + --button-primary-hover-border-color: var(--button-primary-hover-bg-color); + + font: message-box; + font-size: 13px; + font-weight: 400; + line-height: 150%; + border-radius: 4px; + padding: 12px 16px; + border: 1px solid var(--dialog-border-color); + background: var(--dialog-bg-color); + color: var(--text-primary-color); + box-shadow: var(--dialog-shadow); +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) .dialog { + --dialog-bg-color: #1c1b22; + --dialog-border-color: #1c1b22; + --dialog-shadow: 0 2px 14px 0 #15141a; + --text-primary-color: #fbfbfe; + --text-secondary-color: #cfcfd8; + --focus-ring-color: #0df; + --hover-filter: brightness(1.4); + + --textarea-bg-color: #42414d; + + --radio-bg-color: #2b2a33; + --radio-checked-bg-color: #15141a; + --radio-checked-border-color: #0df; + + --button-secondary-bg-color: #2b2a33; + --button-primary-bg-color: #0df; + --button-primary-fg-color: #15141a; + } +} + +:where(html.is-dark) .dialog { + --dialog-bg-color: #1c1b22; + --dialog-border-color: #1c1b22; + --dialog-shadow: 0 2px 14px 0 #15141a; + --text-primary-color: #fbfbfe; + --text-secondary-color: #cfcfd8; + --focus-ring-color: #0df; + --hover-filter: brightness(1.4); + + --textarea-bg-color: #42414d; + + --radio-bg-color: #2b2a33; + --radio-checked-bg-color: #15141a; + --radio-checked-border-color: #0df; + + --button-secondary-bg-color: #2b2a33; + --button-primary-bg-color: #0df; + --button-primary-fg-color: #15141a; +} + +@media screen and (forced-colors: active) { + .dialog { + --dialog-bg-color: Canvas; + --dialog-border-color: CanvasText; + --dialog-shadow: none; + --text-primary-color: CanvasText; + --text-secondary-color: CanvasText; + --hover-filter: none; + --focus-ring-color: ButtonBorder; + + --textarea-border-color: ButtonBorder; + --textarea-bg-color: Field; + --textarea-fg-color: ButtonText; + + --radio-bg-color: ButtonFace; + --radio-checked-bg-color: ButtonFace; + --radio-border-color: ButtonText; + --radio-checked-border-color: ButtonText; + + --button-secondary-bg-color: ButtonFace; + --button-secondary-fg-color: ButtonText; + --button-secondary-border-color: ButtonText; + --button-secondary-hover-bg-color: AccentColor; + --button-secondary-hover-fg-color: AccentColorText; + + --button-primary-bg-color: ButtonText; + --button-primary-fg-color: ButtonFace; + --button-primary-hover-bg-color: AccentColor; + --button-primary-hover-fg-color: AccentColorText; + } +} + +.dialog .mainContainer *:focus-visible { + outline: var(--focus-ring-outline); + outline-offset: 2px; +} + +.dialog .mainContainer .radio { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; +} + +.dialog .mainContainer .radio > .radioButton { + display: flex; + gap: 8px; + align-self: stretch; + align-items: center; +} + +.dialog .mainContainer .radio > .radioButton input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + box-sizing: border-box; + width: 16px; + height: 16px; + border-radius: 50%; + background-color: var(--radio-bg-color); + border: 1px solid var(--radio-border-color); +} + +.dialog .mainContainer .radio > .radioButton input:hover { + filter: var(--hover-filter); +} + +.dialog .mainContainer .radio > .radioButton input:checked { + background-color: var(--radio-checked-bg-color); + border: 4px solid var(--radio-checked-border-color); +} + +.dialog .mainContainer .radio > .radioLabel { + display: flex; + padding-inline-start: 24px; + align-items: flex-start; + gap: 10px; + align-self: stretch; +} + +.dialog .mainContainer .radio > .radioLabel > span { + flex: 1 0 0; + font-size: 11px; + color: var(--text-secondary-color); +} + +.dialog .mainContainer button { + border-radius: 4px; + border: 1px solid; + font: menu; + font-weight: 600; + padding: 4px 16px; + width: auto; + height: 32px; +} + +.dialog .mainContainer button:hover { + cursor: pointer; + filter: var(--hover-filter); +} + +.dialog .mainContainer button.secondaryButton { + color: var(--button-secondary-fg-color); + background-color: var(--button-secondary-bg-color); + border-color: var(--button-secondary-border-color); +} + +.dialog .mainContainer button.secondaryButton:hover { + color: var(--button-secondary-hover-fg-color); + background-color: var(--button-secondary-hover-bg-color); + border-color: var(--button-secondary-hover-border-color); +} + +.dialog .mainContainer button.primaryButton { + color: var(--button-primary-hover-fg-color); + background-color: var(--button-primary-hover-bg-color); + border-color: var(--button-primary-hover-border-color); + opacity: 1; +} + +.dialog .mainContainer button.primaryButton:hover { + color: var(--button-primary-hover-fg-color); + background-color: var(--button-primary-hover-bg-color); + border-color: var(--button-primary-hover-border-color); +} + +.dialog .mainContainer textarea { + font: inherit; + padding: 8px; + resize: none; + margin: 0; + box-sizing: border-box; + border-radius: 4px; + border: 1px solid var(--textarea-border-color); + background: var(--textarea-bg-color); + color: var(--textarea-fg-color); +} + +.dialog .mainContainer textarea:focus { + outline-offset: 0; + border-color: transparent; +} + +.dialog .mainContainer textarea:disabled { + pointer-events: none; + opacity: 0.4; +} + +.textLayer { + position: absolute; + text-align: initial; + inset: 0; + overflow: clip; + opacity: 1; + line-height: 1; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + text-size-adjust: none; + forced-color-adjust: none; + transform-origin: 0 0; + caret-color: CanvasText; + z-index: 0; +} + +.textLayer.highlighting { + touch-action: none; +} + +.textLayer :is(span, br) { + color: transparent; + position: absolute; + white-space: pre; + cursor: text; + transform-origin: 0% 0%; +} + +.textLayer > :not(.markedContent), +.textLayer .markedContent span:not(.markedContent) { + z-index: 1; +} + +.textLayer span.markedContent { + top: 0; + height: 0; +} + +.textLayer .highlight { + --highlight-bg-color: rgb(180 0 170 / 0.25); + --highlight-selected-bg-color: rgb(0 100 0 / 0.25); + --highlight-backdrop-filter: none; + --highlight-selected-backdrop-filter: none; + + margin: -1px; + padding: 1px; + background-color: var(--highlight-bg-color); + -webkit-backdrop-filter: var(--highlight-backdrop-filter); + backdrop-filter: var(--highlight-backdrop-filter); + border-radius: 4px; +} + +@media screen and (forced-colors: active) { + .textLayer .highlight { + --highlight-bg-color: transparent; + --highlight-selected-bg-color: transparent; + --highlight-backdrop-filter: var(--hcm-highlight-filter); + --highlight-selected-backdrop-filter: var(--hcm-highlight-selected-filter); + } +} + +.textLayer .highlight.appended { + position: initial; +} + +.textLayer .highlight.begin { + border-radius: 4px 0 0 4px; +} + +.textLayer .highlight.end { + border-radius: 0 4px 4px 0; +} + +.textLayer .highlight.middle { + border-radius: 0; +} + +.textLayer .highlight.selected { + background-color: var(--highlight-selected-bg-color); + -webkit-backdrop-filter: var(--highlight-selected-backdrop-filter); + backdrop-filter: var(--highlight-selected-backdrop-filter); +} + +.textLayer ::-moz-selection { + background: rgba(0 0 255 / 0.25); + background: color-mix(in srgb, AccentColor, transparent 75%); +} + +.textLayer ::selection { + background: rgba(0 0 255 / 0.25); + background: color-mix(in srgb, AccentColor, transparent 75%); +} + +.textLayer br::-moz-selection { + background: transparent; +} + +.textLayer br::selection { + background: transparent; +} + +.textLayer .endOfContent { + display: block; + position: absolute; + inset: 100% 0 0; + z-index: 0; + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.textLayer .endOfContent.active { + top: 0; +} + +.annotationLayer { + --annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); + --input-focus-border-color: Highlight; + --input-focus-outline: 1px solid Canvas; + --input-unfocused-border-color: transparent; + --input-disabled-border-color: transparent; + --input-hover-border-color: black; + --link-outline: none; + + position: absolute; + top: 0; + left: 0; + pointer-events: none; + transform-origin: 0 0; +} + +@media screen and (forced-colors: active) { + .annotationLayer { + --input-focus-border-color: CanvasText; + --input-unfocused-border-color: ActiveText; + --input-disabled-border-color: GrayText; + --input-hover-border-color: Highlight; + --link-outline: 1.5px solid LinkText; + } + + .annotationLayer .textWidgetAnnotation :is(input, textarea):required, + .annotationLayer .choiceWidgetAnnotation select:required, + .annotationLayer + .buttonWidgetAnnotation:is(.checkBox, .radioButton) + input:required { + outline: 1.5px solid selectedItem; + } + + .annotationLayer .linkAnnotation { + outline: var(--link-outline); + } + + .annotationLayer .linkAnnotation:hover { + -webkit-backdrop-filter: var(--hcm-highlight-filter); + backdrop-filter: var(--hcm-highlight-filter); + } + + .annotationLayer .linkAnnotation > a:hover { + opacity: 0 !important; + background: none !important; + box-shadow: none; + } + + .annotationLayer .popupAnnotation .popup { + outline: calc(1.5px * var(--scale-factor)) solid CanvasText !important; + background-color: ButtonFace !important; + color: ButtonText !important; + } + + .annotationLayer .highlightArea:hover::after { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-backdrop-filter: var(--hcm-highlight-filter); + backdrop-filter: var(--hcm-highlight-filter); + content: ""; + pointer-events: none; + } + + .annotationLayer .popupAnnotation.focused .popup { + outline: calc(3px * var(--scale-factor)) solid Highlight !important; + } +} + +.annotationLayer[data-main-rotation="90"] .norotate { + transform: rotate(270deg) translateX(-100%); +} + +.annotationLayer[data-main-rotation="180"] .norotate { + transform: rotate(180deg) translate(-100%, -100%); +} + +.annotationLayer[data-main-rotation="270"] .norotate { + transform: rotate(90deg) translateY(-100%); +} + +.annotationLayer.disabled section, +.annotationLayer.disabled .popup { + pointer-events: none; +} + +.annotationLayer .annotationContent { + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; +} + +.annotationLayer .annotationContent.freetext { + background: transparent; + border: none; + inset: 0; + overflow: visible; + white-space: nowrap; + font: 10px sans-serif; + line-height: 1.35; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.annotationLayer section { + position: absolute; + text-align: initial; + pointer-events: auto; + box-sizing: border-box; + transform-origin: 0 0; +} + +.annotationLayer section:has(div.annotationContent) canvas.annotationContent { + display: none; +} + +.annotationLayer :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton) > a { + position: absolute; + font-size: 1em; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.annotationLayer + :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder) + > a:hover { + opacity: 0.2; + background-color: rgb(255 255 0); + box-shadow: 0 2px 10px rgb(255 255 0); +} + +.annotationLayer .linkAnnotation.hasBorder:hover { + background-color: rgb(255 255 0 / 0.2); +} + +.annotationLayer .hasBorder { + background-size: 100% 100%; +} + +.annotationLayer .textAnnotation img { + position: absolute; + cursor: pointer; + width: 100%; + height: 100%; + top: 0; + left: 0; +} + +.annotationLayer .textWidgetAnnotation :is(input, textarea), +.annotationLayer .choiceWidgetAnnotation select, +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input { + background-image: var(--annotation-unfocused-field-background); + border: 2px solid var(--input-unfocused-border-color); + box-sizing: border-box; + font: calc(9px * var(--scale-factor)) sans-serif; + height: 100%; + margin: 0; + vertical-align: top; + width: 100%; +} + +.annotationLayer .textWidgetAnnotation :is(input, textarea):required, +.annotationLayer .choiceWidgetAnnotation select:required, +.annotationLayer + .buttonWidgetAnnotation:is(.checkBox, .radioButton) + input:required { + outline: 1.5px solid red; +} + +.annotationLayer .choiceWidgetAnnotation select option { + padding: 0; +} + +.annotationLayer .buttonWidgetAnnotation.radioButton input { + border-radius: 50%; +} + +.annotationLayer .textWidgetAnnotation textarea { + resize: none; +} + +.annotationLayer .textWidgetAnnotation [disabled]:is(input, textarea), +.annotationLayer .choiceWidgetAnnotation select[disabled], +.annotationLayer + .buttonWidgetAnnotation:is(.checkBox, .radioButton) + input[disabled] { + background: none; + border: 2px solid var(--input-disabled-border-color); + cursor: not-allowed; +} + +.annotationLayer .textWidgetAnnotation :is(input, textarea):hover, +.annotationLayer .choiceWidgetAnnotation select:hover, +.annotationLayer + .buttonWidgetAnnotation:is(.checkBox, .radioButton) + input:hover { + border: 2px solid var(--input-hover-border-color); +} + +.annotationLayer .textWidgetAnnotation :is(input, textarea):hover, +.annotationLayer .choiceWidgetAnnotation select:hover, +.annotationLayer .buttonWidgetAnnotation.checkBox input:hover { + border-radius: 2px; +} + +.annotationLayer .textWidgetAnnotation :is(input, textarea):focus, +.annotationLayer .choiceWidgetAnnotation select:focus { + background: none; + border: 2px solid var(--input-focus-border-color); + border-radius: 2px; + outline: var(--input-focus-outline); +} + +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) :focus { + background-image: none; + background-color: transparent; +} + +.annotationLayer .buttonWidgetAnnotation.checkBox :focus { + border: 2px solid var(--input-focus-border-color); + border-radius: 2px; + outline: var(--input-focus-outline); +} + +.annotationLayer .buttonWidgetAnnotation.radioButton :focus { + border: 2px solid var(--input-focus-border-color); + outline: var(--input-focus-outline); +} + +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::before, +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::after, +.annotationLayer .buttonWidgetAnnotation.radioButton input:checked::before { + background-color: CanvasText; + content: ""; + display: block; + position: absolute; +} + +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::before, +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::after { + height: 80%; + left: 45%; + width: 1px; +} + +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::before { + transform: rotate(45deg); +} + +.annotationLayer .buttonWidgetAnnotation.checkBox input:checked::after { + transform: rotate(-45deg); +} + +.annotationLayer .buttonWidgetAnnotation.radioButton input:checked::before { + border-radius: 50%; + height: 50%; + left: 25%; + top: 25%; + width: 50%; +} + +.annotationLayer .textWidgetAnnotation input.comb { + font-family: monospace; + padding-left: 2px; + padding-right: 0; +} + +.annotationLayer .textWidgetAnnotation input.comb:focus { + width: 103%; +} + +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.annotationLayer .fileAttachmentAnnotation .popupTriggerArea { + height: 100%; + width: 100%; +} + +.annotationLayer .popupAnnotation { + position: absolute; + font-size: calc(9px * var(--scale-factor)); + pointer-events: none; + width: -moz-max-content; + width: max-content; + max-width: 45%; + height: auto; +} + +.annotationLayer .popup { + background-color: rgb(255 255 153); + box-shadow: 0 calc(2px * var(--scale-factor)) calc(5px * var(--scale-factor)) + rgb(136 136 136); + border-radius: calc(2px * var(--scale-factor)); + outline: 1.5px solid rgb(255 255 74); + padding: calc(6px * var(--scale-factor)); + cursor: pointer; + font: message-box; + white-space: normal; + word-wrap: break-word; + pointer-events: auto; +} + +.annotationLayer .popupAnnotation.focused .popup { + outline-width: 3px; +} + +.annotationLayer .popup * { + font-size: calc(9px * var(--scale-factor)); +} + +.annotationLayer .popup > .header { + display: inline-block; +} + +.annotationLayer .popup > .header h1 { + display: inline; +} + +.annotationLayer .popup > .header .popupDate { + display: inline-block; + margin-left: calc(5px * var(--scale-factor)); + width: -moz-fit-content; + width: fit-content; +} + +.annotationLayer .popupContent { + border-top: 1px solid rgb(51 51 51); + margin-top: calc(2px * var(--scale-factor)); + padding-top: calc(2px * var(--scale-factor)); +} + +.annotationLayer .richText > * { + white-space: pre-wrap; + font-size: calc(9px * var(--scale-factor)); +} + +.annotationLayer .popupTriggerArea { + cursor: pointer; +} + +.annotationLayer section svg { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; +} + +.annotationLayer .annotationTextContent { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + pointer-events: none; +} + +.annotationLayer .annotationTextContent span { + width: 100%; + display: inline-block; +} + +.annotationLayer svg.quadrilateralsContainer { + contain: strict; + width: 0; + height: 0; + position: absolute; + top: 0; + left: 0; + z-index: -1; +} + +:root { + --xfa-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); + --xfa-focus-outline: auto; +} + +@media screen and (forced-colors: active) { + :root { + --xfa-focus-outline: 2px solid CanvasText; + } + .xfaLayer *:required { + outline: 1.5px solid selectedItem; + } +} + +.xfaLayer { + background-color: transparent; +} + +.xfaLayer .highlight { + margin: -1px; + padding: 1px; + background-color: rgb(239 203 237); + border-radius: 4px; +} + +.xfaLayer .highlight.appended { + position: initial; +} + +.xfaLayer .highlight.begin { + border-radius: 4px 0 0 4px; +} + +.xfaLayer .highlight.end { + border-radius: 0 4px 4px 0; +} + +.xfaLayer .highlight.middle { + border-radius: 0; +} + +.xfaLayer .highlight.selected { + background-color: rgb(203 223 203); +} + +.xfaPage { + overflow: hidden; + position: relative; +} + +.xfaContentarea { + position: absolute; +} + +.xfaPrintOnly { + display: none; +} + +.xfaLayer { + position: absolute; + text-align: initial; + top: 0; + left: 0; + transform-origin: 0 0; + line-height: 1.2; +} + +.xfaLayer * { + color: inherit; + font: inherit; + font-style: inherit; + font-weight: inherit; + font-kerning: inherit; + letter-spacing: -0.01px; + text-align: inherit; + text-decoration: inherit; + box-sizing: border-box; + background-color: transparent; + padding: 0; + margin: 0; + pointer-events: auto; + line-height: inherit; +} + +.xfaLayer *:required { + outline: 1.5px solid red; +} + +.xfaLayer div, +.xfaLayer svg, +.xfaLayer svg * { + pointer-events: none; +} + +.xfaLayer a { + color: blue; +} + +.xfaRich li { + margin-left: 3em; +} + +.xfaFont { + color: black; + font-weight: normal; + font-kerning: none; + font-size: 10px; + font-style: normal; + letter-spacing: 0; + text-decoration: none; + vertical-align: 0; +} + +.xfaCaption { + overflow: hidden; + flex: 0 0 auto; +} + +.xfaCaptionForCheckButton { + overflow: hidden; + flex: 1 1 auto; +} + +.xfaLabel { + height: 100%; + width: 100%; +} + +.xfaLeft { + display: flex; + flex-direction: row; + align-items: center; +} + +.xfaRight { + display: flex; + flex-direction: row-reverse; + align-items: center; +} + +:is(.xfaLeft, .xfaRight) > :is(.xfaCaption, .xfaCaptionForCheckButton) { + max-height: 100%; +} + +.xfaTop { + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.xfaBottom { + display: flex; + flex-direction: column-reverse; + align-items: flex-start; +} + +:is(.xfaTop, .xfaBottom) > :is(.xfaCaption, .xfaCaptionForCheckButton) { + width: 100%; +} + +.xfaBorder { + background-color: transparent; + position: absolute; + pointer-events: none; +} + +.xfaWrapped { + width: 100%; + height: 100%; +} + +:is(.xfaTextfield, .xfaSelect):focus { + background-image: none; + background-color: transparent; + outline: var(--xfa-focus-outline); + outline-offset: -1px; +} + +:is(.xfaCheckbox, .xfaRadio):focus { + outline: var(--xfa-focus-outline); +} + +.xfaTextfield, +.xfaSelect { + height: 100%; + width: 100%; + flex: 1 1 auto; + border: none; + resize: none; + background-image: var(--xfa-unfocused-field-background); +} + +.xfaSelect { + padding-inline: 2px; +} + +:is(.xfaTop, .xfaBottom) > :is(.xfaTextfield, .xfaSelect) { + flex: 0 1 auto; +} + +.xfaButton { + cursor: pointer; + width: 100%; + height: 100%; + border: none; + text-align: center; +} + +.xfaLink { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.xfaCheckbox, +.xfaRadio { + width: 100%; + height: 100%; + flex: 0 0 auto; + border: none; +} + +.xfaRich { + white-space: pre-wrap; + width: 100%; + height: 100%; +} + +.xfaImage { + -o-object-position: left top; + object-position: left top; + -o-object-fit: contain; + object-fit: contain; + width: 100%; + height: 100%; +} + +.xfaLrTb, +.xfaRlTb, +.xfaTb { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.xfaLr { + display: flex; + flex-direction: row; + align-items: stretch; +} + +.xfaRl { + display: flex; + flex-direction: row-reverse; + align-items: stretch; +} + +.xfaTb > div { + justify-content: left; +} + +.xfaPosition { + position: relative; +} + +.xfaArea { + position: relative; +} + +.xfaValignMiddle { + display: flex; + align-items: center; +} + +.xfaTable { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.xfaTable .xfaRow { + display: flex; + flex-direction: row; + align-items: stretch; +} + +.xfaTable .xfaRlRow { + display: flex; + flex-direction: row-reverse; + align-items: stretch; + flex: 1; +} + +.xfaTable .xfaRlRow > div { + flex: 1; +} + +:is(.xfaNonInteractive, .xfaDisabled, .xfaReadOnly) :is(input, textarea) { + background: initial; +} + +@media print { + .xfaTextfield, + .xfaSelect { + background: transparent; + } + + .xfaSelect { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + text-indent: 1px; + text-overflow: ""; + } +} + +.canvasWrapper svg { + transform: none; +} + +.canvasWrapper svg[data-main-rotation="90"] mask, +.canvasWrapper svg[data-main-rotation="90"] use:not(.clip, .mask) { + transform: matrix(0, 1, -1, 0, 1, 0); +} + +.canvasWrapper svg[data-main-rotation="180"] mask, +.canvasWrapper svg[data-main-rotation="180"] use:not(.clip, .mask) { + transform: matrix(-1, 0, 0, -1, 1, 1); +} + +.canvasWrapper svg[data-main-rotation="270"] mask, +.canvasWrapper svg[data-main-rotation="270"] use:not(.clip, .mask) { + transform: matrix(0, -1, 1, 0, 0, 1); +} + +.canvasWrapper svg.highlight { + --blend-mode: multiply; + + position: absolute; + mix-blend-mode: var(--blend-mode); +} + +@media screen and (forced-colors: active) { + .canvasWrapper svg.highlight { + --blend-mode: difference; + } +} + +.canvasWrapper svg.highlight:not(.free) { + fill-rule: evenodd; +} + +.canvasWrapper svg.highlightOutline { + position: absolute; + mix-blend-mode: normal; + fill-rule: evenodd; + fill: none; +} + +.canvasWrapper svg.highlightOutline.hovered:not(.free):not(.selected) { + stroke: var(--hover-outline-color); + stroke-width: var(--outline-width); +} + +.canvasWrapper svg.highlightOutline.selected:not(.free) .mainOutline { + stroke: var(--outline-around-color); + stroke-width: calc(var(--outline-width) + 2 * var(--outline-around-width)); +} + +.canvasWrapper svg.highlightOutline.selected:not(.free) .secondaryOutline { + stroke: var(--outline-color); + stroke-width: var(--outline-width); +} + +.canvasWrapper svg.highlightOutline.free.hovered:not(.selected) { + stroke: var(--hover-outline-color); + stroke-width: calc(2 * var(--outline-width)); +} + +.canvasWrapper svg.highlightOutline.free.selected .mainOutline { + stroke: var(--outline-around-color); + stroke-width: calc(2 * (var(--outline-width) + var(--outline-around-width))); +} + +.canvasWrapper svg.highlightOutline.free.selected .secondaryOutline { + stroke: var(--outline-color); + stroke-width: calc(2 * var(--outline-width)); +} + +.toggle-button { + --button-background-color: #f0f0f4; + --button-background-color-hover: #e0e0e6; + --button-background-color-active: #cfcfd8; + --color-accent-primary: #0060df; + --color-accent-primary-hover: #0250bb; + --color-accent-primary-active: #054096; + --border-interactive-color: #8f8f9d; + --border-radius-circle: 9999px; + --border-width: 1px; + --size-item-small: 16px; + --size-item-large: 32px; + --color-canvas: white; + + --toggle-background-color: var(--button-background-color); + --toggle-background-color-hover: var(--button-background-color-hover); + --toggle-background-color-active: var(--button-background-color-active); + --toggle-background-color-pressed: var(--color-accent-primary); + --toggle-background-color-pressed-hover: var(--color-accent-primary-hover); + --toggle-background-color-pressed-active: var(--color-accent-primary-active); + --toggle-border-color: var(--border-interactive-color); + --toggle-border-color-hover: var(--toggle-border-color); + --toggle-border-color-active: var(--toggle-border-color); + --toggle-border-radius: var(--border-radius-circle); + --toggle-border-width: var(--border-width); + --toggle-height: var(--size-item-small); + --toggle-width: var(--size-item-large); + --toggle-dot-background-color: var(--toggle-border-color); + --toggle-dot-background-color-hover: var(--toggle-dot-background-color); + --toggle-dot-background-color-active: var(--toggle-dot-background-color); + --toggle-dot-background-color-on-pressed: var(--color-canvas); + --toggle-dot-margin: 1px; + --toggle-dot-height: calc( + var(--toggle-height) - 2 * var(--toggle-dot-margin) - 2 * + var(--toggle-border-width) + ); + --toggle-dot-width: var(--toggle-dot-height); + --toggle-dot-transform-x: calc( + var(--toggle-width) - 4 * var(--toggle-dot-margin) - var(--toggle-dot-width) + ); + + -webkit-appearance: none; + + -moz-appearance: none; + + appearance: none; + padding: 0; + margin: 0; + border: var(--toggle-border-width) solid var(--toggle-border-color); + height: var(--toggle-height); + width: var(--toggle-width); + border-radius: var(--toggle-border-radius); + background: var(--toggle-background-color); + box-sizing: border-box; + flex-shrink: 0; +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) .toggle-button { + --button-background-color: color-mix(in srgb, currentColor 7%, transparent); + --button-background-color-hover: color-mix( + in srgb, + currentColor 14%, + transparent + ); + --button-background-color-active: color-mix( + in srgb, + currentColor 21%, + transparent + ); + --color-accent-primary: #0df; + --color-accent-primary-hover: #80ebff; + --color-accent-primary-active: #aaf2ff; + --border-interactive-color: #bfbfc9; + --color-canvas: #1c1b22; + } +} + +:where(html.is-dark) .toggle-button { + --button-background-color: color-mix(in srgb, currentColor 7%, transparent); + --button-background-color-hover: color-mix( + in srgb, + currentColor 14%, + transparent + ); + --button-background-color-active: color-mix( + in srgb, + currentColor 21%, + transparent + ); + --color-accent-primary: #0df; + --color-accent-primary-hover: #80ebff; + --color-accent-primary-active: #aaf2ff; + --border-interactive-color: #bfbfc9; + --color-canvas: #1c1b22; +} + +@media (forced-colors: active) { + .toggle-button { + --color-accent-primary: ButtonText; + --color-accent-primary-hover: SelectedItem; + --color-accent-primary-active: SelectedItem; + --border-interactive-color: ButtonText; + --button-background-color: ButtonFace; + --border-interactive-color-hover: SelectedItem; + --border-interactive-color-active: SelectedItem; + --border-interactive-color-disabled: GrayText; + --color-canvas: ButtonText; + } +} + +.toggle-button:focus-visible { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); +} + +.toggle-button:enabled:hover { + background: var(--toggle-background-color-hover); + border-color: var(--toggle-border-color); +} + +.toggle-button:enabled:active { + background: var(--toggle-background-color-active); + border-color: var(--toggle-border-color); +} + +.toggle-button[aria-pressed="true"] { + background: var(--toggle-background-color-pressed); + border-color: transparent; +} + +.toggle-button[aria-pressed="true"]:enabled:hover { + background: var(--toggle-background-color-pressed-hover); + border-color: transparent; +} + +.toggle-button[aria-pressed="true"]:enabled:active { + background: var(--toggle-background-color-pressed-active); + border-color: transparent; +} + +.toggle-button::before { + display: block; + content: ""; + background-color: var(--toggle-dot-background-color); + height: var(--toggle-dot-height); + width: var(--toggle-dot-width); + margin: var(--toggle-dot-margin); + border-radius: var(--toggle-border-radius); + translate: 0; +} + +.toggle-button[aria-pressed="true"]::before { + translate: var(--toggle-dot-transform-x); + background-color: var(--toggle-dot-background-color-on-pressed); +} + +.toggle-button[aria-pressed="true"]:enabled:hover::before, +.toggle-button[aria-pressed="true"]:enabled:active::before { + background-color: var(--toggle-dot-background-color-on-pressed); +} + +[dir="rtl"] .toggle-button[aria-pressed="true"]::before { + translate: calc(-1 * var(--toggle-dot-transform-x)); +} + +@media (prefers-reduced-motion: no-preference) { + .toggle-button::before { + transition: translate 100ms; + } +} + +@media (prefers-contrast) { + .toggle-button:enabled:hover { + border-color: var(--toggle-border-color-hover); + } + + .toggle-button:enabled:active { + border-color: var(--toggle-border-color-active); + } + + .toggle-button[aria-pressed="true"]:enabled { + border-color: var(--toggle-border-color); + position: relative; + } + + .toggle-button[aria-pressed="true"]:enabled:hover, + .toggle-button[aria-pressed="true"]:enabled:hover:active { + border-color: var(--toggle-border-color-hover); + } + + .toggle-button[aria-pressed="true"]:enabled:active { + background-color: var(--toggle-dot-background-color-active); + border-color: var(--toggle-dot-background-color-hover); + } + + .toggle-button:hover::before, + .toggle-button:active::before { + background-color: var(--toggle-dot-background-color-hover); + } +} + +@media (forced-colors) { + .toggle-button { + --toggle-dot-background-color: var(--color-accent-primary); + --toggle-dot-background-color-hover: var(--color-accent-primary-hover); + --toggle-dot-background-color-active: var(--color-accent-primary-active); + --toggle-dot-background-color-on-pressed: var(--button-background-color); + --toggle-background-color-disabled: var(--button-background-color-disabled); + --toggle-border-color-hover: var(--border-interactive-color-hover); + --toggle-border-color-active: var(--border-interactive-color-active); + --toggle-border-color-disabled: var(--border-interactive-color-disabled); + } + + .toggle-button[aria-pressed="true"]:enabled::after { + border: 1px solid var(--button-background-color); + content: ""; + position: absolute; + height: var(--toggle-height); + width: var(--toggle-width); + display: block; + border-radius: var(--toggle-border-radius); + inset: -2px; + } + + .toggle-button[aria-pressed="true"]:enabled:active::after { + border-color: var(--toggle-border-color-active); + } +} + +:root { + --navbar-height: 64px; + --outline-width: 2px; + --outline-color: #0060df; + --outline-around-width: 1px; + --outline-around-color: #f0f0f4; + --hover-outline-around-color: var(--outline-around-color); + --focus-outline: solid var(--outline-width) var(--outline-color); + --unfocus-outline: solid var(--outline-width) transparent; + --focus-outline-around: solid var(--outline-around-width) + var(--outline-around-color); + --hover-outline-color: #8f8f9d; + --hover-outline: solid var(--outline-width) var(--hover-outline-color); + --hover-outline-around: solid var(--outline-around-width) + var(--hover-outline-around-color); + --freetext-line-height: 1.35; + --freetext-padding: 2px; + --resizer-bg-color: var(--outline-color); + --resizer-size: 6px; + --resizer-shift: calc( + 0px - (var(--outline-width) + var(--resizer-size)) / 2 - + var(--outline-around-width) + ); + --editorFreeText-editing-cursor: text; + --editorInk-editing-cursor: url(../images/cursor-editorInk.svg) 0 16, pointer; + --editorHighlight-editing-cursor: url(../images/cursor-editorTextHighlight.svg) + 24 24, + text; + --editorFreeHighlight-editing-cursor: url(../images/cursor-editorFreeHighlight.svg) + 1 18, + pointer; +} +.visuallyHidden { + position: absolute; + top: 0; + left: 0; + border: 0; + margin: 0; + padding: 0; + width: 0; + height: 0; + overflow: hidden; + white-space: nowrap; + font-size: 0; +} + +.textLayer.highlighting { + cursor: var(--editorFreeHighlight-editing-cursor); +} + +.textLayer.highlighting:not(.free) span { + cursor: var(--editorHighlight-editing-cursor); +} + +.textLayer.highlighting.free span { + cursor: var(--editorFreeHighlight-editing-cursor); +} + +@media (min-resolution: 1.1dppx) { + :root { + --editorFreeText-editing-cursor: url(../images/cursor-editorFreeText.svg) 0 + 16, + text; + } +} + +@media screen and (forced-colors: active) { + :root { + --outline-color: CanvasText; + --outline-around-color: ButtonFace; + --resizer-bg-color: ButtonText; + --hover-outline-color: Highlight; + --hover-outline-around-color: SelectedItemText; + } +} + +[data-editor-rotation="90"] { + transform: rotate(90deg); +} + +[data-editor-rotation="180"] { + transform: rotate(180deg); +} + +[data-editor-rotation="270"] { + transform: rotate(270deg); +} + +.annotationEditorLayer { + background: transparent; + position: absolute; + inset: 0; + font-size: calc(100px * var(--scale-factor)); + transform-origin: 0 0; + cursor: auto; +} + +.annotationEditorLayer.waiting { + content: ""; + cursor: wait; + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.annotationEditorLayer.disabled { + pointer-events: none; +} + +.annotationEditorLayer.freetextEditing { + cursor: var(--editorFreeText-editing-cursor); +} + +.annotationEditorLayer.inkEditing { + cursor: var(--editorInk-editing-cursor); +} + +.annotationEditorLayer :is(.freeTextEditor, .inkEditor, .stampEditor) { + position: absolute; + background: transparent; + z-index: 1; + transform-origin: 0 0; + cursor: auto; + max-width: 100%; + max-height: 100%; + border: var(--unfocus-outline); +} + +.annotationEditorLayer + .draggable.selectedEditor:is(.freeTextEditor, .inkEditor, .stampEditor) { + cursor: move; +} + +.annotationEditorLayer .moving:is(.freeTextEditor, .inkEditor, .stampEditor) { + touch-action: none; +} + +.annotationEditorLayer + .selectedEditor:is(.freeTextEditor, .inkEditor, .stampEditor) { + border: var(--focus-outline); + outline: var(--focus-outline-around); +} + +.annotationEditorLayer + .selectedEditor:is(.freeTextEditor, .inkEditor, .stampEditor)::before { + content: ""; + position: absolute; + inset: 0; + border: var(--focus-outline-around); + pointer-events: none; +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor):hover:not(.selectedEditor) { + border: var(--hover-outline); + outline: var(--hover-outline-around); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor):hover:not( + .selectedEditor + )::before { + content: ""; + position: absolute; + inset: 0; + border: var(--focus-outline-around); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + --editor-toolbar-delete-image: url(../images/editor-toolbar-delete.svg); + --editor-toolbar-bg-color: #f0f0f4; + --editor-toolbar-highlight-image: url(../images/toolbarButton-editorHighlight.svg); + --editor-toolbar-fg-color: #2e2e56; + --editor-toolbar-border-color: #8f8f9d; + --editor-toolbar-hover-border-color: var(--editor-toolbar-border-color); + --editor-toolbar-hover-bg-color: #e0e0e6; + --editor-toolbar-hover-fg-color: var(--editor-toolbar-fg-color); + --editor-toolbar-hover-outline: none; + --editor-toolbar-focus-outline-color: #0060df; + --editor-toolbar-shadow: 0 2px 6px 0 rgb(58 57 68 / 0.2); + --editor-toolbar-vert-offset: 6px; + --editor-toolbar-height: 28px; + --editor-toolbar-padding: 2px; + + display: flex; + width: -moz-fit-content; + width: fit-content; + height: var(--editor-toolbar-height); + flex-direction: column; + justify-content: center; + align-items: center; + cursor: default; + pointer-events: auto; + box-sizing: content-box; + padding: var(--editor-toolbar-padding); + + position: absolute; + inset-inline-end: 0; + inset-block-start: calc(100% + var(--editor-toolbar-vert-offset)); + + border-radius: 6px; + background-color: var(--editor-toolbar-bg-color); + border: 1px solid var(--editor-toolbar-border-color); + box-shadow: var(--editor-toolbar-shadow); +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + --editor-toolbar-bg-color: #2b2a33; + --editor-toolbar-fg-color: #fbfbfe; + --editor-toolbar-hover-bg-color: #52525e; + --editor-toolbar-focus-outline-color: #0df; + } +} + +:where(html.is-dark) + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + --editor-toolbar-bg-color: #2b2a33; + --editor-toolbar-fg-color: #fbfbfe; + --editor-toolbar-hover-bg-color: #52525e; + --editor-toolbar-focus-outline-color: #0df; +} + +@media screen and (forced-colors: active) { + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + --editor-toolbar-bg-color: ButtonFace; + --editor-toolbar-fg-color: ButtonText; + --editor-toolbar-border-color: ButtonText; + --editor-toolbar-hover-border-color: AccentColor; + --editor-toolbar-hover-bg-color: ButtonFace; + --editor-toolbar-hover-fg-color: AccentColor; + --editor-toolbar-hover-outline: 2px solid + var(--editor-toolbar-hover-border-color); + --editor-toolbar-focus-outline-color: ButtonBorder; + --editor-toolbar-shadow: none; + } +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar.hidden { + display: none; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar:has(:focus-visible) { + border-color: transparent; +} + +[dir="ltr"] + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + transform-origin: 100% 0; +} + +[dir="rtl"] + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar { + transform-origin: 0 0; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons { + display: flex; + justify-content: center; + align-items: center; + gap: 0; + height: 100%; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .divider { + width: 1px; + height: calc( + 2 * var(--editor-toolbar-padding) + var(--editor-toolbar-height) + ); + background-color: var(--editor-toolbar-border-color); + display: inline-block; + margin-inline: 2px; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .highlightButton { + width: var(--editor-toolbar-height); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .highlightButton::before { + content: ""; + -webkit-mask-image: var(--editor-toolbar-highlight-image); + mask-image: var(--editor-toolbar-highlight-image); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + display: inline-block; + background-color: var(--editor-toolbar-fg-color); + width: 100%; + height: 100%; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .highlightButton:hover::before { + background-color: var(--editor-toolbar-hover-fg-color); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .delete { + width: var(--editor-toolbar-height); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .delete::before { + content: ""; + -webkit-mask-image: var(--editor-toolbar-delete-image); + mask-image: var(--editor-toolbar-delete-image); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + display: inline-block; + background-color: var(--editor-toolbar-fg-color); + width: 100%; + height: 100%; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .delete:hover::before { + background-color: var(--editor-toolbar-hover-fg-color); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + > * { + height: var(--editor-toolbar-height); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + > :not(.divider) { + border: none; + background-color: transparent; + cursor: pointer; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + > :not(.divider):hover { + border-radius: 2px; + background-color: var(--editor-toolbar-hover-bg-color); + color: var(--editor-toolbar-hover-fg-color); + outline: var(--editor-toolbar-hover-outline); + outline-offset: 1px; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + > :not(.divider):hover:active { + outline: none; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + > :not(.divider):focus-visible { + border-radius: 2px; + outline: 2px solid var(--editor-toolbar-focus-outline-color); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText { + --alt-text-add-image: url(../images/altText_add.svg); + --alt-text-done-image: url(../images/altText_done.svg); + + display: flex; + align-items: center; + justify-content: center; + width: -moz-max-content; + width: max-content; + padding-inline: 8px; + pointer-events: all; + font: menu; + font-weight: 590; + font-size: 12px; + color: var(--editor-toolbar-fg-color); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText:disabled { + pointer-events: none; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText::before { + content: ""; + -webkit-mask-image: var(--alt-text-add-image); + mask-image: var(--alt-text-add-image); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + display: inline-block; + width: 12px; + height: 13px; + background-color: var(--editor-toolbar-fg-color); + margin-inline-end: 4px; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText:hover::before { + background-color: var(--editor-toolbar-hover-fg-color); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText.done::before { + -webkit-mask-image: var(--alt-text-done-image); + mask-image: var(--alt-text-done-image); +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText + .tooltip { + display: none; +} + +:is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText + .tooltip.show { + --alt-text-tooltip-bg: #f0f0f4; + --alt-text-tooltip-fg: #15141a; + --alt-text-tooltip-border: #8f8f9d; + --alt-text-tooltip-shadow: 0px 2px 6px 0px rgb(58 57 68 / 0.2); + + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: absolute; + top: calc(100% + 2px); + inset-inline-start: 0; + padding-block: 2px 3px; + padding-inline: 3px; + max-width: 300px; + width: -moz-max-content; + width: max-content; + height: auto; + font-size: 12px; + + border: 0.5px solid var(--alt-text-tooltip-border); + background: var(--alt-text-tooltip-bg); + box-shadow: var(--alt-text-tooltip-shadow); + color: var(--alt-text-tooltip-fg); + + pointer-events: none; +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText + .tooltip.show { + --alt-text-tooltip-bg: #1c1b22; + --alt-text-tooltip-fg: #fbfbfe; + --alt-text-tooltip-shadow: 0px 2px 6px 0px #15141a; + } +} + +:where(html.is-dark) + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText + .tooltip.show { + --alt-text-tooltip-bg: #1c1b22; + --alt-text-tooltip-fg: #fbfbfe; + --alt-text-tooltip-shadow: 0px 2px 6px 0px #15141a; +} + +@media screen and (forced-colors: active) { + :is( + .annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), + .textLayer + ) + .editToolbar + .buttons + .altText + .tooltip.show { + --alt-text-tooltip-bg: Canvas; + --alt-text-tooltip-fg: CanvasText; + --alt-text-tooltip-border: CanvasText; + --alt-text-tooltip-shadow: none; + } +} + +.annotationEditorLayer .freeTextEditor { + padding: calc(var(--freetext-padding) * var(--scale-factor)); + width: auto; + height: auto; + touch-action: none; +} + +.annotationEditorLayer .freeTextEditor .internal { + background: transparent; + border: none; + inset: 0; + overflow: visible; + white-space: nowrap; + font: 10px sans-serif; + line-height: var(--freetext-line-height); + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.annotationEditorLayer .freeTextEditor .overlay { + position: absolute; + display: none; + background: transparent; + inset: 0; + width: 100%; + height: 100%; +} + +.annotationEditorLayer freeTextEditor .overlay.enabled { + display: block; +} + +.annotationEditorLayer .freeTextEditor .internal:empty::before { + content: attr(default-content); + color: gray; +} + +.annotationEditorLayer .freeTextEditor .internal:focus { + outline: none; + -webkit-user-select: auto; + -moz-user-select: auto; + user-select: auto; +} + +.annotationEditorLayer .inkEditor { + width: 100%; + height: 100%; +} + +.annotationEditorLayer .inkEditor.editing { + cursor: inherit; +} + +.annotationEditorLayer .inkEditor .inkEditorCanvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + touch-action: none; +} + +.annotationEditorLayer .stampEditor { + width: auto; + height: auto; +} + +.annotationEditorLayer .stampEditor canvas { + position: absolute; + width: 100%; + height: 100%; + margin: 0; +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers { + position: absolute; + inset: 0; +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers.hidden { + display: none; +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer { + width: var(--resizer-size); + height: var(--resizer-size); + background: content-box var(--resizer-bg-color); + border: var(--focus-outline-around); + border-radius: 2px; + position: absolute; +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.topLeft { + top: var(--resizer-shift); + left: var(--resizer-shift); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.topMiddle { + top: var(--resizer-shift); + left: calc(50% + var(--resizer-shift)); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.topRight { + top: var(--resizer-shift); + right: var(--resizer-shift); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.middleRight { + top: calc(50% + var(--resizer-shift)); + right: var(--resizer-shift); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.bottomRight { + bottom: var(--resizer-shift); + right: var(--resizer-shift); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.bottomMiddle { + bottom: var(--resizer-shift); + left: calc(50% + var(--resizer-shift)); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.bottomLeft { + bottom: var(--resizer-shift); + left: var(--resizer-shift); +} + +.annotationEditorLayer + :is(.freeTextEditor, .inkEditor, .stampEditor) + > .resizers + > .resizer.middleLeft { + top: calc(50% + var(--resizer-shift)); + left: var(--resizer-shift); +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomRight { + cursor: nwse-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomMiddle { + cursor: ns-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomLeft { + cursor: nesw-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleLeft { + cursor: ew-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topLeft, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomRight { + cursor: nesw-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topMiddle, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomMiddle, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomMiddle { + cursor: ew-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topRight, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomLeft { + cursor: nwse-resize; +} + +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleRight, +.annotationEditorLayer[data-main-rotation="0"] + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="90"] + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="180"] + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleLeft, +.annotationEditorLayer[data-main-rotation="270"] + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleLeft { + cursor: ns-resize; +} + +.annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .editToolbar { + rotate: 270deg; +} + +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .editToolbar { + inset-inline-end: calc(0px - var(--editor-toolbar-vert-offset)); + inset-block-start: 0; +} + +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .editToolbar { + inset-inline-end: calc(100% + var(--editor-toolbar-vert-offset)); + inset-block-start: 0; +} + +.annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="180"], + [data-main-rotation="90"] [data-editor-rotation="90"], + [data-main-rotation="180"] [data-editor-rotation="0"], + [data-main-rotation="270"] [data-editor-rotation="270"] + ) + .editToolbar { + rotate: 180deg; + inset-inline-end: 100%; + inset-block-start: calc(0pc - var(--editor-toolbar-vert-offset)); +} + +.annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .editToolbar { + rotate: 90deg; +} + +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .editToolbar { + inset-inline-end: calc(100% + var(--editor-toolbar-vert-offset)); + inset-block-start: 100%; +} + +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .editToolbar { + inset-inline-start: calc(0px - var(--editor-toolbar-vert-offset)); + inset-block-start: 0; +} + +.dialog.altText::backdrop { + -webkit-mask: url(#alttext-manager-mask); + mask: url(#alttext-manager-mask); +} + +.dialog.altText.positioned { + margin: 0; +} + +.dialog.altText #altTextContainer { + width: 300px; + height: -moz-fit-content; + height: fit-content; + display: inline-flex; + flex-direction: column; + align-items: flex-start; + gap: 16px; +} + +.dialog.altText #altTextContainer #overallDescription { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + align-self: stretch; +} + +.dialog.altText #altTextContainer #overallDescription span { + align-self: stretch; +} + +.dialog.altText #altTextContainer #overallDescription .title { + font-size: 13px; + font-style: normal; + font-weight: 590; +} + +.dialog.altText #altTextContainer #addDescription { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 8px; +} + +.dialog.altText #altTextContainer #addDescription .descriptionArea { + flex: 1; + padding-inline: 24px 10px; +} + +.dialog.altText #altTextContainer #addDescription .descriptionArea textarea { + width: 100%; + min-height: 75px; +} + +.dialog.altText #altTextContainer #buttons { + display: flex; + justify-content: flex-end; + align-items: flex-start; + gap: 8px; + align-self: stretch; +} + +.colorPicker { + --hover-outline-color: #0250bb; + --selected-outline-color: #0060df; + --swatch-border-color: #cfcfd8; +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) .colorPicker { + --hover-outline-color: #80ebff; + --selected-outline-color: #aaf2ff; + --swatch-border-color: #52525e; + } +} + +:where(html.is-dark) .colorPicker { + --hover-outline-color: #80ebff; + --selected-outline-color: #aaf2ff; + --swatch-border-color: #52525e; +} + +@media screen and (forced-colors: active) { + .colorPicker { + --hover-outline-color: Highlight; + --selected-outline-color: var(--hover-outline-color); + --swatch-border-color: ButtonText; + } +} + +.colorPicker .swatch { + width: 16px; + height: 16px; + border: 1px solid var(--swatch-border-color); + border-radius: 100%; + outline-offset: 2px; + box-sizing: border-box; + forced-color-adjust: none; +} + +.colorPicker button:is(:hover, .selected) > .swatch { + border: none; +} + +.annotationEditorLayer[data-main-rotation="0"] + .highlightEditor:not(.free) + > .editToolbar { + rotate: 0deg; +} + +.annotationEditorLayer[data-main-rotation="90"] + .highlightEditor:not(.free) + > .editToolbar { + rotate: 270deg; +} + +.annotationEditorLayer[data-main-rotation="180"] + .highlightEditor:not(.free) + > .editToolbar { + rotate: 180deg; +} + +.annotationEditorLayer[data-main-rotation="270"] + .highlightEditor:not(.free) + > .editToolbar { + rotate: 90deg; +} + +.annotationEditorLayer .highlightEditor { + position: absolute; + background: transparent; + z-index: 1; + cursor: auto; + max-width: 100%; + max-height: 100%; + border: none; + outline: none; + pointer-events: none; + transform-origin: 0 0; +} + +.annotationEditorLayer .highlightEditor:not(.free) { + transform: none; +} + +.annotationEditorLayer .highlightEditor .internal { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: auto; +} + +.annotationEditorLayer .highlightEditor.disabled .internal { + pointer-events: none; +} + +.annotationEditorLayer .highlightEditor.selectedEditor .internal { + cursor: pointer; +} + +.annotationEditorLayer .highlightEditor .editToolbar { + --editor-toolbar-colorpicker-arrow-image: url(../images/toolbarButton-menuArrow.svg); + + transform-origin: center !important; +} + +.annotationEditorLayer .highlightEditor .editToolbar .buttons .colorPicker { + position: relative; + width: auto; + display: flex; + justify-content: center; + align-items: center; + gap: 4px; + padding: 4px; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker::after { + content: ""; + -webkit-mask-image: var(--editor-toolbar-colorpicker-arrow-image); + mask-image: var(--editor-toolbar-colorpicker-arrow-image); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + display: inline-block; + background-color: var(--editor-toolbar-fg-color); + width: 12px; + height: 12px; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker:hover::after { + background-color: var(--editor-toolbar-hover-fg-color); +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker:has(.dropdown:not(.hidden)) { + background-color: var(--editor-toolbar-hover-bg-color); +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker:has(.dropdown:not(.hidden))::after { + scale: -1; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown { + position: absolute; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + gap: 11px; + padding-block: 8px; + border-radius: 6px; + background-color: var(--editor-toolbar-bg-color); + border: 1px solid var(--editor-toolbar-border-color); + box-shadow: var(--editor-toolbar-shadow); + inset-block-start: calc(100% + 4px); + width: calc(100% + 2 * var(--editor-toolbar-padding)); +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown + button { + width: 100%; + height: auto; + border: none; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + background: none; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown + button:is(:active, :focus-visible) { + outline: none; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown + button + > .swatch { + outline-offset: 2px; +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown + button[aria-selected="true"] + > .swatch { + outline: 2px solid var(--selected-outline-color); +} + +.annotationEditorLayer + .highlightEditor + .editToolbar + .buttons + .colorPicker + .dropdown + button:is(:hover, :active, :focus-visible) + > .swatch { + outline: 2px solid var(--hover-outline-color); +} + +.editorParamsToolbar:has(#highlightParamsToolbarContainer) { + padding: unset; +} + +#highlightParamsToolbarContainer { + height: auto; + padding-inline: 10px; + padding-block: 10px 16px; + gap: 16px; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +#highlightParamsToolbarContainer .editorParamsLabel { + width: -moz-fit-content; + width: fit-content; + inset-inline-start: 0; +} + +#highlightParamsToolbarContainer .colorPicker { + display: flex; + flex-direction: column; + gap: 8px; +} + +#highlightParamsToolbarContainer .colorPicker .dropdown { + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: row; + height: auto; +} + +#highlightParamsToolbarContainer .colorPicker .dropdown button { + width: auto; + height: auto; + border: none; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + background: none; + flex: 0 0 auto; +} + +#highlightParamsToolbarContainer .colorPicker .dropdown button .swatch { + width: 24px; + height: 24px; +} + +#highlightParamsToolbarContainer + .colorPicker + .dropdown + button:is(:active, :focus-visible) { + outline: none; +} + +#highlightParamsToolbarContainer + .colorPicker + .dropdown + button[aria-selected="true"] + > .swatch { + outline: 2px solid var(--selected-outline-color); +} + +#highlightParamsToolbarContainer + .colorPicker + .dropdown + button:is(:hover, :active, :focus-visible) + > .swatch { + outline: 2px solid var(--hover-outline-color); +} + +#highlightParamsToolbarContainer #editorHighlightThickness { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + align-self: stretch; +} + +#highlightParamsToolbarContainer #editorHighlightThickness .editorParamsLabel { + width: 100%; + height: auto; + align-self: stretch; +} + +#highlightParamsToolbarContainer #editorHighlightThickness .thicknessPicker { + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; + + --example-color: #bfbfc9; +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) + #highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker { + --example-color: #80808e; + } +} + +:where(html.is-dark) + #highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker { + --example-color: #80808e; +} + +@media screen and (forced-colors: active) { + #highlightParamsToolbarContainer #editorHighlightThickness .thicknessPicker { + --example-color: CanvasText; + } +} + +:is( + #highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker + > .editorParamsSlider[disabled] + ) { + opacity: 0.4; +} + +#highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker::before, +#highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker::after { + content: ""; + width: 8px; + aspect-ratio: 1; + display: block; + border-radius: 100%; + background-color: var(--example-color); +} + +#highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker::after { + width: 24px; +} + +#highlightParamsToolbarContainer + #editorHighlightThickness + .thicknessPicker + .editorParamsSlider { + width: unset; + height: 14px; +} + +#highlightParamsToolbarContainer #editorHighlightVisibility { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + align-self: stretch; +} + +#highlightParamsToolbarContainer #editorHighlightVisibility .divider { + --divider-color: #d7d7db; + + margin-block: 4px; + width: 100%; + height: 1px; + background-color: var(--divider-color); +} + +@media (prefers-color-scheme: dark) { + :where(html:not(.is-light)) + #highlightParamsToolbarContainer + #editorHighlightVisibility + .divider { + --divider-color: #8f8f9d; + } +} + +:where(html.is-dark) + #highlightParamsToolbarContainer + #editorHighlightVisibility + .divider { + --divider-color: #8f8f9d; +} + +@media screen and (forced-colors: active) { + #highlightParamsToolbarContainer #editorHighlightVisibility .divider { + --divider-color: CanvasText; + } +} + +#highlightParamsToolbarContainer #editorHighlightVisibility .toggler { + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; +} + +:root { + --viewer-container-height: 0; + --pdfViewer-padding-bottom: 0; + --page-margin: 10px auto; + --page-border: 9px solid transparent; + --spreadHorizontalWrapped-margin-LR: -3.5px; + --loading-icon-delay: 400ms; +} + +@media screen and (forced-colors: active) { + :root { + --pdfViewer-padding-bottom: 9px; + --page-margin: 10px auto; + --page-border: 1px solid CanvasText; + --spreadHorizontalWrapped-margin-LR: 3.5px; + } +} + +[data-main-rotation="90"] { + transform: rotate(90deg) translateY(-100%); +} +[data-main-rotation="180"] { + transform: rotate(180deg) translate(-100%, -100%); +} +[data-main-rotation="270"] { + transform: rotate(270deg) translateX(-100%); +} + +#hiddenCopyElement, +.hiddenCanvasElement { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + display: none; +} + +.pdfViewer { + --scale-factor: 1; + + padding-bottom: var(--pdfViewer-padding-bottom); + + --hcm-highlight-filter: none; + --hcm-highlight-selected-filter: none; +} + +@media screen and (forced-colors: active) { + .pdfViewer { + --hcm-highlight-filter: invert(100%); + } +} + +.pdfViewer .canvasWrapper { + width: 100%; + height: 100%; +} + +.pdfViewer .canvasWrapper canvas { + margin: 0; + display: block; +} + +.pdfViewer .canvasWrapper canvas[hidden] { + display: none; +} + +.pdfViewer .canvasWrapper canvas[zooming] { + width: 100%; + height: 100%; +} + +.pdfViewer .canvasWrapper canvas .structTree { + contain: strict; +} + +.pdfViewer .page { + direction: ltr; + width: 816px; + height: 1056px; + margin: var(--page-margin); + position: relative; + overflow: visible; + border: var(--page-border); + background-clip: content-box; + background-color: rgb(255 255 255); +} + +.pdfViewer .dummyPage { + position: relative; + width: 0; + height: var(--viewer-container-height); +} + +.pdfViewer.noUserSelect { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.pdfViewer.removePageBorders .page { + margin: 0 auto 10px; + border: none; +} + +.pdfViewer:is(.scrollHorizontal, .scrollWrapped), +.spread { + margin-inline: 3.5px; + text-align: center; +} + +.pdfViewer.scrollHorizontal, +.spread { + white-space: nowrap; +} + +.pdfViewer.removePageBorders, +.pdfViewer:is(.scrollHorizontal, .scrollWrapped) .spread { + margin-inline: 0; +} + +.spread :is(.page, .dummyPage), +.pdfViewer:is(.scrollHorizontal, .scrollWrapped) :is(.page, .spread) { + display: inline-block; + vertical-align: middle; +} + +.spread .page, +.pdfViewer:is(.scrollHorizontal, .scrollWrapped) .page { + margin-inline: var(--spreadHorizontalWrapped-margin-LR); +} + +.pdfViewer.removePageBorders .spread .page, +.pdfViewer.removePageBorders:is(.scrollHorizontal, .scrollWrapped) .page { + margin-inline: 5px; +} + +.pdfViewer .page.loadingIcon::after { + position: absolute; + top: 0; + left: 0; + content: ""; + width: 100%; + height: 100%; + background: url("../images/loading-icon.gif") center no-repeat; + display: none; + transition-property: display; + transition-delay: var(--loading-icon-delay); + z-index: 5; + contain: strict; +} + +.pdfViewer .page.loading::after { + display: block; +} + +.pdfViewer .page:not(.loading)::after { + transition-property: none; + display: none; +} + +.pdfPresentationMode .pdfViewer { + padding-bottom: 0; +} + +.pdfPresentationMode .spread { + margin: 0; +} + +.pdfPresentationMode .pdfViewer .page { + margin: 0 auto; + border: 2px solid transparent; +} + +html[data-toolbar-density="compact"] { + --toolbar-height: 1.875rem; +} + +html[data-toolbar-density="touch"] { + --toolbar-height: 2.75rem; +} + +:root { + --dir-factor: 1; + --inline-start: left; + --inline-end: right; + + --sidebar-width: 200px; + --sidebar-transition-duration: 200ms; + --sidebar-transition-timing-function: ease; + + --toolbar-height: 3.75rem; + --toolButton-height: 3rem; + --toolButton-width: 3rem; + --toolButton-icon-font-size: 2.5rem; + --toolButton-border-radius: 15px; + + --toolbar-icon-opacity: 0.7; + --doorhanger-icon-opacity: 0.9; + --editor-toolbar-base-offset: 105px; + + --main-color: rgb(12 12 13); + --body-bg-color: rgb(212 212 215); + --progressBar-color: rgb(10 132 255); + --progressBar-bg-color: rgb(221 221 222); + --progressBar-blend-color: rgb(116 177 239); + --scrollbar-color: auto; + --scrollbar-bg-color: auto; + --toolbar-icon-bg-color: rgb(0 0 0); + --toolbar-icon-hover-bg-color: rgb(0 0 0); + + --sidebar-narrow-bg-color: rgb(212 212 215 / 0.9); + --sidebar-toolbar-bg-color: rgb(245 246 247); + --toolbar-bg-color: rgb(249 249 250); + --toolbar-border-color: rgb(184 184 184); + --toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color); + --toolbar-border-bottom: none; + --toolbarSidebar-box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 + rgb(0 0 0 / 0.25), + 0 1px 0 rgb(0 0 0 / 0.15), 0 0 1px rgb(0 0 0 / 0.1); + --toolbarSidebar-border-bottom: none; + --button-hover-color: rgb(221 222 223); + --toggled-btn-color: rgb(0 0 0); + --toggled-btn-bg-color: rgb(0 0 0 / 0.3); + --toggled-hover-active-btn-color: rgb(0 0 0 / 0.4); + --toggled-hover-btn-outline: none; + --dropdown-btn-bg-color: rgb(215 215 219); + --dropdown-btn-border: none; + --separator-color: rgb(0 0 0 / 0.3); + --field-color: rgb(6 6 6); + --field-bg-color: rgb(255 255 255); + --field-border-color: rgb(187 187 188); + --treeitem-color: rgb(0 0 0 / 0.8); + --treeitem-bg-color: rgb(0 0 0 / 0.15); + --treeitem-hover-color: rgb(0 0 0 / 0.9); + --treeitem-selected-color: rgb(0 0 0 / 0.9); + --treeitem-selected-bg-color: rgb(0 0 0 / 0.25); + --thumbnail-hover-color: rgb(0 0 0 / 0.1); + --thumbnail-selected-color: rgb(0 0 0 / 0.2); + --doorhanger-bg-color: rgb(255 255 255); + --doorhanger-border-color: rgb(12 12 13 / 0.2); + --doorhanger-hover-color: rgb(12 12 13); + --doorhanger-hover-bg-color: rgb(237 237 237); + --doorhanger-separator-color: rgb(222 222 222); + --dialog-button-border: none; + --dialog-button-bg-color: rgb(12 12 13 / 0.1); + --dialog-button-hover-bg-color: rgb(12 12 13 / 0.3); + + --loading-icon: url(../images/loading.svg); + --treeitem-expanded-icon: url(../images/treeitem-expanded.svg); + --treeitem-collapsed-icon: url(../images/treeitem-collapsed.svg); + --toolbarButton-editorFreeText-icon: url(../images/toolbarButton-editorFreeText.svg); + --toolbarButton-editorHighlight-icon: url(../images/toolbarButton-editorHighlight.svg); + --toolbarButton-editorInk-icon: url(../images/toolbarButton-editorInk.svg); + --toolbarButton-editorStamp-icon: url(../images/toolbarButton-editorStamp.svg); + --toolbarButton-menuArrow-icon: url(../images/toolbarButton-menuArrow.svg); + --toolbarButton-sidebarToggle-icon: url(../images/toolbarButton-sidebarToggle.svg); + --toolbarButton-secondaryToolbarToggle-icon: url(../images/toolbarButton-secondaryToolbarToggle.svg); + --toolbarButton-pageUp-icon: url(../images/toolbarButton-pageUp.svg); + --toolbarButton-pageDown-icon: url(../images/toolbarButton-pageDown.svg); + --toolbarButton-zoomOut-icon: url(../images/toolbarButton-zoomOut.svg); + --toolbarButton-zoomIn-icon: url(../images/toolbarButton-zoomIn.svg); + --toolbarButton-presentationMode-icon: url(../images/toolbarButton-presentationMode.svg); + --toolbarButton-print-icon: url(../images/toolbarButton-print.svg); + --toolbarButton-openFile-icon: url(../images/toolbarButton-openFile.svg); + --toolbarButton-download-icon: url(../images/toolbarButton-download.svg); + --toolbarButton-bookmark-icon: url(../images/toolbarButton-bookmark.svg); + --toolbarButton-viewThumbnail-icon: url(../images/toolbarButton-viewThumbnail.svg); + --toolbarButton-viewOutline-icon: url(../images/toolbarButton-viewOutline.svg); + --toolbarButton-viewAttachments-icon: url(../images/toolbarButton-viewAttachments.svg); + --toolbarButton-viewLayers-icon: url(../images/toolbarButton-viewLayers.svg); + --toolbarButton-currentOutlineItem-icon: url(../images/toolbarButton-currentOutlineItem.svg); + --toolbarButton-search-icon: url(../images/toolbarButton-search.svg); + --toolbarButton-backToHome-icon: url(../images/toolbarButton-home.svg); + --findbarButton-previous-icon: url(../images/findbarButton-previous.svg); + --findbarButton-next-icon: url(../images/findbarButton-next.svg); + --secondaryToolbarButton-firstPage-icon: url(../images/secondaryToolbarButton-firstPage.svg); + --secondaryToolbarButton-lastPage-icon: url(../images/secondaryToolbarButton-lastPage.svg); + --secondaryToolbarButton-rotateCcw-icon: url(../images/secondaryToolbarButton-rotateCcw.svg); + --secondaryToolbarButton-rotateCw-icon: url(../images/secondaryToolbarButton-rotateCw.svg); + --secondaryToolbarButton-selectTool-icon: url(../images/secondaryToolbarButton-selectTool.svg); + --secondaryToolbarButton-handTool-icon: url(../images/secondaryToolbarButton-handTool.svg); + --secondaryToolbarButton-scrollPage-icon: url(../images/secondaryToolbarButton-scrollPage.svg); + --secondaryToolbarButton-scrollVertical-icon: url(../images/secondaryToolbarButton-scrollVertical.svg); + --secondaryToolbarButton-scrollHorizontal-icon: url(../images/secondaryToolbarButton-scrollHorizontal.svg); + --secondaryToolbarButton-scrollWrapped-icon: url(../images/secondaryToolbarButton-scrollWrapped.svg); + --secondaryToolbarButton-spreadNone-icon: url(../images/secondaryToolbarButton-spreadNone.svg); + --secondaryToolbarButton-spreadOdd-icon: url(../images/secondaryToolbarButton-spreadOdd.svg); + --secondaryToolbarButton-spreadEven-icon: url(../images/secondaryToolbarButton-spreadEven.svg); + --secondaryToolbarButton-documentProperties-icon: url(../images/secondaryToolbarButton-documentProperties.svg); + --editorParams-stampAddImage-icon: url(../images/toolbarButton-zoomIn.svg); +} + +[dir="rtl"]:root { + --dir-factor: -1; + --inline-start: right; + --inline-end: left; +} + +@media (prefers-color-scheme: dark) { + :root:where(:not(.is-light)) { + --main-color: rgb(249 249 250); + --body-bg-color: rgb(42 42 46); + --progressBar-color: rgb(0 96 223); + --progressBar-bg-color: rgb(40 40 43); + --progressBar-blend-color: rgb(20 68 133); + --scrollbar-color: rgb(121 121 123); + --scrollbar-bg-color: rgb(35 35 39); + --toolbar-icon-bg-color: rgb(255 255 255); + --toolbar-icon-hover-bg-color: rgb(255 255 255); + + --sidebar-narrow-bg-color: rgb(42 42 46 / 0.9); + --sidebar-toolbar-bg-color: rgb(50 50 52); + --toolbar-bg-color: rgb(56 56 61); + --toolbar-border-color: rgb(12 12 13); + --button-hover-color: rgb(102 102 103); + --toggled-btn-color: rgb(255 255 255); + --toggled-btn-bg-color: rgb(0 0 0 / 0.3); + --toggled-hover-active-btn-color: rgb(0 0 0 / 0.4); + --dropdown-btn-bg-color: rgb(74 74 79); + --separator-color: rgb(0 0 0 / 0.3); + --field-color: rgb(250 250 250); + --field-bg-color: rgb(64 64 68); + --field-border-color: rgb(115 115 115); + --treeitem-color: rgb(255 255 255 / 0.8); + --treeitem-bg-color: rgb(255 255 255 / 0.15); + --treeitem-hover-color: rgb(255 255 255 / 0.9); + --treeitem-selected-color: rgb(255 255 255 / 0.9); + --treeitem-selected-bg-color: rgb(255 255 255 / 0.25); + --thumbnail-hover-color: rgb(255 255 255 / 0.1); + --thumbnail-selected-color: rgb(255 255 255 / 0.2); + --doorhanger-bg-color: rgb(74 74 79); + --doorhanger-border-color: rgb(39 39 43); + --doorhanger-hover-color: rgb(249 249 250); + --doorhanger-hover-bg-color: rgb(93 94 98); + --doorhanger-separator-color: rgb(92 92 97); + --dialog-button-bg-color: rgb(92 92 97); + --dialog-button-hover-bg-color: rgb(115 115 115); + } +} + +:root:where(.is-dark) { + --main-color: rgb(249 249 250); + --body-bg-color: rgb(42 42 46); + --progressBar-color: rgb(0 96 223); + --progressBar-bg-color: rgb(40 40 43); + --progressBar-blend-color: rgb(20 68 133); + --scrollbar-color: rgb(121 121 123); + --scrollbar-bg-color: rgb(35 35 39); + --toolbar-icon-bg-color: rgb(255 255 255); + --toolbar-icon-hover-bg-color: rgb(255 255 255); + + --sidebar-narrow-bg-color: rgb(42 42 46 / 0.9); + --sidebar-toolbar-bg-color: rgb(50 50 52); + --toolbar-bg-color: rgb(56 56 61); + --toolbar-border-color: rgb(12 12 13); + --button-hover-color: rgb(102 102 103); + --toggled-btn-color: rgb(255 255 255); + --toggled-btn-bg-color: rgb(0 0 0 / 0.3); + --toggled-hover-active-btn-color: rgb(0 0 0 / 0.4); + --dropdown-btn-bg-color: rgb(74 74 79); + --separator-color: rgb(0 0 0 / 0.3); + --field-color: rgb(250 250 250); + --field-bg-color: rgb(64 64 68); + --field-border-color: rgb(115 115 115); + --treeitem-color: rgb(255 255 255 / 0.8); + --treeitem-bg-color: rgb(255 255 255 / 0.15); + --treeitem-hover-color: rgb(255 255 255 / 0.9); + --treeitem-selected-color: rgb(255 255 255 / 0.9); + --treeitem-selected-bg-color: rgb(255 255 255 / 0.25); + --thumbnail-hover-color: rgb(255 255 255 / 0.1); + --thumbnail-selected-color: rgb(255 255 255 / 0.2); + --doorhanger-bg-color: rgb(74 74 79); + --doorhanger-border-color: rgb(39 39 43); + --doorhanger-hover-color: rgb(249 249 250); + --doorhanger-hover-bg-color: rgb(93 94 98); + --doorhanger-separator-color: rgb(92 92 97); + --dialog-button-bg-color: rgb(92 92 97); + --dialog-button-hover-bg-color: rgb(115 115 115); +} + +@media screen and (forced-colors: active) { + :root { + --button-hover-color: Highlight; + --doorhanger-hover-bg-color: Highlight; + --toolbar-icon-opacity: 1; + --toolbar-icon-bg-color: ButtonText; + --toolbar-icon-hover-bg-color: ButtonFace; + --toggled-hover-active-btn-color: ButtonText; + --toggled-hover-btn-outline: 2px solid ButtonBorder; + --toolbar-border-color: CanvasText; + --toolbar-border-bottom: 1px solid var(--toolbar-border-color); + --toolbar-box-shadow: none; + --toggled-btn-color: HighlightText; + --toggled-btn-bg-color: LinkText; + --doorhanger-hover-color: ButtonFace; + --doorhanger-border-color-whcm: 1px solid ButtonText; + --doorhanger-triangle-opacity-whcm: 0; + --dialog-button-border: 1px solid Highlight; + --dialog-button-hover-bg-color: Highlight; + --dialog-button-hover-color: ButtonFace; + --dropdown-btn-border: 1px solid ButtonText; + --field-border-color: ButtonText; + --main-color: CanvasText; + --separator-color: GrayText; + --doorhanger-separator-color: GrayText; + --toolbarSidebar-box-shadow: none; + --toolbarSidebar-border-bottom: 1px solid var(--toolbar-border-color); + } +} + +@media screen and (prefers-reduced-motion: reduce) { + :root { + --sidebar-transition-duration: 0; + } +} + +* { + padding: 0; + margin: 0; +} + +html, +body { + height: 100%; + width: 100%; +} + +.hidden, +[hidden] { + display: none !important; +} + +#viewerContainer.pdfPresentationMode:fullscreen { + top: 0; + background-color: rgb(0 0 0); + width: 100%; + height: 100%; + overflow: hidden; + cursor: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.pdfPresentationMode:fullscreen section:not([data-internal-link]) { + pointer-events: none; +} + +.pdfPresentationMode:fullscreen .textLayer span { + cursor: none; +} + +.pdfPresentationMode.pdfPresentationModeControls > *, +.pdfPresentationMode.pdfPresentationModeControls .textLayer span { + cursor: default; +} + +#outerContainer { + width: 100%; + height: calc(100% - var(--navbar-height)); + position: relative; +} + +#sidebarContainer { + position: absolute; + inset-block: var(--toolbar-height) 0; + inset-inline-start: calc(-1 * var(--sidebar-width)); + width: var(--sidebar-width); + visibility: hidden; + z-index: 100; + font: message-box; + border-top: 1px solid rgb(51 51 51); + border-inline-end: var(--doorhanger-border-color-whcm); + transition-property: inset-inline-start; + transition-duration: var(--sidebar-transition-duration); + transition-timing-function: var(--sidebar-transition-timing-function); +} + +#outerContainer:is(.sidebarMoving, .sidebarOpen) #sidebarContainer { + visibility: visible; +} +#outerContainer.sidebarOpen #sidebarContainer { + inset-inline-start: 0; +} + +#mainContainer { + position: absolute; + inset: 0; + min-width: 350px; +} + +#sidebarContent { + inset-block: var(--toolbar-height) 0; + inset-inline-start: 0; + overflow: auto; + position: absolute; + width: 100%; + box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgb(0 0 0 / 0.25); +} + +#viewerContainer { + overflow: auto; + position: absolute; + inset: var(--toolbar-height) 0 0; + outline: none; +} +#viewerContainer:not(.pdfPresentationMode) { + transition-duration: var(--sidebar-transition-duration); + transition-timing-function: var(--sidebar-transition-timing-function); +} + +#outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { + inset-inline-start: var(--sidebar-width); + transition-property: inset-inline-start; +} + +.toolbar { + position: relative; + inset-inline: 0; + z-index: 20; + cursor: default; + font: message-box; +} + +:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer) + :is(input, button, select), +.secondaryToolbar :is(input, button, a, select) { + outline: none; + font: message-box; +} + +#toolbarContainer { + width: 100%; + border-radius: 5px; +} + +#toolbarSidebar { + width: 100%; + height: var(--toolbar-height); + background-color: var(--sidebar-toolbar-bg-color); + box-shadow: var(--toolbarSidebar-box-shadow); + border-bottom: var(--toolbarSidebar-border-bottom); +} + +#sidebarResizer { + position: absolute; + inset-block: 0; + inset-inline-end: -6px; + width: 6px; + z-index: 200; + cursor: ew-resize; +} + +#toolbarContainer, +.findbar, +.secondaryToolbar, +.editorParamsToolbar { + position: relative; + height: var(--toolbar-height); + /* background-color:var(--toolbar-bg-color); */ + background-color: var(--md-sys-color-surface-5); + box-shadow: var(--toolbar-box-shadow); + border-bottom: var(--toolbar-border-bottom); +} + +#toolbarViewer { + height: var(--toolbar-height); + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} + +#loadingBar { + --progressBar-percent: 0%; + --progressBar-end-offset: 0; + + position: absolute; + inset-inline: 0 var(--progressBar-end-offset); + height: 4px; + background-color: var(--progressBar-bg-color); + border-bottom: 1px solid var(--toolbar-border-color); + transition-property: inset-inline-start; + transition-duration: var(--sidebar-transition-duration); + transition-timing-function: var(--sidebar-transition-timing-function); +} + +#outerContainer.sidebarOpen #loadingBar { + inset-inline-start: var(--sidebar-width); +} + +#loadingBar .progress { + position: absolute; + top: 0; + inset-inline-start: 0; + width: 100%; + transform: scaleX(var(--progressBar-percent)); + transform-origin: calc(50% - 50% * var(--dir-factor)) 0; + height: 100%; + background-color: var(--progressBar-color); + overflow: hidden; + transition: transform 200ms; +} + +@keyframes progressIndeterminate { + 0% { + transform: translateX(calc(-142px * var(--dir-factor))); + } + 100% { + transform: translateX(0); + } +} + +#loadingBar.indeterminate .progress { + transform: none; + background-color: var(--progressBar-bg-color); + transition: none; +} + +#loadingBar.indeterminate .progress .glimmer { + position: absolute; + top: 0; + inset-inline-start: 0; + height: 100%; + width: calc(100% + 150px); + background: repeating-linear-gradient( + 135deg, + var(--progressBar-blend-color) 0, + var(--progressBar-bg-color) 5px, + var(--progressBar-bg-color) 45px, + var(--progressBar-color) 55px, + var(--progressBar-color) 95px, + var(--progressBar-blend-color) 100px + ); + animation: progressIndeterminate 1s linear infinite; +} + +#outerContainer.sidebarResizing + :is(#sidebarContainer, #viewerContainer, #loadingBar) { + transition-duration: 0s; +} + +.findbar, +.secondaryToolbar, +.editorParamsToolbar { + top: 32px; + position: absolute; + z-index: 30000; + height: auto; + padding: 0 4px; + margin: 4px 2px; + font: message-box; + font-size: 12px; + line-height: 14px; + text-align: left; + cursor: default; +} + +.findbar { + inset-inline-start: 64px; + min-width: 300px; + background-color: var(--toolbar-bg-color); +} +.findbar > div { + /* height:32px; */ + height: var(--toolbar-height); +} +.findbar > div#findbarInputContainer { + margin-inline-end: 4px; +} +.findbar.wrapContainers > div, +.findbar.wrapContainers > div#findbarMessageContainer > * { + clear: both; +} +.findbar.wrapContainers > div#findbarMessageContainer { + height: auto; +} + +.findbar input[type="checkbox"] { + pointer-events: none; +} + +.findbar label { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.findbar label:hover, +.findbar input:focus-visible + label { + color: var(--toggled-btn-color); + background-color: var(--button-hover-color); +} + +.findbar .toolbarField[type="checkbox"]:checked + .toolbarLabel { + background-color: var(--toggled-btn-bg-color) !important; + color: var(--toggled-btn-color); +} + +#findInput { + width: 200px; +} + +#findInput::-moz-placeholder { + font-style: normal; +} + +#findInput::placeholder { + font-style: normal; +} + +.loadingInput:has(> #findInput[data-status="pending"])::after { + display: block; + visibility: visible; +} + +#findInput[data-status="notFound"] { + background-color: rgb(255 102 102); +} + +.secondaryToolbar, +.editorParamsToolbar { + padding: 6px 0 10px; + inset-inline-end: 4px; + height: auto; + background-color: var(--doorhanger-bg-color); +} + +.editorParamsToolbarContainer { + width: 220px; + margin-bottom: -4px; +} + +.editorParamsToolbarContainer > .editorParamsSetter { + min-height: 26px; + display: flex; + align-items: center; + justify-content: space-between; + padding-inline: 10px; +} + +.editorParamsToolbarContainer .editorParamsLabel { + padding-inline-end: 10px; + flex: none; + font: menu; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 150%; + color: var(--main-color); +} + +.editorParamsToolbarContainer .editorParamsColor { + width: 32px; + height: 32px; + flex: none; +} + +.editorParamsToolbarContainer .editorParamsSlider { + background-color: transparent; + width: 90px; + flex: 0 1 0; +} + +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-progress { + background-color: black; +} + +.editorParamsToolbarContainer + .editorParamsSlider::-webkit-slider-runnable-track, +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-track { + background-color: black; +} + +.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-thumb, +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-thumb { + background-color: white; +} + +#secondaryToolbarButtonContainer { + max-width: 220px; + min-height: 26px; + max-height: calc(var(--viewer-container-height) - 40px); + overflow-y: auto; + margin-bottom: -4px; +} + +#editorStampParamsToolbar { + inset-inline-end: calc(var(--editor-toolbar-base-offset) + 0px); +} + +#editorInkParamsToolbar { + inset-inline-end: calc(var(--editor-toolbar-base-offset) + 28px); +} + +#editorFreeTextParamsToolbar { + inset-inline-end: calc(var(--editor-toolbar-base-offset) + 56px); +} + +#editorHighlightParamsToolbar { + inset-inline-end: calc(var(--editor-toolbar-base-offset) + 84px); +} + +#editorStampAddImage::before { + -webkit-mask-image: var(--editorParams-stampAddImage-icon); + mask-image: var(--editorParams-stampAddImage-icon); +} + +.doorHanger, +.doorHangerRight { + border-radius: 2px; + box-shadow: 0 1px 5px var(--doorhanger-border-color), + 0 0 0 1px var(--doorhanger-border-color); + border: var(--doorhanger-border-color-whcm); +} +:is(.doorHanger, .doorHangerRight)::after, +:is(.doorHanger, .doorHangerRight)::before { + bottom: 100%; + border: 8px solid rgb(0 0 0 / 0); + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + opacity: var(--doorhanger-triangle-opacity-whcm); +} +.doorHanger::after { + inset-inline-start: 10px; + margin-inline-start: -8px; + border-bottom-color: var(--toolbar-bg-color); +} +.doorHangerRight::after { + inset-inline-end: 10px; + margin-inline-end: -8px; + border-bottom-color: var(--doorhanger-bg-color); +} +:is(.doorHanger, .doorHangerRight)::before { + border-bottom-color: var(--doorhanger-border-color); + border-width: 9px; +} +.doorHanger::before { + inset-inline-start: 10px; + margin-inline-start: -9px; +} +.doorHangerRight::before { + inset-inline-end: 10px; + margin-inline-end: -9px; +} + +#findResultsCount { + background-color: rgb(217 217 217); + color: rgb(82 82 82); + text-align: center; + padding: 4px 5px; + margin: 5px; +} + +#findMsg[data-status="notFound"] { + font-weight: bold; +} + +:is(#findResultsCount, #findMsg):empty { + display: none; +} + +#toolbarViewerMiddle { + display: flex; + flex-wrap: wrap; + order: 2; +} + +#toolbarViewerLeft, +#toolbarSidebarLeft { + float: var(--inline-start); +} +#toolbarViewerRight, +#toolbarSidebarRight { + float: var(--inline-end); +} + +#toolbarViewerLeft > *, +#toolbarViewerMiddle > *, +#toolbarViewerRight > *, +#toolbarSidebarLeft *, +#toolbarSidebarRight *, +.findbar * { + position: relative; + float: var(--inline-start); +} + +#redactionsToolbarViewer { + order: 3; + column-gap: 3px; +} + +#toolbarViewerLeft { + order: 1; + margin-right: auto; + padding-inline-start: 1px; +} +#toolbarViewerRight { + display: flex; + margin-left: auto; + column-gap: 3px; + order: 4; + padding-inline-end: 1px; +} +#toolbarSidebarRight { + padding-inline-end: 2px; +} + +.splitToolbarButton { + margin: 2px; + display: inline-block; + padding-top: 5px; +} +.splitToolbarButton > .toolbarButton { + float: var(--inline-start); +} + +.toolbarButton, +.secondaryToolbarButton, +.dialogButton { + border: none; + background: none; + width: 28px; + height: 28px; + outline: none; + + background-color: var(--md-sys-color-secondary); + color: var(--md-sys-color-on-secondary); + border-color: var(--md-sys-color-secondary); + box-shadow: var(--md-sys-elevation-3) !important; +} + +.toolbarButton { + height: var(--toolButton-height); + width: var(--toolButton-width); + border-radius: var(--toolButton-border-radius) !important; +} + +.dialogButton:is(:hover, :focus-visible) { + background-color: var(--dialog-button-hover-bg-color); +} + +.dialogButton:is(:hover, :focus-visible) > span { + color: var(--dialog-button-hover-color); +} + +.toolbarButton > span { + display: inline-block; + width: 0; + height: 0; + overflow: hidden; +} + +:is(.toolbarButton, .secondaryToolbarButton, .dialogButton)[disabled] { + opacity: 0.5; +} + +.splitToolbarButton > .toolbarButton:is(:hover, :focus-visible), +.dropdownToolbarButton:hover { + background-color: var(--button-hover-color); +} +.splitToolbarButton > .toolbarButton { + position: relative; + margin: 0; + height: var(--toolButton-height); + width: var(--toolButton-width); +} +#toolbarSidebar .splitToolbarButton > .toolbarButton { + margin-inline-end: 2px; +} + +.splitToolbarButtonSeparator { + float: var(--inline-start); + margin: 4px 3px; + width: 1px; + height: 20px; + background-color: var(--separator-color); + height: var(--toolButton-height); +} + +#scaleSelectContainer { + height: 3.125rem; + inset: 4px 0 0 0; + border-radius: var(--toolButton-border-radius); +} + +#scaleSelectContainer::after { + width: 1.875rem; + height: 1.875rem; +} + +#scaleSelect { + font-size: 1.25rem !important; + height: 100%; + border-radius: inherit; +} + +.toolbarButton, +.dropdownToolbarButton, +.secondaryToolbarButton, +.dialogButton { + min-width: 16px; + margin: 2px 3px; + padding: 2px 6px 0; + border: none; + border-radius: 2px; + color: var(--main-color); + font-size: 12px; + line-height: 14px; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: default; + box-sizing: border-box; +} + +.toolbarButton:is(:hover, :focus-visible) { + background-color: var(--button-hover-color); +} +.secondaryToolbarButton:is(:hover, :focus-visible) { + background-color: var(--doorhanger-hover-bg-color); + color: var(--doorhanger-hover-color); +} + +:is(.toolbarButton, .secondaryToolbarButton).toggled, +.splitToolbarButton.toggled > .toolbarButton.toggled { + background-color: var(--toggled-btn-bg-color); + color: var(--toggled-btn-color); +} + +:is(.toolbarButton, .secondaryToolbarButton).toggled:hover, +.splitToolbarButton.toggled > .toolbarButton.toggled:hover { + outline: var(--toggled-hover-btn-outline) !important; +} + +:is(.toolbarButton, .secondaryToolbarButton).toggled::before { + background-color: var(--toggled-btn-color); +} + +:is(.toolbarButton, .secondaryToolbarButton).toggled:hover:active, +.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active { + background-color: var(--toggled-hover-active-btn-color); +} + +.dropdownToolbarButton { + display: flex; + width: -moz-fit-content; + width: fit-content; + min-width: 140px; + padding: 0; + background-color: var(--dropdown-btn-bg-color); + border: var(--dropdown-btn-border); +} +.dropdownToolbarButton::after { + top: 10px; + inset-inline-end: 6px; + pointer-events: none; + -webkit-mask-image: var(--toolbarButton-menuArrow-icon); + mask-image: var(--toolbarButton-menuArrow-icon); +} + +.dropdownToolbarButton > select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + width: inherit; + min-width: inherit; + height: 28px; + font-size: 12px; + color: var(--main-color); + margin: 0; + padding-block: 1px 2px; + padding-inline: 6px 38px; + border: none; + background-color: var(--dropdown-btn-bg-color); +} +.dropdownToolbarButton > select:is(:hover, :focus-visible) { + background-color: var(--button-hover-color); + color: var(--toggled-btn-color); +} +.dropdownToolbarButton > select > option { + background: var(--doorhanger-bg-color); + color: var(--main-color); +} + +.toolbarButtonSpacer { + width: 30px; + display: inline-block; + height: 1px; +} + +:is(.toolbarButton, .secondaryToolbarButton, .treeItemToggler)::before, +.dropdownToolbarButton::after { + position: absolute; + display: inline-block; + width: 16px; + height: 16px; + + content: ""; + background-color: var(--toolbar-icon-bg-color); + -webkit-mask-size: cover; + mask-size: cover; +} + +.dropdownToolbarButton:is(:hover, :focus-visible, :active)::after { + background-color: var(--toolbar-icon-hover-bg-color); +} + +.toolbarButton::before { + opacity: var(--toolbar-icon-opacity); + top: 8px; + left: 10px; + height: 1.875rem; + width: 1.875rem; + background-color: var(--md-sys-color-on-secondary); +} + +.toolbarButton:is(:hover, :focus-visible)::before, +.secondaryToolbarButton:is(:hover, :focus-visible)::before { + background-color: var(--toolbar-icon-hover-bg-color); +} + +.secondaryToolbarButton::before { + opacity: var(--doorhanger-icon-opacity); + top: 5px; + inset-inline-start: 12px; +} + +#sidebarToggle { + height: var(--toolButton-height); + width: var(--toolButton-width); +} + +#sidebarToggle::before { + -webkit-mask-image: var(--toolbarButton-sidebarToggle-icon); + mask-image: var(--toolbarButton-sidebarToggle-icon); + transform: scaleX(var(--dir-factor)); + + height: 1.875rem; + width: 1.875rem; +} + +#secondaryToolbarToggle::before { + -webkit-mask-image: var(--toolbarButton-secondaryToolbarToggle-icon); + mask-image: var(--toolbarButton-secondaryToolbarToggle-icon); + transform: scaleX(var(--dir-factor)); +} + +#backToHome::before { + -webkit-mask-image: var(--toolbarButton-backToHome-icon); + mask-image: var(--toolbarButton-backToHome-icon); + transform: scaleX(var(--dir-factor)); +} + +#findPrevious::before { + -webkit-mask-image: var(--findbarButton-previous-icon); + mask-image: var(--findbarButton-previous-icon); +} + +#findNext::before { + -webkit-mask-image: var(--findbarButton-next-icon); + mask-image: var(--findbarButton-next-icon); +} + +#previous::before { + -webkit-mask-image: var(--toolbarButton-pageUp-icon); + mask-image: var(--toolbarButton-pageUp-icon); +} + +#next::before { + -webkit-mask-image: var(--toolbarButton-pageDown-icon); + mask-image: var(--toolbarButton-pageDown-icon); +} + +#zoomOut::before { + -webkit-mask-image: var(--toolbarButton-zoomOut-icon); + mask-image: var(--toolbarButton-zoomOut-icon); +} + +#zoomIn::before { + -webkit-mask-image: var(--toolbarButton-zoomIn-icon); + mask-image: var(--toolbarButton-zoomIn-icon); +} + +#presentationMode::before { + -webkit-mask-image: var(--toolbarButton-presentationMode-icon); + mask-image: var(--toolbarButton-presentationMode-icon); +} + +#editorFreeText::before { + -webkit-mask-image: var(--toolbarButton-editorFreeText-icon); + mask-image: var(--toolbarButton-editorFreeText-icon); +} + +#editorHighlight::before { + -webkit-mask-image: var(--toolbarButton-editorHighlight-icon); + mask-image: var(--toolbarButton-editorHighlight-icon); +} + +#editorInk::before { + -webkit-mask-image: var(--toolbarButton-editorInk-icon); + mask-image: var(--toolbarButton-editorInk-icon); +} + +#editorStamp::before { + -webkit-mask-image: var(--toolbarButton-editorStamp-icon); + mask-image: var(--toolbarButton-editorStamp-icon); +} + +:is(#print, #secondaryPrint)::before { + -webkit-mask-image: var(--toolbarButton-print-icon); + mask-image: var(--toolbarButton-print-icon); +} + +#secondaryOpenFile::before, +#openFile::before { + -webkit-mask-image: var(--toolbarButton-openFile-icon); + mask-image: var(--toolbarButton-openFile-icon); +} + +:is(#download, #secondaryDownload)::before { + -webkit-mask-image: var(--toolbarButton-download-icon); + mask-image: var(--toolbarButton-download-icon); +} + +a.secondaryToolbarButton { + padding-top: 5px; + text-decoration: none; +} +a:is(.toolbarButton, .secondaryToolbarButton)[href="#"] { + opacity: 0.5; + pointer-events: none; +} + +#viewBookmark::before { + -webkit-mask-image: var(--toolbarButton-bookmark-icon); + mask-image: var(--toolbarButton-bookmark-icon); +} + +#viewThumbnail::before { + -webkit-mask-image: var(--toolbarButton-viewThumbnail-icon); + mask-image: var(--toolbarButton-viewThumbnail-icon); +} + +#viewOutline::before { + -webkit-mask-image: var(--toolbarButton-viewOutline-icon); + mask-image: var(--toolbarButton-viewOutline-icon); + transform: scaleX(var(--dir-factor)); +} + +#viewAttachments::before { + -webkit-mask-image: var(--toolbarButton-viewAttachments-icon); + mask-image: var(--toolbarButton-viewAttachments-icon); +} + +#viewLayers::before { + -webkit-mask-image: var(--toolbarButton-viewLayers-icon); + mask-image: var(--toolbarButton-viewLayers-icon); +} + +#currentOutlineItem::before { + -webkit-mask-image: var(--toolbarButton-currentOutlineItem-icon); + mask-image: var(--toolbarButton-currentOutlineItem-icon); + transform: scaleX(var(--dir-factor)); +} + +#viewFind::before { + -webkit-mask-image: var(--toolbarButton-search-icon); + mask-image: var(--toolbarButton-search-icon); +} + +.pdfSidebarNotification::after { + position: absolute; + display: inline-block; + top: 2px; + inset-inline-end: 2px; + content: ""; + background-color: rgb(112 219 85); + height: 9px; + width: 9px; + border-radius: 50%; +} + +.secondaryToolbarButton { + position: relative; + margin: 0; + padding: 0 0 1px; + padding-inline-start: 36px; + height: auto; + min-height: 26px; + width: auto; + min-width: 100%; + text-align: start; + white-space: normal; + border-radius: 0; + box-sizing: border-box; + display: inline-block; +} +.secondaryToolbarButton > span { + padding-inline-end: 4px; +} + +#firstPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-firstPage-icon); + mask-image: var(--secondaryToolbarButton-firstPage-icon); +} + +#lastPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-lastPage-icon); + mask-image: var(--secondaryToolbarButton-lastPage-icon); +} + +#pageRotateCcw::before { + -webkit-mask-image: var(--secondaryToolbarButton-rotateCcw-icon); + mask-image: var(--secondaryToolbarButton-rotateCcw-icon); +} + +#pageRotateCw::before { + -webkit-mask-image: var(--secondaryToolbarButton-rotateCw-icon); + mask-image: var(--secondaryToolbarButton-rotateCw-icon); +} + +#cursorSelectTool::before { + -webkit-mask-image: var(--secondaryToolbarButton-selectTool-icon); + mask-image: var(--secondaryToolbarButton-selectTool-icon); +} + +#cursorHandTool::before { + -webkit-mask-image: var(--secondaryToolbarButton-handTool-icon); + mask-image: var(--secondaryToolbarButton-handTool-icon); +} + +#scrollPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollPage-icon); + mask-image: var(--secondaryToolbarButton-scrollPage-icon); +} + +#scrollVertical::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollVertical-icon); + mask-image: var(--secondaryToolbarButton-scrollVertical-icon); +} + +#scrollHorizontal::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollHorizontal-icon); + mask-image: var(--secondaryToolbarButton-scrollHorizontal-icon); +} + +#scrollWrapped::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollWrapped-icon); + mask-image: var(--secondaryToolbarButton-scrollWrapped-icon); +} + +#spreadNone::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadNone-icon); + mask-image: var(--secondaryToolbarButton-spreadNone-icon); +} + +#spreadOdd::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadOdd-icon); + mask-image: var(--secondaryToolbarButton-spreadOdd-icon); +} + +#spreadEven::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadEven-icon); + mask-image: var(--secondaryToolbarButton-spreadEven-icon); +} + +#documentProperties::before { + -webkit-mask-image: var(--secondaryToolbarButton-documentProperties-icon); + mask-image: var(--secondaryToolbarButton-documentProperties-icon); +} + +.verticalToolbarSeparator { + display: block; + margin: 5px 2px; + width: 1px; + height: 22px; + background-color: var(--separator-color); +} +.horizontalToolbarSeparator { + display: block; + margin: 6px 0; + height: 1px; + width: 100%; + background-color: var(--doorhanger-separator-color); +} + +.toolbarField { + padding: 4px 7px; + margin: 3px 0; + border-radius: 2px; + background-color: var(--field-bg-color); + background-clip: padding-box; + border: 1px solid var(--field-border-color); + box-shadow: none; + color: var(--field-color); + font-size: 12px; + line-height: 16px; + outline: none; +} + +.toolbarField[type="checkbox"] { + opacity: 0; + position: absolute !important; + left: 0; + margin: 10px 0 3px; + margin-inline-start: 7px; +} + +#pageNumber { + -moz-appearance: textfield; + text-align: end; + width: var(--toolButton-width); + height: var(--toolButton-height); + font-size: 1.25rem !important; + background-size: 0 0; + transition-property: none; + border-radius: 10px; +} + +#pageNumber::-webkit-inner-spin-button { + -webkit-appearance: none; +} + +.loadingInput:has(> #pageNumber.loading)::after { + display: block; + visibility: visible; + + transition-property: visibility; + transition-delay: var(--loading-icon-delay); +} + +.loadingInput::after { + position: absolute; + visibility: hidden; + display: none; + top: calc(50% - 12px); + width: 16px; + height: 16px; + + content: ""; + background-color: var(--toolbar-icon-bg-color); + -webkit-mask-size: cover; + mask-size: cover; + -webkit-mask-image: var(--loading-icon); + mask-image: var(--loading-icon); +} + +.loadingInput.start { + height: var(--toolButton-height); + width: var(--toolButton-width); + padding-top: 5px; +} + +.loadingInput.start::after { + inset-inline-start: 4px; +} + +.loadingInput.end::after { + inset-inline-end: 4px; +} + +.toolbarField:focus { + border-color: #0a84ff; +} + +.toolbarLabel { + min-width: 16px; + padding: 7px; + margin: 2px; + border-radius: 2px; + color: var(--md-sys-color-on-surface); + font-size: 12px; + line-height: 14px; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: default; +} + +#numPages { + font-size: 1.25rem; + line-height: 2.812rem; +} + +#numPages.toolbarLabel { + padding-inline-start: 3px; +} + +#thumbnailView, +#outlineView, +#attachmentsView, +#layersView { + position: absolute; + width: calc(100% - 12px); + inset-block: 0; + padding: 4px 4px 0; + overflow: auto; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +#thumbnailView { + width: calc(100% - 60px); + padding: 10px 30px 0; +} + +#thumbnailView > a:is(:active, :focus) { + outline: 0; +} + +.thumbnail { + --thumbnail-width: 0; + --thumbnail-height: 0; + + float: var(--inline-start); + width: var(--thumbnail-width); + height: var(--thumbnail-height); + margin: 0 10px 5px; + padding: 1px; + border: 7px solid transparent; + border-radius: 2px; +} + +#thumbnailView > a:last-of-type > .thumbnail { + margin-bottom: 10px; +} + +a:focus > .thumbnail, +.thumbnail:hover { + border-color: var(--thumbnail-hover-color); +} +.thumbnail.selected { + border-color: var(--thumbnail-selected-color) !important; +} + +.thumbnailImage { + width: var(--thumbnail-width); + height: var(--thumbnail-height); + opacity: 0.9; +} +a:focus > .thumbnail > .thumbnailImage, +.thumbnail:hover > .thumbnailImage { + opacity: 0.95; +} +.thumbnail.selected > .thumbnailImage { + opacity: 1 !important; +} + +.thumbnail:not([data-loaded]) > .thumbnailImage { + width: calc(var(--thumbnail-width) - 2px); + height: calc(var(--thumbnail-height) - 2px); + border: 1px dashed rgb(132 132 132); +} + +.treeWithDeepNesting > .treeItem, +.treeItem > .treeItems { + margin-inline-start: 20px; +} + +.treeItem > a { + text-decoration: none; + display: inline-block; + min-width: calc(100% - 4px); + height: auto; + margin-bottom: 1px; + padding: 2px 0 5px; + padding-inline-start: 4px; + border-radius: 2px; + color: var(--treeitem-color); + font-size: 13px; + line-height: 15px; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + white-space: normal; + cursor: pointer; +} + +#layersView .treeItem > a * { + cursor: pointer; +} +#layersView .treeItem > a > label { + padding-inline-start: 4px; +} +#layersView .treeItem > a > label > input { + float: var(--inline-start); + margin-top: 1px; +} + +.treeItemToggler { + position: relative; + float: var(--inline-start); + height: 0; + width: 0; + color: rgb(255 255 255 / 0.5); +} +.treeItemToggler::before { + inset-inline-end: 4px; + -webkit-mask-image: var(--treeitem-expanded-icon); + mask-image: var(--treeitem-expanded-icon); +} +.treeItemToggler.treeItemsHidden::before { + -webkit-mask-image: var(--treeitem-collapsed-icon); + mask-image: var(--treeitem-collapsed-icon); + transform: scaleX(var(--dir-factor)); +} +.treeItemToggler.treeItemsHidden ~ .treeItems { + display: none; +} + +.treeItem.selected > a { + background-color: var(--treeitem-selected-bg-color); + color: var(--treeitem-selected-color); +} + +.treeItemToggler:hover, +.treeItemToggler:hover + a, +.treeItemToggler:hover ~ .treeItems, +.treeItem > a:hover { + background-color: var(--treeitem-bg-color); + background-clip: padding-box; + border-radius: 2px; + color: var(--treeitem-hover-color); +} + +#outlineOptionsContainer { + display: none; +} + +#sidebarContainer:has(#outlineView:not(.hidden)) #outlineOptionsContainer { + display: inherit; +} + +.dialogButton { + width: auto; + margin: 3px 4px 2px !important; + padding: 2px 11px; + color: var(--main-color); + background-color: var(--dialog-button-bg-color); + border: var(--dialog-button-border) !important; +} + +dialog { + margin: auto; + padding: 15px; + border-spacing: 4px; + color: var(--main-color); + font: message-box; + font-size: 12px; + line-height: 14px; + background-color: var(--doorhanger-bg-color); + border: 1px solid rgb(0 0 0 / 0.5); + border-radius: 4px; + box-shadow: 0 1px 4px rgb(0 0 0 / 0.3); +} +dialog::backdrop { + background-color: rgb(0 0 0 / 0.2); +} + +dialog > .row { + display: table-row; +} + +dialog > .row > * { + display: table-cell; +} + +dialog .toolbarField { + margin: 5px 0; +} + +dialog .separator { + display: block; + margin: 4px 0; + height: 1px; + width: 100%; + background-color: var(--separator-color); +} + +dialog .buttonRow { + text-align: center; + vertical-align: middle; +} + +dialog :link { + color: rgb(255 255 255); +} + +#passwordDialog { + text-align: center; +} +#passwordDialog .toolbarField { + width: 200px; +} + +#documentPropertiesDialog { + text-align: left; +} +#documentPropertiesDialog .row > * { + min-width: 100px; + text-align: start; +} +#documentPropertiesDialog .row > span { + width: 125px; + word-wrap: break-word; +} +#documentPropertiesDialog .row > p { + max-width: 225px; + word-wrap: break-word; +} +#documentPropertiesDialog .buttonRow { + margin-top: 10px; +} + +.grab-to-pan-grab { + cursor: grab !important; +} +.grab-to-pan-grab + *:not(input):not(textarea):not(button):not(select):not(:link) { + cursor: inherit !important; +} +.grab-to-pan-grab:active, +.grab-to-pan-grabbing { + cursor: grabbing !important; +} +.grab-to-pan-grabbing { + position: fixed; + background: rgb(0 0 0 / 0); + display: block; + inset: 0; + overflow: hidden; + z-index: 50000; +} + +@page { + margin: 0; +} + +#printContainer { + display: none; +} + +@media print { + body { + background: rgb(0 0 0 / 0) none; + } + body[data-pdfjsprinting] #outerContainer { + display: none; + } + body[data-pdfjsprinting] #printContainer { + display: block; + } + #printContainer { + height: 100%; + } + #printContainer > .printedPage { + page-break-after: always; + page-break-inside: avoid; + height: 100%; + width: 100%; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + #printContainer > .xfaPrintedPage .xfaPage { + position: absolute; + } + + #printContainer > .xfaPrintedPage { + page-break-after: always; + page-break-inside: avoid; + width: 100%; + height: 100%; + position: relative; + } + + #printContainer > .printedPage :is(canvas, img) { + max-width: 100%; + max-height: 100%; + + direction: ltr; + display: block; + } +} + +.visibleMediumView { + display: none; +} + +@media all and (max-width: 840px) { + #sidebarContainer { + background-color: var(--sidebar-narrow-bg-color); + } + #outerContainer.sidebarOpen #viewerContainer { + inset-inline-start: 0 !important; + } +} + +@media all and (max-width: 750px) { + :root { + --editor-toolbar-base-offset: 40px; + } + #outerContainer .hiddenMediumView { + display: none; + } + #outerContainer .visibleMediumView { + display: inherit; + } +} + +@media all and (max-width: 690px) { + .hiddenSmallView, + .hiddenSmallView * { + display: none; + } + .toolbarButtonSpacer { + width: 0; + } + .findbar { + inset-inline-start: 34px; + } +} +/* +@media all and (max-width: 560px){ + #scaleSelectContainer{ + display:none; + } +} */ + +#showMoreBtnContainer { + display: none; +} +.toolbar img.main-icon { + height: 3.375rem; + width: 3.375rem; + inset: 5px; +} + +@media (max-width: 1125px) { + #showMoreBtnContainer { + display: flex; + } + + #toolbarViewerMiddle > .splitToolbarButton { + display: flex; + } + + #toolbarViewerRight { + display: none; + margin-left: 0; + } + + #toolbarViewerRight > div.splitToolbarButton { + display: flex; + flex-direction: column; + align-items: center; + row-gap: 3px; + + position: absolute; + left: 3px; + top: var(--toolbar-height); + } +} + +@media (max-width: 885px) { + #toolbarViewerMiddle { + order: 3; + position: fixed; + display: flex; + flex-wrap: nowrap; + bottom: 15px; + left: 50%; + transform: translate(-50%); + } + + #toolbarViewerMiddle .splitToolbarButton .splitToolbarButtonSeparator { + display: none; + } + + #redactionsToolbarViewer { + order: 2; + } + + + #pageBasedRedactionOverlay > .bg-card { + padding: 1.5rem; + } + + #pageBasedRedactionOverlay > .bg-card > div.tool-header { + display: flex; + column-gap: 10px; + } + + #pageBasedRedactionOverlay > .bg-card > div.tool-header > span:nth-child(1) { + margin: auto; + height: 3.5rem; + width: 3.5rem; + border-radius: 15px; + font-size: 2.5rem; + } + + #pageBasedRedactionOverlay > .bg-card > div.tool-header > span:nth-child(2) { + font-size: 1.5rem; + } + + #pageBasedRedactionOverlay > .bg-card > div:nth-child(3) { + flex-direction: column; + row-gap: 3px; + } + + #pageBasedRedactionOverlay > .bg-card > div:nth-child(3) > input { + width: 100%; + height: 30px; + margin-left: 0 !important; + flex: none; + } +} + +@media (max-width: 510px) { + .toolbar img.main-icon { + display: none; + } +} + +@media (max-width: 450px) { + :root { + --toolButton-height: 2.5rem; + --toolButton-width: 2.5rem; + --toolButton-icon-font-size: 1.8rem; + } + + #pageNumber { + font-size: 1rem !important; + } + + #numPages { + font-size: 1rem; + line-height: 2.512rem; + } + + .toolbarButton::before { + left: 5px; + top: 5px; + } + + #redactionsToolbarViewer { + order: 2; + } + + #toolbarViewerMiddle { + position: fixed; + display: flex; + flex-wrap: nowrap; + order: 3; + bottom: 15px; + left: 50%; + transform: translate(-50%); + } + + #scaleSelectContainer { + height: 2.825rem; + } + + html, + body { + overflow: hidden !important; + } + + .splitToolbarButton { + display: flex !important; + } + + .toolbar img.main-icon { + height: var(--toolButton-height); + width: var(--toolButton-width); + inset: 10px 0 0 0; + } +} + +@media (max-width: 390px) { + #toolbarViewerLeft { + display: grid; + } + + #toolbarViewerLeft #showMoreBtnContainer { + grid-row: 1; + grid-column: 1; + } + + #sidebarToggle { + grid-row: 1; + grid-column: 2; + } + + #toolbarViewerLeft .loadingInput.start { + grid-row: 1; + grid-column: 3; + + margin-bottom: auto; + margin-top: -2px + } + + #pageNumber { + height: 1.9rem; + } + + #numPages { + grid-row: 1; + grid-column: 3; + + line-height: 0; + + margin-top: auto; + margin-bottom: -4px + } + +} diff --git a/src/main/resources/static/pdfjs-legacy/pdf.mjs b/src/main/resources/static/pdfjs-legacy/pdf.mjs index e38f4c38..da8e4014 100644 --- a/src/main/resources/static/pdfjs-legacy/pdf.mjs +++ b/src/main/resources/static/pdfjs-legacy/pdf.mjs @@ -4630,7 +4630,7 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) { /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; -/******/ +/******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache @@ -4644,14 +4644,14 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) { /******/ // no module.loaded needed /******/ exports: {} /******/ }; -/******/ +/******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } -/******/ +/******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { @@ -4664,12 +4664,12 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) { /******/ } /******/ }; /******/ })(); -/******/ +/******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); -/******/ +/******/ /************************************************************************/ var __webpack_exports__ = globalThis.pdfjsLib = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. @@ -6385,8 +6385,8 @@ function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true) const useRound = util_FeatureTest.isCSSRoundSupported; const w = `var(--scale-factor) * ${pageWidth}px`, h = `var(--scale-factor) * ${pageHeight}px`; - const widthStr = useRound ? `round(${w}, 1px)` : `calc(${w})`, - heightStr = useRound ? `round(${h}, 1px)` : `calc(${h})`; + const widthStr = useRound ? `round(up, ${w}, 1px)` : `calc(${w})`, + heightStr = useRound ? `round(up, ${h}, 1px)` : `calc(${h})`; if (!mustFlip || viewport.rotation % 180 === 0) { style.width = widthStr; style.height = heightStr; @@ -24317,4 +24317,4 @@ var __webpack_exports__updateTextLayer = __webpack_exports__.updateTextLayer; var __webpack_exports__version = __webpack_exports__.version; export { __webpack_exports__AbortException as AbortException, __webpack_exports__AnnotationEditorLayer as AnnotationEditorLayer, __webpack_exports__AnnotationEditorParamsType as AnnotationEditorParamsType, __webpack_exports__AnnotationEditorType as AnnotationEditorType, __webpack_exports__AnnotationEditorUIManager as AnnotationEditorUIManager, __webpack_exports__AnnotationLayer as AnnotationLayer, __webpack_exports__AnnotationMode as AnnotationMode, __webpack_exports__CMapCompressionType as CMapCompressionType, __webpack_exports__ColorPicker as ColorPicker, __webpack_exports__DOMSVGFactory as DOMSVGFactory, __webpack_exports__DrawLayer as DrawLayer, __webpack_exports__FeatureTest as FeatureTest, __webpack_exports__GlobalWorkerOptions as GlobalWorkerOptions, __webpack_exports__ImageKind as ImageKind, __webpack_exports__InvalidPDFException as InvalidPDFException, __webpack_exports__MissingPDFException as MissingPDFException, __webpack_exports__OPS as OPS, __webpack_exports__Outliner as Outliner, __webpack_exports__PDFDataRangeTransport as PDFDataRangeTransport, __webpack_exports__PDFDateString as PDFDateString, __webpack_exports__PDFWorker as PDFWorker, __webpack_exports__PasswordResponses as PasswordResponses, __webpack_exports__PermissionFlag as PermissionFlag, __webpack_exports__PixelsPerInch as PixelsPerInch, __webpack_exports__RenderingCancelledException as RenderingCancelledException, __webpack_exports__TextLayer as TextLayer, __webpack_exports__UnexpectedResponseException as UnexpectedResponseException, __webpack_exports__Util as Util, __webpack_exports__VerbosityLevel as VerbosityLevel, __webpack_exports__XfaLayer as XfaLayer, __webpack_exports__build as build, __webpack_exports__createValidAbsoluteUrl as createValidAbsoluteUrl, __webpack_exports__fetchData as fetchData, __webpack_exports__getDocument as getDocument, __webpack_exports__getFilenameFromUrl as getFilenameFromUrl, __webpack_exports__getPdfFilenameFromUrl as getPdfFilenameFromUrl, __webpack_exports__getXfaPageViewport as getXfaPageViewport, __webpack_exports__isDataScheme as isDataScheme, __webpack_exports__isPdfFile as isPdfFile, __webpack_exports__noContextMenu as noContextMenu, __webpack_exports__normalizeUnicode as normalizeUnicode, __webpack_exports__renderTextLayer as renderTextLayer, __webpack_exports__setLayerDimensions as setLayerDimensions, __webpack_exports__shadow as shadow, __webpack_exports__updateTextLayer as updateTextLayer, __webpack_exports__version as version }; -//# sourceMappingURL=pdf.mjs.map \ No newline at end of file +//# sourceMappingURL=pdf.mjs.map diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index d4cdebbe..b89f60a0 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -170,6 +170,9 @@
+
+
diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 02b6699c..f8f1901a 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -227,6 +227,9 @@
+
+
diff --git a/src/main/resources/templates/security/redact.html b/src/main/resources/templates/security/redact.html new file mode 100644 index 00000000..f060211b --- /dev/null +++ b/src/main/resources/templates/security/redact.html @@ -0,0 +1,708 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+
+
+
+ ink_eraser + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+
+
+ +
+
+
+ document_scanner + +
+
+ + +
+
+ + +
+ + +
+
+
+
+
+
+
+ + + + +
+
+ +
+
+
+ + +
+
+
+
+
+
+ + + +
+
+
+ +
+ + + + + + + + + + + + +
+
+
+
+
+ +
+ +
+ +
+ +
+ +
+ + + + + icon +
+
+
+ +
+ +
+ + + +
+
+ + + + +
+
+
+ + + + +
+
+ + + + + +
+ +
+ + + + + +
+ + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+ +
+ +
+
+ +
+
+ + +
+
+ +
+ File name: +

-

+
+
+ File size: +

-

+
+
+
+ Title: +

-

+
+
+ Author: +

-

+
+
+ Subject: +

-

+
+
+ Keywords: +

-

+
+
+ Creation + Date: +

-

+
+
+ Modification + Date: +

-

+
+
+ Creator: +

-

+
+
+
+ PDF Producer: +

-

+
+
+ PDF Version: +

-

+
+
+ Page Count: +

-

+
+
+ Page Size: +

-

+
+
+
+ Fast Web View: +

-

+
+
+ +
+
+ +
+
+ Choose an + option + + Alt text (alternative text) helps when people can’t see the image or when it doesn’t load. + +
+
+
+
+ + +
+
+ + Aim for 1-2 sentences that describe the subject, setting, or actions. + +
+
+
+ +
+
+
+
+
+ + +
+
+ + This is used for ornamental images, like borders or watermarks. + +
+
+
+
+ + +
+
+
+ +
+ Preparing document for printing… +
+
+ + 0% +
+
+ +
+
+
+ +
+
+ + + + + \ No newline at end of file