/*
    Styles for Morph's Blazor components. Link it from the host app:

        <link rel="stylesheet" href="_content/Morph.Blazor/morph.css" />

    Theming is done entirely through the --morph-* custom properties below. Every rule reads them with a
    literal fallback, so the components look right with no configuration at all, and nothing here declares
    a value of its own — link order can't fight the host, and a host that themes by setting these on :root
    always wins. To follow a host palette, map them once:

        :root {
            --morph-primary: var(--primary-color);
            --morph-surface: var(--surface-color);
        }

    | property           | what it colours                                  | default |
    | ------------------ | ------------------------------------------------ | ------- |
    | --morph-primary    | headings, focus accents, the download button      | #2b579a |
    | --morph-surface    | raised panels (upload area, option/convert panels) | #ffffff |
    | --morph-background | recessed areas (preview well, select backgrounds)  | #f8f9fa |
    | --morph-text       | body text                                          | #333    |
    | --morph-muted      | secondary text (captions, notes, progress labels)  | #6c757d |
    | --morph-border     | every border and divider                           | #dee2e6 |
    | --morph-band       | the editor's title band, its tabs and file name     | --morph-primary, darkened |
    | --morph-on-band    | text and icons on the band                         | #ffffff |
    | --morph-selection  | selected text on a rendered page                   | rgb(0 96 223 / 0.3)   |
    | --morph-find       | the viewer's find matches                          | rgb(255 200 0 / 0.45) |
    | --morph-find-current | the viewer's current find match                  | rgb(255 110 0 / 0.55) |
*/

/* Scoped to this library's own subtrees so the package never imposes a global reset on the host. */
:where(.converter, .converter *, .preview, .preview *, .progress, .progress *, .error, .error *, .viewer, .viewer *) {
    box-sizing: border-box;
}

.converter {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.file-drop {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 2rem;
    background: var(--morph-surface, #ffffff);
    border: 2px dashed var(--morph-border, #dee2e6);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
}

.file-drop:hover,
.converter-dragging .file-drop {
    border-color: var(--morph-primary, #2b579a);
}

.converter-dragging .file-drop {
    background: color-mix(in srgb, var(--morph-primary, #2b579a) 8%, var(--morph-surface, #ffffff));
}

.file-drop-icon {
    display: flex;
    color: var(--morph-primary, #2b579a);
}

.file-drop-icon svg {
    width: 2.5rem;
    height: 2.5rem;
}

.file-drop-text {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.file-drop-text strong {
    color: var(--morph-primary, #2b579a);
    font-size: 1.1rem;
}

.file-drop-text span {
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
}

.file-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}

.upload-panel {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.upload-or {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.upload-or::before,
.upload-or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--morph-border, #dee2e6);
}

/* One sample button per readable format. They share the row evenly on a roomy panel and wrap to full
   width when it gets tight, so the labels never truncate. */
.sample-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.sample-btn {
    display: inline-flex;
    flex: 1 1 10rem;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.95rem;
    font-weight: 600;
    transition: border-color 0.2s, background 0.2s;
}

.sample-btn svg {
    flex: none;
    width: 1.15rem;
    height: 1.15rem;
}

.sample-btn:hover:not(:disabled) {
    border-color: var(--morph-primary, #2b579a);
}

.sample-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* The preview stacks one image per rendered page; it scrolls when a long document exceeds the cap. */
.preview {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    max-height: 70vh;
    overflow-y: auto;
    background: var(--morph-background, #f8f9fa);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    padding: 1rem;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.15);
}

/* One page: the image and, over it, the selectable text layer. The sheet carries the paper look so the
   overlay's box is exactly the image's — no border between the two to offset the text. */
.preview-sheet {
    position: relative;
    max-width: 100%;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 2px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    background: #ffffff;
}

.preview-page {
    display: block;
    max-width: 100%;
    height: auto;
}

/*
    The selectable text layer (morph-text.js): transparent text over a rendered page image, where the page
    drew it. The overlay is a size container and every length inside is in cqw, so the text tracks the
    image's displayed size at any width or zoom with no script. Nothing here is visible — only a
    selection or a find highlight paints.
*/
.text-layer {
    position: absolute;
    inset: 0;
    overflow: clip;
    container-type: inline-size;
    /* 0px: a stray <br>'s line has no height, so there is nothing to hit between the positioned lines. */
    font: 400 0/1 "Morph Text", sans-serif;
    font-kerning: normal;
    font-synthesis: none;
    text-rendering: geometricPrecision;
    letter-spacing: 0;
    word-spacing: 0;
    text-transform: none;
    text-indent: 0;
    text-align: left;
    white-space: pre;
    direction: ltr;
    forced-color-adjust: none;
    -webkit-text-size-adjust: none;
    text-size-adjust: none;
    user-select: text;
    -webkit-user-select: text;
}

/* A correctness guard rather than theming: the raster below already shows the text. */
.text-layer,
.text-layer * {
    color: transparent !important;
}

/* Word's formatting marks (Show/Hide ¶): no text of their own, never hit, drawn in Word's mark blue. */
.text-marks {
    position: absolute;
    inset: 0;
    pointer-events: none;
    user-select: none;
}

.text-layer .text-mark {
    position: absolute;
    line-height: 1;
    color: #3b5ba5 !important;
    font-family: "Morph Text", sans-serif;
    white-space: pre;
}

.text-mark::before {
    content: attr(data-m);
}

.text-mark-space,
.text-mark-tab {
    transform: translate(-50%, -50%);
}

.text-mark-end {
    transform: translateY(-50%);
}

.text-line,
.text-frame,
.text-end,
.text-layer br {
    position: absolute;
}

.text-line {
    cursor: text;
    z-index: 1;
}

.text-layer .b {
    font-weight: 700;
}

.text-layer .i {
    font-style: italic;
}

/* Rotated text boxes and cells turn about their centre, as the painter turns them. */
.text-frame {
    transform-origin: 50% 50%;
}

.text-clip {
    overflow: clip;
}

/* A Word exact-height row clips vertically only: ink may overhang the cell sideways. */
.text-clip-y {
    overflow-x: visible;
    overflow-y: clip;
}

/* Without an explicit rule the browser repaints selected text in a visible colour; this keeps it
   transparent and paints only the band. */
.text-layer ::selection {
    color: transparent;
    background: var(--morph-selection, rgb(0 96 223 / 0.3));
}

.text-layer br::selection {
    background: transparent;
}

/* A rule of its own: a selector list with a pseudo-element the browser does not know drops the whole rule. */
.text-layer ::search-text {
    color: transparent;
}

::highlight(morph-find) {
    color: transparent;
    background-color: var(--morph-find, rgb(255 200 0 / 0.45));
}

::highlight(morph-find-current) {
    color: transparent;
    background-color: var(--morph-find-current, rgb(255 110 0 / 0.55));
}

/* What a comment is on, and the comment or tracked change chosen in the review pane. */
::highlight(morph-comment) {
    color: transparent;
    background-color: var(--morph-comment, rgb(255 214 102 / 0.4));
}

::highlight(morph-review-current) {
    color: transparent;
    background-color: var(--morph-review-current, rgb(124 92 255 / 0.35));
}

/* The end-of-content element: covers the layer while a selection is dragged, so crossing empty space
   between lines extends the selection rather than jumping it to the page's start. */
.text-end {
    inset: 100% 0 0;
    z-index: 0;
    cursor: default;
    user-select: none;
    -webkit-user-select: none;
}

.text-layer.selecting .text-end {
    top: 0;
}

@media print {
    .text-layer {
        display: none;
    }
}

.preview-busy {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 200px;
    width: 100%;
}

/* Wraps the page preview and the result pane; on wide viewports they sit side by side. */
.workspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
}

/* The selected format's converted output, shown beside the page preview on wide screens only. */
.result-pane {
    display: flex;
    flex-direction: column;
    height: 70vh;
    overflow: hidden;
    background: var(--morph-background, #f8f9fa);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.15);
}

.result-caption {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 1rem;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
    font-weight: 600;
}

/* Annotation to the right of the caption title, explaining the "… KB elided …" markers in the text below. */
.result-note {
    font-size: 0.75rem;
    font-weight: 400;
    font-style: italic;
    white-space: nowrap;
}

/* Document content is designed against paper, so the iframe stays white in both themes. */
.result-frame {
    flex: 1;
    width: 100%;
    border: 0;
    background: #ffffff;
}

.result-text {
    flex: 1;
    margin: 0;
    padding: 1rem;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.result-busy {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

/* Wide screens: the page preview and the result pane sit side by side. :has() scopes the wider layout to
   when a pane is actually present, so the converter keeps its single column whenever there is nothing to
   show on the right. The host is responsible for letting its own container relax to suit — see the
   .container:has(.result-pane) rule in the sample app. */
@media (min-width: 1200px) {
    .workspace:has(.result-pane) {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    /* Match the pane's fixed height so the pair reads as one row. */
    .workspace:has(.result-pane) .preview {
        height: 70vh;
        max-height: none;
    }
}

.progress {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 100%;
}

.progress-track {
    position: relative;
    overflow: hidden;
    height: 8px;
    border-radius: 4px;
    background: var(--morph-border, #dee2e6);
}

.progress-fill {
    height: 100%;
    border-radius: 4px;
    background: var(--morph-primary, #2b579a);
    transition: width 0.15s ease;
}

.progress-fill-indeterminate {
    width: 40%;
    /* Animate transform, not margin-left. A conversion blocks the UI thread on the single-threaded
       runtime; a main-thread (layout) animation freezes with it, whereas a compositor-driven transform
       keeps sliding — so the bar stays alive while the render churns. will-change promotes it to its own
       layer so the compositor owns the animation. */
    animation: morph-progress-indeterminate 1.2s ease-in-out infinite;
    will-change: transform;
}

@keyframes morph-progress-indeterminate {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
}

.progress-label {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.85rem;
    color: var(--morph-muted, #6c757d);
}

.progress-count {
    font-variant-numeric: tabular-nums;
}

.image-options {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    padding: 1.5rem;
    background: var(--morph-surface, #ffffff);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.option-note {
    margin: 0;
    flex-basis: 100%;
    color: var(--morph-muted, #6c757d);
    font-size: 0.8rem;
}

.no-options {
    margin: 0;
    padding: 1rem 1.5rem;
    color: var(--morph-muted, #6c757d);
    background: var(--morph-surface, #ffffff);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    font-size: 0.9rem;
}

.download-row {
    display: flex;
}

.btn-spinner {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: 0.5rem;
    vertical-align: -0.15em;
    border: 2px solid rgba(255, 255, 255, 0.5);
    border-top-color: white;
    border-radius: 50%;
    animation: morph-spin 0.8s linear infinite;
}

@keyframes morph-spin {
    to { transform: rotate(360deg); }
}

.convert-panel {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: flex-end;
    padding: 1.5rem;
    background: var(--morph-surface, #ffffff);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.format-selector {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1;
    min-width: 200px;
}

.format-selector label {
    font-weight: 500;
}

.format-select {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font-size: 0.9rem;
}

.convert-btn {
    padding: 0.6rem 1.5rem;
    border: 1px solid var(--morph-primary, #2b579a);
    background: var(--morph-primary, #2b579a);
    color: white;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 600;
    transition: opacity 0.2s;
}

.convert-btn:hover {
    opacity: 0.9;
}

.convert-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Document content is designed against paper, so the error panel keeps its own light palette in both
   themes — like the preview and the result iframe. */
.error {
    padding: 1rem;
    background: #f8d7da;
    color: #842029;
    border: 1px solid #f5c2c7;
    border-radius: 8px;
}

.error-message {
    margin: 0;
}

.error-report {
    margin: 0.75rem 0 0;
    font-size: 0.9rem;
}

.error-report a {
    color: #842029;
    font-weight: 600;
}

/*
    The document viewer (MorphViewer): a toolbar, a thumbnail sidebar and a scrolling column of pages. It
    fills its box — give it a height; 80vh is only a default. The script sizes pages through two custom
    properties per page (--pw, --ph: the page in points) and one on the column (--z: the zoom), so a zoom
    is one property change and the layout follows without Blazor re-rendering anything.
*/
.viewer {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 80vh;
    min-height: 320px;
    overflow: hidden;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
}

.viewer[data-rotation="90"] {
    --viewer-rotation: 90deg;
}

.viewer[data-rotation="180"] {
    --viewer-rotation: 180deg;
}

.viewer[data-rotation="270"] {
    --viewer-rotation: 270deg;
}

.viewer-toolbar,
.viewer-findbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    padding: 0.35rem 0.5rem;
    background: var(--morph-surface, #ffffff);
    border-bottom: 1px solid var(--morph-border, #dee2e6);
}

.viewer-toolbar {
    justify-content: space-between;
}

.viewer-group {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.viewer-group-start,
.viewer-group-end {
    flex: 1 1 0;
}

.viewer-group-end {
    justify-content: flex-end;
}

.viewer-button {
    position: relative;
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--morph-text, #333);
    cursor: pointer;
}

/* Icons are Lucide's, drawn with their own stroke in the button's text colour: the sheet sizes them. */
.viewer-button svg {
    flex: none;
    width: 1.15rem;
    height: 1.15rem;
}

.viewer-button:hover:not(:disabled),
.viewer-button[aria-pressed="true"] {
    border-color: var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
}

.viewer-button[aria-pressed="true"] {
    color: var(--morph-primary, #2b579a);
}

.viewer-button:disabled {
    opacity: 0.4;
    cursor: default;
}

.viewer-button:focus-visible,
.viewer-thumb:focus-visible,
.viewer-pages:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -2px;
}

.viewer-hidden-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

.viewer-title {
    min-width: 0;
    margin-left: 0.25rem;
    overflow: hidden;
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.viewer-page-input,
.viewer-zoom,
.viewer-find-input {
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
}

.viewer-page-input {
    width: 3.25rem;
    text-align: right;
}

.viewer-page-count,
.viewer-find-status {
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.viewer-page-count {
    margin-right: 0.25rem;
}

.viewer-zoom {
    max-width: 9.5rem;
}

.viewer-divider {
    width: 1px;
    height: 1.25rem;
    margin: 0 0.25rem;
    background: var(--morph-border, #dee2e6);
}

.viewer-find-input {
    flex: 0 1 16rem;
    min-width: 8rem;
}

.viewer-find-option {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin: 0 0.5rem;
    font-size: 0.85rem;
    white-space: nowrap;
}

.viewer-find-status {
    min-width: 5rem;
}

.viewer-find-close {
    margin-left: auto;
}

.viewer-edit-signature {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
}

.viewer-edit-signature .review-signature-input {
    width: 8rem;
}

/*
    The editor laid over a paragraph (morph-edit.js). Like the text layer it is a size container the
    size of the page with every length in cqw, so it keeps its place and its size through any zoom; unlike
    the text layer it is there to be seen. The box is opaque — the paragraph's own picture is under it,
    and the two are never quite the same line for line.
*/
.edit-layer {
    position: absolute;
    inset: 0;
    z-index: 3;
    container-type: inline-size;
    pointer-events: none;
}

.edit-box {
    position: absolute;
    overflow-x: hidden;
    overflow-y: auto;
    outline: 1px solid #e3e3e3;
    outline-offset: 1px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.25);
    background-color: #ffffff;
    color: #000000;
    font-family: "Morph Text", sans-serif;
    font-kerning: normal;
    font-synthesis: none;
    font-style: normal;
    font-weight: 400;
    letter-spacing: 0;
    text-rendering: geometricPrecision;
    text-transform: none;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    direction: ltr;
    cursor: text;
    pointer-events: auto;
    user-select: text;
    -webkit-user-select: text;
    forced-color-adjust: none;
    -webkit-text-size-adjust: none;
    text-size-adjust: none;
}

.edit-box:focus-visible {
    outline-width: 2px;
}

.edit-box ::selection {
    background: var(--morph-selection, rgb(0 96 223 / 0.3));
}

/* Handed in: what was typed stays on show until the page is drawn again with it. */
.edit-box.edit-pending {
    outline-style: dashed;
    box-shadow: none;
    cursor: progress;
}

.edit-p {
    margin: 0;
    padding: 0;
}

/* A tab, as wide as the script sets it to reach the paragraph's stop (layoutTabs); its own character
   takes no room, and a stop's leader is drawn across it. */
.edit-tab {
    display: inline-block;
    width: 0;
    vertical-align: baseline;
    tab-size: 0;
    letter-spacing: 0;
    white-space: pre;
    /* So a leader, drawn along the bottom, runs near the baseline rather than under the line. */
    line-height: 1;
}

.edit-tab[data-leader="dot"] {
    border-bottom: 0.12em dotted currentColor;
}

.edit-tab[data-leader="hyphen"] {
    border-bottom: 0.08em dashed currentColor;
}

.edit-tab[data-leader="line"] {
    border-bottom: 0.06em solid currentColor;
}

.edit-tab[data-leader="heavy"] {
    border-bottom: 0.14em solid currentColor;
}

.edit-atom {
    user-select: all;
    -webkit-user-select: all;
}

.edit-hidden {
    display: none;
}

/* Text the page did not draw: hidden text, shown as Word shows it with its formatting marks on. */
.edit-undrawn {
    text-decoration-line: underline !important;
    text-decoration-style: dotted !important;
    opacity: 0.6;
}

.edit-field {
    background-color: rgb(0 0 0 / 0.08);
}

/* A field, a note's reference, a break or a picture struck under tracking in the open paragraph, until
   it is handed in: struck through in the revision colour, as the page draws a deletion. */
.edit-struck {
    color: #D13438 !important;
    text-decoration-line: line-through !important;
}

.edit-drawing.edit-struck {
    opacity: 0.5;
    outline: 2px solid #D13438;
    outline-offset: -2px;
}

.edit-drawing {
    display: inline-block;
    vertical-align: baseline;
    border: 1px dashed var(--morph-muted, #6c757d);
    background-color: rgb(0 0 0 / 0.05);
}

/* The picture itself, drawn at the size the line gives it: no stand-in's frame or shade. */
.edit-drawing.edit-picture {
    border: none;
    background-color: transparent;
    background-size: 100% 100%;
    background-repeat: no-repeat;
}

/* A picture selected in the line: a frame its handles size it by, its size, and a way back to the
   size it was made for. In the editing layer beside the box, so none of it is the paragraph's text. */
.edit-frame {
    position: absolute;
    z-index: 3;
    box-sizing: border-box;
    border: 1px solid var(--morph-primary, #2b579a);
    pointer-events: none;
}

.edit-handle {
    position: absolute;
    width: 9px;
    height: 9px;
    margin: -5px 0 0 -5px;
    border: 1px solid var(--morph-primary, #2b579a);
    border-radius: 50%;
    background: #ffffff;
    pointer-events: auto;
    touch-action: none;
}

.edit-handle-nw { left: 0; top: 0; cursor: nwse-resize; }
.edit-handle-n { left: 50%; top: 0; cursor: ns-resize; }
.edit-handle-ne { left: 100%; top: 0; cursor: nesw-resize; }
.edit-handle-e { left: 100%; top: 50%; cursor: ew-resize; }
.edit-handle-se { left: 100%; top: 100%; cursor: nwse-resize; }
.edit-handle-s { left: 50%; top: 100%; cursor: ns-resize; }
.edit-handle-sw { left: 0; top: 100%; cursor: nesw-resize; }
.edit-handle-w { left: 0; top: 50%; cursor: ew-resize; }

.edit-frame-size,
.edit-frame-reset {
    position: absolute;
    top: calc(100% + 6px);
    padding: 1px 6px;
    border-radius: 3px;
    font: 12px/1.6 var(--morph-font, system-ui, sans-serif);
    white-space: nowrap;
}

.edit-frame-size {
    left: 0;
    background: var(--morph-primary, #2b579a);
    color: #ffffff;
}

.edit-frame-reset {
    right: 0;
    border: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333333);
    cursor: pointer;
    pointer-events: auto;
}

.edit-break {
    padding: 0 0.4em;
    border: 1px dashed var(--morph-muted, #6c757d);
    color: var(--morph-muted, #6c757d);
    font-size: 0.7em;
    white-space: nowrap;
}

@media print {
    .edit-layer {
        display: none;
    }
}

.viewer > .error {
    margin: 0.5rem;
}

.viewer-body {
    position: relative;
    display: flex;
    flex: 1;
    min-height: 0;
}

.viewer-sidebar {
    display: none;
    flex: none;
    width: 172px;
    overflow-y: auto;
    background: var(--morph-surface, #ffffff);
    border-right: 1px solid var(--morph-border, #dee2e6);
}

.viewer[data-sidebar] .viewer-sidebar {
    display: block;
}

.viewer-thumbs {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0;
}

.viewer-thumb {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem;
    border: 2px solid transparent;
    border-radius: 4px;
    background: none;
    color: var(--morph-muted, #6c757d);
    font: inherit;
    font-size: 0.75rem;
    cursor: pointer;
}

.viewer-thumb[aria-current="page"] {
    border-color: var(--morph-primary, #2b579a);
    color: var(--morph-primary, #2b579a);
}

/* 120px wide, the page's shape — turned with the pages. */
.viewer-thumb-sheet {
    position: relative;
    display: block;
    width: 120px;
    aspect-ratio: var(--pw) / var(--ph);
    overflow: hidden;
    background: #ffffff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.viewer[data-rotation="90"] .viewer-thumb-sheet,
.viewer[data-rotation="270"] .viewer-thumb-sheet {
    aspect-ratio: var(--ph) / var(--pw);
}

.viewer-thumb-sheet img,
.viewer-thumb-vector {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 120px;
    aspect-ratio: var(--pw) / var(--ph);
    transform: translate(-50%, -50%) rotate(var(--viewer-rotation, 0deg));
}

.viewer-thumb-vector {
    height: auto;
    pointer-events: none;
}

.viewer[data-rotation="90"] .viewer-thumb-sheet img,
.viewer[data-rotation="270"] .viewer-thumb-sheet img,
.viewer[data-rotation="90"] .viewer-thumb-vector,
.viewer[data-rotation="270"] .viewer-thumb-vector {
    width: calc(120px * var(--pw) / var(--ph));
}

.viewer-thumb-sheet img:not([src]),
.viewer-image:not([src]) {
    visibility: hidden;
}

.viewer-main {
    position: relative;
    display: flex;
    flex: 1;
    min-width: 0;
}

/* Pages centre with auto margins rather than align-items: centring, a page zoomed wider than the view
   would overflow to the left, out of reach of the scrollbar. */
.viewer-pages {
    --z: 1;
    position: relative;
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 12px;
    overflow: auto;
    overflow-anchor: none;
    /* Two fingers zoom the pages (morph-viewer.js), not the host's page around them. */
    touch-action: pan-x pan-y;
    scrollbar-gutter: stable;
}

/* content-visibility skips the layout and paint of off-screen pages; their text stays findable. */
.viewer-page {
    position: relative;
    flex: none;
    width: calc(var(--pw) * var(--z) * 1pt);
    height: calc(var(--ph) * var(--z) * 1pt);
    margin: 0 auto;
    background: #ffffff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    content-visibility: auto;
}

.viewer[data-rotation="90"] .viewer-page,
.viewer[data-rotation="270"] .viewer-page {
    width: calc(var(--ph) * var(--z) * 1pt);
    height: calc(var(--pw) * var(--z) * 1pt);
}

/* The page at its own orientation, turned into place — its text layer turns with it. */
.viewer-sheet {
    position: absolute;
    top: 50%;
    left: 50%;
    width: calc(var(--pw) * var(--z) * 1pt);
    height: calc(var(--ph) * var(--z) * 1pt);
    overflow: hidden;
    background: #ffffff;
    transform: translate(-50%, -50%) rotate(var(--viewer-rotation, 0deg));
}

.viewer-image {
    display: block;
    width: 100%;
    height: 100%;
    user-select: none;
    -webkit-user-select: none;
    -webkit-user-drag: none;
}

/* Holds a page's or a thumbnail's SVG and is inert, which the svg itself cannot be (morph-viewer.js,
   vectorFrom); it draws no box, so the svg lays out as the page's or the sheet's own child. */
.viewer-vector-holder {
    display: contents;
}

/* A page drawn as SVG (MorphViewer.VectorPages): a picture to the reader, whose text is the text layer's. */
.viewer-vector {
    display: block;
    width: 100%;
    height: 100%;
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
}

.viewer-page-message {
    position: absolute;
    top: 45%;
    right: 0;
    left: 0;
    padding: 0 1rem;
    color: #842029;
    font-size: 0.85rem;
    text-align: center;
}

.viewer-empty,
.viewer-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 2rem;
    text-align: center;
}

.viewer-overlay {
    z-index: 5;
    background: color-mix(in srgb, var(--morph-background, #f8f9fa) 85%, transparent);
}

.viewer-overlay .progress {
    max-width: 24rem;
}

.viewer-empty-title {
    margin: 0;
    color: var(--morph-primary, #2b579a);
    font-size: 1.1rem;
    font-weight: 600;
}

.viewer-empty-note {
    margin: 0;
    color: var(--morph-muted, #6c757d);
    font-size: 0.85rem;
}

.viewer-empty .sample-row {
    width: min(100%, 36rem);
    margin-top: 0.5rem;
}

.viewer-empty-open,
.viewer-overlay-cancel,
.viewer-print-ready button {
    padding: 0.5rem 1.25rem;
    border: 1px solid var(--morph-primary, #2b579a);
    border-radius: 4px;
    background: var(--morph-primary, #2b579a);
    color: white;
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}

.viewer-overlay-cancel {
    background: var(--morph-surface, #ffffff);
    color: var(--morph-primary, #2b579a);
}

.viewer-dragging .viewer-main::after {
    content: "";
    position: absolute;
    inset: 8px;
    border: 2px dashed var(--morph-primary, #2b579a);
    border-radius: 8px;
    pointer-events: none;
}

/* Shown only when Safari needs a fresh click before it will print. */
.viewer-print-ready {
    position: absolute;
    top: 1rem;
    left: 50%;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    transform: translateX(-50%);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    background: var(--morph-surface, #ffffff);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

/* How many comments and changes are waiting, on the toolbar button that opens them. */
.viewer-badge {
    position: absolute;
    top: -0.2rem;
    right: -0.3rem;
    min-width: 1rem;
    padding: 0 0.25rem;
    border-radius: 0.5rem;
    background: var(--morph-primary, #2b579a);
    color: white;
    font-size: 0.65rem;
    font-weight: 600;
    line-height: 1rem;
    text-align: center;
    pointer-events: none;
}

/*
    The review pane: a Word document's comments and tracked changes, one card each, down the document.
    It takes its width from the pages, which refit themselves (the script watches the column's size).
*/
.viewer-review {
    display: flex;
    flex: none;
    flex-direction: column;
    width: min(22rem, 45%);
    min-height: 0;
    background: var(--morph-surface, #ffffff);
    border-left: 1px solid var(--morph-border, #dee2e6);
    font-size: 0.85rem;
}

.viewer-review[aria-busy="true"] {
    cursor: progress;
}

.review-head,
.review-actions {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    padding: 0.35rem 0.5rem;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
}

.review-title {
    margin-right: 0.25rem;
    font-weight: 600;
}

.review-filter,
.review-signature-input,
.review-input {
    min-width: 0;
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font: inherit;
}

.review-filter {
    flex: 1 1 6rem;
}

.review-close {
    margin-left: auto;
}

.review-action,
.review-button {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    font: inherit;
    cursor: pointer;
}

.review-action:hover:not(:disabled),
.review-button:hover:not(:disabled) {
    background: var(--morph-background, #f8f9fa);
}

.review-action-primary,
.review-button-primary {
    border-color: var(--morph-primary, #2b579a);
    background: var(--morph-primary, #2b579a);
    color: white;
}

.review-action-primary:hover:not(:disabled),
.review-button-primary:hover:not(:disabled) {
    background: var(--morph-primary, #2b579a);
    filter: brightness(1.1);
}

.review-action:disabled,
.review-button:disabled,
.review-tool:disabled {
    opacity: 0.45;
    cursor: default;
}

.review-button svg {
    width: 0.9rem;
    height: 0.9rem;
}

.review-button svg g {
    stroke-width: 2.5;
}

.review-signature {
    display: flex;
    flex: none;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.5rem;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
    color: var(--morph-muted, #6c757d);
    white-space: nowrap;
}

.review-signature-input {
    flex: 1;
}

.review-note,
.review-empty {
    flex: none;
    margin: 0;
    padding: 0.5rem 0.75rem;
    color: var(--morph-muted, #6c757d);
}

.review-list {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.5rem;
    min-height: 0;
    padding: 0.5rem;
    overflow-y: auto;
}

.review-list:empty {
    display: none;
}

.review-card {
    display: flex;
    flex: none;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-left: 3px solid var(--morph-comment-accent, #d9a400);
    border-radius: 4px;
    background: var(--morph-surface, #ffffff);
    cursor: pointer;
}

/* A tracked change wears the colour it is drawn in on the page. */
.review-change {
    border-left-color: var(--morph-change-accent, #d13438);
}

.review-card:hover {
    background: var(--morph-background, #f8f9fa);
}

.review-card:focus-visible,
.review-tool:focus-visible,
.review-action:focus-visible,
.review-button:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: 1px;
}

.review-active {
    border-color: var(--morph-primary, #2b579a);
    border-left-color: var(--morph-primary, #2b579a);
    box-shadow: 0 1px 4px rgb(0 0 0 / 0.15);
}

.review-resolved:not(.review-active) {
    opacity: 0.65;
}

.review-entry {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.review-reply {
    margin-left: 0.5rem;
    padding-left: 0.6rem;
    border-left: 2px solid var(--morph-border, #dee2e6);
}

.review-meta {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
}

.review-avatar {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: var(--morph-primary, #2b579a);
    color: white;
    font-size: 0.65rem;
    font-weight: 600;
}

.review-name {
    min-width: 0;
    overflow: hidden;
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.review-date,
.review-where {
    margin: 0;
    color: var(--morph-muted, #6c757d);
    font-size: 0.75rem;
    white-space: nowrap;
}

/* What a formatting change did ("Font: Bold, Italic"), which can run to several lines. */
.review-detail {
    margin: 0;
    font-size: 0.8125rem;
    overflow-wrap: anywhere;
}

.review-tools {
    display: none;
    gap: 0.1rem;
    margin-left: auto;
}

/* A comment's own tools stay out of the way until its card is the one in hand. */
.review-card:hover .review-tools,
.review-card:focus-within .review-tools,
.review-active .review-tools {
    display: inline-flex;
}

.review-tool {
    padding: 0 0.3rem;
    border: 0;
    border-radius: 3px;
    background: none;
    color: var(--morph-primary, #2b579a);
    font: inherit;
    font-size: 0.75rem;
    cursor: pointer;
}

.review-tool:hover:not(:disabled) {
    text-decoration: underline;
}

.review-body,
.review-quote {
    margin: 0;
    overflow-wrap: anywhere;
}

.review-comment-text {
    white-space: pre-line;
}

.review-quote {
    padding-left: 0.5rem;
    border-left: 2px solid var(--morph-comment-accent, #d9a400);
    color: var(--morph-muted, #6c757d);
    font-size: 0.8rem;
}

.review-kind {
    margin-right: 0.3rem;
    font-weight: 600;
}

.review-change[data-kind="Insertion"] .review-text,
.review-change[data-kind="RowInsertion"] .review-text,
.review-change[data-kind="CellInsertion"] .review-text {
    color: var(--morph-change-accent, #d13438);
    text-decoration: underline;
}

.review-change[data-kind="Deletion"] .review-text,
.review-change[data-kind="RowDeletion"] .review-text,
.review-change[data-kind="CellDeletion"] .review-text {
    color: var(--morph-change-accent, #d13438);
    text-decoration: line-through;
}

.review-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.review-draft {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    cursor: default;
}

.review-input {
    width: 100%;
    min-height: 3.5rem;
    box-sizing: border-box;
    resize: vertical;
}

/* Presentation mode: the current page alone on black, fitted to the screen. */
.viewer[data-presenting] {
    border: 0;
    border-radius: 0;
    background: #000000;
}

/* The stand-in for fullscreen where the browser has none (an iPhone) or refuses it (an embedded frame).
   !important because the host sizes the viewer itself (80vh is only a default) and its rule would
   otherwise keep the overlay at that size. */
.viewer[data-presenting="overlay"] {
    position: fixed !important;
    inset: 0 !important;
    z-index: 2147483000;
    width: auto !important;
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    margin: 0 !important;
}

.viewer[data-presenting] .viewer-toolbar,
.viewer[data-presenting] .viewer-findbar,
.viewer[data-presenting] .editor-ribbon,
.viewer[data-presenting] .editor-status,
.viewer[data-presenting] .edit-layer,
.viewer[data-presenting] .viewer-sidebar,
.viewer[data-presenting] .viewer-review,
.viewer[data-presenting] > .error {
    display: none;
}

.viewer[data-presenting] .viewer-pages {
    justify-content: center;
    padding: 0;
    overflow: hidden;
    background: #000000;
    scrollbar-gutter: auto;
}

.viewer[data-presenting] .viewer-page {
    display: none;
    margin: auto;
    box-shadow: none;
}

.viewer[data-presenting] .viewer-page[data-current] {
    display: block;
}

/* A click advances the presentation, so it must not start a text selection. */
.viewer[data-presenting] .text-layer {
    pointer-events: none;
}

/* Printing: the pages .NET rendered for the purpose, alone. */
.print-container {
    display: none;
}

@media print {
    html[data-morph-printing] body > :not(.print-container) {
        display: none !important;
    }

    html[data-morph-printing],
    html[data-morph-printing] body {
        margin: 0 !important;
        padding: 0 !important;
        background: #ffffff !important;
    }

    html[data-morph-printing] .print-container {
        display: block;
    }

    .print-page {
        display: flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        break-after: page;
        break-inside: avoid;
    }

    .print-page:last-child {
        break-after: auto;
    }

    .print-page img {
        display: block;
        max-width: 100%;
        max-height: 100%;
    }

    .print-page > svg {
        display: block;
        width: 100%;
        height: 100%;
    }
}

@media (max-width: 640px) {
    .viewer-title,
    .viewer-divider,
    .editor-name,
    .editor-status-note {
        display: none;
    }


    /* A phone's toolbar: the side buttons share the first row, navigation and zoom take the next, wrapping
       rather than pushing a button out of the viewer's box. */
    .viewer-group-start,
    .viewer-group-end {
        flex: 1 1 auto;
    }

    .viewer-group-middle {
        order: 3;
        flex: 1 0 100%;
        flex-wrap: wrap;
        justify-content: center;
    }

    .viewer-page-input {
        width: 2.75rem;
    }

    .viewer-zoom {
        max-width: 7.5rem;
    }

    /* On a phone the sidebar overlays the pages rather than squeezing them. */
    .viewer-sidebar {
        position: absolute;
        inset: 0 auto 0 0;
        z-index: 4;
        box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2);
    }

    /* So does the review pane, from the other side. */
    .viewer-review {
        position: absolute;
        inset: 0 0 0 auto;
        z-index: 4;
        width: min(22rem, 88%);
        box-shadow: -2px 0 8px rgba(0, 0, 0, 0.2);
    }
}

@media (max-width: 768px) {
    .convert-panel {
        flex-direction: column;
        align-items: stretch;
    }

    .convert-btn {
        width: 100%;
    }

    /* Two sample buttons fit a phone row and the third wraps alone, which reads as a mistake. Stack
       them one per row instead — the labels then never wrap either. Stacking turns the row's flex-basis
       into a *height*, so the buttons also have to drop back to their natural size. */
    .sample-row {
        flex-direction: column;
    }

    .sample-row .sample-btn {
        flex: none;
    }
}

/* Replace, under find, in the editor. */
.viewer-replace {
    display: flex;
    flex: 1 0 100%;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
}

.viewer-text-button {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    height: 2rem;
    padding: 0 0.6rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.viewer-text-button:disabled {
    opacity: 0.45;
    cursor: default;
}

/*
    The editor (MorphEditor): the viewer's pages under a ribbon of tabs, as in Word, and a status bar
    under them. The ribbon's own menus open within it; a backdrop under the ribbon catches the press
    that closes one, and the File menu and the dialogs stand over everything.
*/
.viewer.editor {
    height: 85vh;
}

.editor-ribbon {
    position: relative;
    z-index: 6;
    background: var(--morph-surface, #ffffff);
    border-bottom: 1px solid var(--morph-border, #dee2e6);
}

/* Word's title band: the tabs stand on it, the chosen one open onto the ribbon under it, with the file's
   name and Save beside them. */
.editor-titlebar {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    padding: 0.3rem 0.5rem 0;
    background: var(--morph-band, color-mix(in srgb, var(--morph-primary, #2b579a) 88%, black));
    color: var(--morph-on-band, #ffffff);
}

.editor-tabs,
.editor-tablist {
    display: flex;
    flex: none;
    align-items: flex-end;
    gap: 0.1rem;
}

.editor-file,
.editor-tab {
    padding: 0.4rem 0.8rem 0.45rem;
    border: none;
    border-radius: 4px 4px 0 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.editor-file {
    font-weight: 600;
}

.editor-file:hover:not(:disabled),
.editor-tab:hover:not(:disabled, [aria-selected="true"]) {
    background: rgb(255 255 255 / 0.15);
}

.editor-tab[aria-selected="true"] {
    background: var(--morph-surface, #ffffff);
    color: var(--morph-primary, #2b579a);
    font-weight: 600;
}

.editor-tab:disabled {
    opacity: 0.6;
    cursor: default;
}

.editor-file:focus-visible,
.editor-tab:focus-visible {
    outline: 2px solid var(--morph-on-band, #ffffff);
    outline-offset: -3px;
}

.editor-tool:focus-visible,
.editor-fold:focus-visible,
.editor-gallery-item:focus-visible,
.editor-dropdown:focus-visible,
.editor-menu-item:focus-visible,
.editor-grid-cell:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -2px;
}

.editor-name {
    flex: 1;
    align-self: center;
    min-width: 0;
    overflow: hidden;
    font-size: 0.85rem;
    font-weight: 600;
    text-align: center;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-dirty {
    font-weight: 400;
    opacity: 0.8;
}

.editor-quick {
    display: flex;
    flex: none;
    align-self: center;
    gap: 0.15rem;
    padding-bottom: 0.2rem;
}

.editor-quick .viewer-button {
    color: inherit;
}

.editor-quick .viewer-button:hover:not(:disabled) {
    border-color: transparent;
    background: rgb(255 255 255 / 0.15);
}

.editor-quick .viewer-button:focus-visible {
    outline-color: var(--morph-on-band, #ffffff);
}

/* The ribbon: groups of commands, each as tall as two rows of buttons, its name under it as in Word
   (the name is its aria-label, drawn by the sheet). */
.editor-tools {
    --ribbon-row: 2rem;
    --ribbon-gap: 0.2rem;
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.25rem 0;
    padding: 0.3rem 0.25rem 0.15rem;
}

.editor-group {
    position: relative;
    display: flex;
    flex: none;
    align-items: center;
    gap: 0.2rem;
    min-height: calc(var(--ribbon-row) * 2 + var(--ribbon-gap) + 1.1rem);
    padding: 0 0.5rem 1.1rem;
    border-right: 1px solid var(--morph-border, #dee2e6);
}

/* Under the group, and out of its flow, so that a name never widens its group. */
.editor-group::after {
    content: attr(aria-label);
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    color: var(--morph-muted, #6c757d);
    font-size: 0.7rem;
    line-height: 1rem;
    text-align: center;
    white-space: nowrap;
    pointer-events: none;
}

.editor-group:last-child {
    border-right: none;
}

/* What a group holds, in a row; in a folded group, what its button opens under it. */
.editor-group-body {
    display: flex;
    align-items: center;
    gap: 0.2rem;
}

/* A group the ribbon has no room for is folded into one button with its name (foldRibbon in
   morph-viewer.js), as Word's ribbon folds one; pressed, the group opens whole under it. The button looks
   as a large command does, but is not one. */
.editor-fold {
    position: relative;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    height: calc(var(--ribbon-row) * 2 + var(--ribbon-gap));
    min-width: 3.25rem;
    max-width: 6.5rem;
    padding: 0.2rem 0.4rem;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    line-height: 1.1;
    text-align: center;
    cursor: pointer;
}

.editor-fold:hover {
    border-color: var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
}

.editor-fold svg {
    flex: none;
    width: 1.6rem;
    height: 1.6rem;
}

.editor-fold svg.editor-caret {
    width: 0.75rem;
    height: 0.75rem;
    margin-top: -0.1rem;
}

.editor-group[data-fold="folded"] > .editor-fold {
    display: inline-flex;
}

.editor-group[data-fold="folded"] > .editor-group-body,
.editor-group[data-fold="folded"]::after {
    display: none;
}

.editor-group[data-fold="folded"][data-open] > .editor-fold {
    border-color: var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
}

.editor-group[data-fold="folded"][data-open] > .editor-group-body {
    position: absolute;
    top: calc(100% + 2px);
    left: 0;
    z-index: 9;
    display: flex;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 6px;
    background: var(--morph-surface, #ffffff);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}

/* A group that can first get smaller (data-squeeze): the style gallery shows two columns of styles, and
   the small buttons beside a large one only their icons, keeping their tooltips (the name is still the
   button's, at no size). */
.editor-group[data-squeeze][data-fold="squeezed"] .editor-gallery {
    grid-template-columns: repeat(2, 6.25rem);
}

.editor-group[data-squeeze][data-fold="squeezed"] .editor-gallery-item:nth-child(n + 5) {
    display: none;
}

.editor-group[data-squeeze][data-fold="squeezed"] .editor-stack .editor-tool {
    gap: 0;
    padding: 0 0.45rem;
    font-size: 0;
}

/* Two rows of small buttons, as the Font and Paragraph groups are. */
.editor-rows {
    display: flex;
    flex-direction: column;
    gap: var(--ribbon-gap);
}

.editor-row {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    min-height: var(--ribbon-row);
}

/* Small labelled buttons one over another, beside a group's large one. */
.editor-stack {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    gap: var(--ribbon-gap);
    min-height: calc(var(--ribbon-row) * 2 + var(--ribbon-gap));
}

.editor-stack-three {
    --ribbon-row: 1.4rem;
    gap: 0.1rem;
}

.editor-stack-three .editor-tool,
.editor-stack-three .editor-size-field {
    height: 1.4rem;
}

/* A group's main command: its icon large, its name under it. */
.editor-tool.editor-large {
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    height: calc(var(--ribbon-row) * 2 + var(--ribbon-gap));
    min-width: 3.25rem;
    max-width: 6.5rem;
    padding: 0.2rem 0.4rem;
    line-height: 1.1;
    text-align: center;
    white-space: normal;
}

.editor-tool.editor-large svg {
    width: 1.6rem;
    height: 1.6rem;
}

.editor-tool.editor-large svg.editor-caret {
    width: 0.75rem;
    height: 0.75rem;
    margin-top: -0.1rem;
}

.editor-tool.editor-large .editor-badge {
    position: absolute;
    top: 0.15rem;
    right: 0.15rem;
}

/* Word's style gallery: tiles drawn as the styles' text is, two rows of them; the arrows beside it page
   through, and the last opens the whole list. A tile is paper, white with black automatic text, under
   any theme: it shows the style as the page will, which stays white too. */
.editor-gallery {
    display: grid;
    grid-template-columns: repeat(4, 6.25rem);
    grid-auto-rows: var(--ribbon-row);
    gap: var(--ribbon-gap);
    padding: 1px;
}

.editor-gallery-item {
    display: flex;
    align-items: center;
    min-width: 0;
    padding: 0 0.5rem;
    overflow: hidden;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: #ffffff;
    color: #000000;
    font-family: inherit;
    line-height: 1;
    text-align: left;
    cursor: pointer;
}

/* The name clips for its ellipsis, so its own line has to hold the descenders: at the tile's line
   height of 1 the box was one em tall and cut the tail off the g of "No Spacing". */
.editor-gallery-name {
    overflow: hidden;
    line-height: 1.3;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-gallery-item:hover:not(:disabled) {
    border-color: var(--morph-primary, #2b579a);
}

.editor-gallery-item[aria-selected="true"] {
    border-color: var(--morph-primary, #2b579a);
    box-shadow: inset 0 0 0 1px var(--morph-primary, #2b579a);
    background: color-mix(in srgb, var(--morph-primary, #2b579a) 12%, #ffffff);
}

.editor-gallery-item:disabled {
    opacity: 0.45;
    cursor: default;
}

.editor-gallery-arrows {
    flex-direction: column;
    align-self: stretch;
    justify-content: flex-start;
}

.editor-gallery-arrows > .viewer-button {
    width: 1.25rem;
    height: calc((var(--ribbon-row) * 2 + var(--ribbon-gap)) / 3);
    border-color: var(--morph-border, #dee2e6);
    border-radius: 0;
}

.editor-gallery-arrows > .viewer-button svg {
    width: 0.8rem;
    height: 0.8rem;
}

.editor-anchor.editor-gallery-arrows > .editor-menu {
    right: 0;
    left: auto;
}

.editor-tool {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    height: 2rem;
    padding: 0 0.55rem;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    white-space: nowrap;
    cursor: pointer;
}

.editor-tool:hover:not(:disabled),
.editor-tool[aria-pressed="true"] {
    border-color: var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
}

.editor-tool[aria-pressed="true"] {
    color: var(--morph-primary, #2b579a);
}

.editor-tool:disabled,
.editor-tool-disabled,
.editor-tool[data-unselected] {
    opacity: 0.4;
    cursor: default;
}

/* Cut and Copy at a caret, marked by the script (markClipboard in morph-viewer.js). */
.editor-tool-disabled,
.editor-tool[data-unselected],
.editor-menu-item[data-unselected] {
    pointer-events: none;
}

.editor-menu-item[data-unselected] {
    color: var(--morph-muted, #6c757d);
    opacity: 0.55;
}

.editor-tool svg,
.editor-menu-item svg,
.viewer-text-button svg,
.editor-start-new svg,
.editor-dropdown svg {
    flex: none;
    width: 1.1rem;
    height: 1.1rem;
}

.editor-tool svg.editor-caret,
.editor-dropdown svg {
    width: 0.85rem;
    height: 0.85rem;
}

.editor-badge {
    position: static;
    margin-left: 0.15rem;
}

.editor-dropdown {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    min-width: 9.5rem;
    height: 2rem;
    padding: 0 0.5rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.editor-dropdown:disabled {
    opacity: 0.45;
    cursor: default;
}

/* The font and the size the caret is in, kept current by the script (data-edit-show): boxes a name or a
   size is typed into, each joined to the arrow that opens its list. */
.editor-combo {
    display: inline-flex;
    align-items: stretch;
}

.editor-combo-input {
    height: 2rem;
    padding: 0 0.5rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-right: none;
    border-radius: 4px 0 0 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    text-overflow: ellipsis;
}

.editor-combo-input:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -2px;
}

.editor-combo-input:disabled {
    opacity: 0.45;
}

.editor-combo .editor-dropdown {
    min-width: 0;
    padding: 0 0.3rem;
    border-radius: 0 4px 4px 0;
}

.editor-font-input {
    width: 8rem;
}

.editor-size-input {
    width: 2.75rem;
}

.editor-fonts {
    min-width: 15rem;
}

.editor-font {
    font-size: 0.95rem;
}

.editor-sizes {
    min-width: 5rem;
}

.editor-menu-note {
    max-width: 14rem;
    margin: 0.35rem 0.6rem;
    color: var(--morph-muted, #6c757d);
    font-size: 0.75rem;
    white-space: normal;
}

/* A dropdown and its menu, which opens under it rather than at the group's start. */
.editor-anchor {
    position: relative;
    display: inline-flex;
}

.editor-anchor > .editor-menu {
    left: 0;
}

/* A colour button carries the colour it applies, as a bar under its icon; its arrow opens the palette. */

.editor-swatch-button {
    flex-direction: column;
    gap: 1px;
}

.editor-swatch-button::after {
    content: "";
    width: 1rem;
    height: 3px;
    border-radius: 1px;
    background: var(--swatch);
}

.editor-swatch-button svg {
    width: 1rem;
    height: 1rem;
}

.viewer-button.editor-split-arrow {
    width: 1rem;
}

.viewer-button.editor-split-arrow svg {
    width: 0.75rem;
    height: 0.75rem;
}

.editor-palette {
    min-width: 0;
    width: max-content;
}

.editor-swatches {
    display: grid;
    grid-template-columns: repeat(5, 1.4rem);
    gap: 4px;
    padding: 0.4rem 0.6rem;
}

.editor-swatch {
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    cursor: pointer;
}

.editor-swatch:hover,
.editor-swatch:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: 1px;
}

/* A floating picture selected on a page: a frame round it, handles at its corners, its size below. */
.viewer-picture-frame {
    position: absolute;
    z-index: 3;
    box-sizing: border-box;
    border: 1px solid var(--morph-primary, #2b579a);
    pointer-events: none;
}

.viewer-picture-frame::after {
    content: attr(data-size);
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 4px;
    padding: 1px 4px;
    border-radius: 3px;
    background: var(--morph-primary, #2b579a);
    color: #ffffff;
    font-size: 11px;
    white-space: nowrap;
}

/* Coauthoring: a bar beside a paragraph someone else has open, in their colour, their name over it. */
.viewer-presence {
    position: absolute;
    z-index: 2;
    width: 3px;
    border-radius: 2px;
    background: var(--presence);
    pointer-events: none;
}

.viewer-presence::before {
    content: attr(data-name);
    position: absolute;
    bottom: 100%;
    left: 0;
    padding: 0 4px;
    border-radius: 3px 3px 3px 0;
    background: var(--presence);
    color: #ffffff;
    font: 600 11px/16px system-ui, sans-serif;
    white-space: nowrap;
}

/* The colours the people in a session are told apart by, by the index the session gives each. */
.viewer-presence-0, .wopi-user-0 { --presence: #c239b3; }
.viewer-presence-1, .wopi-user-1 { --presence: #0078d4; }
.viewer-presence-2, .wopi-user-2 { --presence: #107c10; }
.viewer-presence-3, .wopi-user-3 { --presence: #ca5010; }
.viewer-presence-4, .wopi-user-4 { --presence: #8764b8; }
.viewer-presence-5, .wopi-user-5 { --presence: #038387; }
.viewer-presence-6, .wopi-user-6 { --presence: #986f0b; }
.viewer-presence-7, .wopi-user-7 { --presence: #d13438; }

.viewer-picture-handle {
    position: absolute;
    width: 10px;
    height: 10px;
    margin: -5px;
    box-sizing: border-box;
    border: 1px solid var(--morph-primary, #2b579a);
    border-radius: 50%;
    background: #ffffff;
    pointer-events: auto;
    touch-action: none;
}

.viewer-picture-handle[data-corner="ne"] { left: 100%; top: 0; cursor: nesw-resize; }
.viewer-picture-handle[data-corner="se"] { left: 100%; top: 100%; cursor: nwse-resize; }

/* Format Painter on: the pages take a painter's cursor until text is selected on them. */
.viewer[data-painting="on"] .viewer-page,
.viewer[data-painting="on"] .viewer-page .text-layer {
    cursor: copy;
}

/* Word's Bullets and Numbering libraries: a grid of the looks, each drawn as its list's first marks. */
.editor-list-grid {
    display: grid;
    grid-template-columns: repeat(3, 4.5rem);
    gap: 6px;
    padding: 0.4rem 0.6rem;
}

.editor-list-item {
    height: 3rem;
    padding: 0 0.3rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: transparent;
    color: inherit;
    font-size: 0.85rem;
    line-height: 1.2;
    cursor: pointer;
}

.editor-list-item:hover,
.editor-list-item:focus-visible,
.editor-list-item[aria-checked="true"] {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: 1px;
}

.editor-style-name {
    max-width: 9rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0.5rem;
    z-index: 8;
    display: flex;
    flex-direction: column;
    min-width: 13rem;
    max-height: 60vh;
    overflow-y: auto;
    padding: 0.25rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 6px;
    background: var(--morph-surface, #ffffff);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}

.editor-file-menu {
    top: 2.35rem;
    left: 0.5rem;
    min-width: 16rem;
}

/* The right-click menu, where the pointer was (the style sets left and top; the script moves it in from
   the editor's edges). It does not scroll, so its submenus can stand out beside it. */
.editor-context-menu {
    max-height: none;
    overflow: visible;
    min-width: 14rem;
}

.editor-menu-item:disabled {
    color: var(--morph-muted, #6c757d);
    cursor: default;
    opacity: 0.55;
}

.editor-menu-item:disabled:hover {
    background: transparent;
}

/* A line that opens a submenu, beside it: on hover, or when pressed, which is how a touch opens it. */
.editor-menu-sub {
    position: relative;
    display: flex;
    flex-direction: column;
}

.editor-menu-sub > .editor-menu-item::after {
    content: "›";
    margin-left: auto;
    padding-left: 1rem;
    color: var(--morph-muted, #6c757d);
}

.editor-submenu {
    display: none;
    top: -0.3rem;
    left: 100%;
}

.editor-menu-sub:hover > .editor-submenu,
.editor-menu-sub[data-open] > .editor-submenu {
    display: flex;
}

.editor-context-menu[data-flip] .editor-submenu {
    left: auto;
    right: 100%;
}

.editor-menu-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    border: none;
    border-left: 3px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.875rem;
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
}

.editor-menu-item:hover,
.editor-menu [data-menu-active] {
    background: var(--morph-background, #f8f9fa);
}

/* The line the arrow keys are on (keyboard navigation in morph-viewer.js): the focus stays where it was. */
.editor-menu [data-menu-active] {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -2px;
}

.editor-menu-item[aria-checked="true"],
.editor-menu-item[aria-selected="true"] {
    border-left-color: var(--morph-primary, #2b579a);
    background: var(--morph-background, #f8f9fa);
}

.editor-menu-heading {
    padding: 0.45rem 0.6rem 0.2rem;
    color: var(--morph-muted, #6c757d);
    font-size: 0.75rem;
    font-weight: 600;
}

.editor-menu-separator {
    height: 1px;
    margin: 0.25rem 0;
    background: var(--morph-border, #dee2e6);
}

.editor-styles {
    min-width: 16rem;
}

/* Each style is drawn as its text is; on a dark theme a dark text colour would vanish, so it is let be. */
.editor-style {
    line-height: 1.3;
}

.editor-grid {
    display: grid;
    grid-template-columns: repeat(var(--columns), 1.1rem);
    gap: 3px;
    padding: 0.25rem 0.6rem 0.6rem;
}

.editor-grid-cell {
    width: 1.1rem;
    height: 1.1rem;
    padding: 0;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 2px;
    background: var(--morph-surface, #ffffff);
    cursor: pointer;
}

.editor-grid-cell[data-lit] {
    border-color: var(--morph-primary, #2b579a);
    background: color-mix(in srgb, var(--morph-primary, #2b579a) 25%, transparent);
}

.editor-backdrop {
    position: absolute;
    inset: 0;
    z-index: 5;
}

.editor-file-menu {
    z-index: 8;
}

.editor-status {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 2rem;
    padding: 0.15rem 0.75rem;
    border-top: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
    color: var(--morph-muted, #6c757d);
    font-size: 0.8rem;
    white-space: nowrap;
}

.editor-status-button {
    padding: 0.1rem 0.3rem;
    border: none;
    border-radius: 3px;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.editor-status-button:hover {
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
}

.editor-status-button[aria-pressed="true"] {
    color: var(--morph-text, #333);
    font-weight: 600;
}

.editor-status-tracking {
    color: var(--morph-change-accent, #d13438);
}

.editor-status-extend:not([data-value="true"]) {
    display: none;
}

.editor-status-note {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.editor-status-zoom {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    margin-left: auto;
}

.editor-status .viewer-button {
    width: 1.6rem;
    height: 1.6rem;
}

.editor-zoom-value {
    min-width: 3rem;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.editor-dialog-backdrop {
    position: absolute;
    inset: 0;
    z-index: 9;
    background: rgba(0, 0, 0, 0.3);
}

.editor-dialog {
    position: absolute;
    top: 18%;
    left: 50%;
    z-index: 10;
    width: min(26rem, calc(100% - 2rem));
    padding: 1rem 1.25rem;
    transform: translateX(-50%);
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 8px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}

.editor-dialog-title {
    margin: 0 0 0.75rem;
    color: var(--morph-primary, #2b579a);
    font-size: 1rem;
}

.editor-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 0.85rem;
}

.editor-input {
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
    font: inherit;
}

/* A menu item with what it means under its name: a margin preset's sizes, a paper's. */
.editor-menu-pair {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1rem;
}

.editor-menu-detail {
    color: var(--morph-muted, #6c757d);
    font-size: 0.75rem;
}

/* Word's ruler, drawn by the script over the current page: the text's width white, the margins grey,
   ticks each quarter centimetre, and the paragraph's indent markers to drag. */
.editor-ruler {
    position: relative;
    flex: none;
    height: 1.4rem;
    overflow: hidden;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
    user-select: none;
}

.ruler-strip {
    position: absolute;
    top: 0.2rem;
    bottom: 0.2rem;
    border: 1px solid var(--morph-border, #dee2e6);
    background: #ffffff;
    color: #444444;
}

.ruler-margin {
    position: absolute;
    top: 0;
    bottom: 0;
    background: #d9dde3;
}

.ruler-tick {
    position: absolute;
    top: 40%;
    width: 1px;
    height: 20%;
    background: #777777;
}

.ruler-tick-half {
    top: 30%;
    height: 40%;
}

.ruler-number {
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    font-size: 0.6rem;
    line-height: 1;
}

.ruler-marker {
    position: absolute;
    z-index: 1;
    width: 0.6rem;
    height: 0.4rem;
    margin-left: -0.3rem;
    background: #7a8699;
    cursor: ew-resize;
    touch-action: none;
}

.ruler-first {
    top: -1px;
    clip-path: polygon(0 0, 100% 0, 50% 100%);
}

.ruler-hanging,
.ruler-right {
    bottom: 0.25rem;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.ruler-left {
    bottom: -1px;
    height: 0.25rem;
}

/* A group's dialog launcher, at the foot of the group by its name, as Word's. */
.editor-launcher {
    position: absolute;
    z-index: 1;
    right: 0.15rem;
    bottom: 0.05rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    padding: 0;
    border: none;
    border-radius: 2px;
    background: transparent;
    color: var(--morph-muted, #6c757d);
    cursor: pointer;
}

.editor-launcher svg {
    width: 0.75rem;
    height: 0.75rem;
}

.editor-launcher:hover:not(:disabled) {
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
}

.editor-launcher:disabled {
    opacity: 0.4;
    cursor: default;
}

/* The Paragraph and Font dialogs: their pages, their groups of fields, and the Font dialog's preview. */
.editor-dialog-wide {
    top: 1rem;
    width: min(34rem, calc(100% - 2rem));
    max-height: calc(100% - 2rem);
    overflow-y: auto;
}

.editor-dialog-tabs {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 0.5rem;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
}

.editor-dialog-tab {
    padding: 0.35rem 0.75rem;
    border: none;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.editor-dialog-tab[aria-selected="true"] {
    border-bottom-color: var(--morph-primary, #2b579a);
    color: var(--morph-primary, #2b579a);
    font-weight: 600;
}

.editor-fieldset {
    margin: 0 0 0.6rem;
    padding: 0.4rem 0.6rem 0.6rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
}

.editor-fieldset legend {
    padding: 0 0.25rem;
    color: var(--morph-muted, #6c757d);
    font-size: 0.75rem;
    font-weight: 600;
}

.editor-field-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.4rem 0.75rem;
}

.editor-field-grid-three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-bottom: 0.6rem;
}

.editor-field-inline {
    max-width: 14rem;
}

.editor-check {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.15rem 0;
    font-size: 0.875rem;
}

.editor-effects {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.editor-font-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 4rem;
    overflow: hidden;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: #ffffff;
    color: #000000;
}

/* The Bookmark dialog's list of the document's bookmarks. */
.editor-bookmarks {
    display: flex;
    flex-direction: column;
    min-height: 6rem;
    max-height: 12rem;
    overflow-y: auto;
    margin-top: 0.5rem;
    padding: 0.25rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
}

.editor-margin-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 0.75rem;
}

/* A column's width, in centimetres, on the Table tab. */
.editor-size-field {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0 0.25rem;
}

.editor-size-field svg {
    width: 1rem;
    height: 1rem;
}

.editor-width-input {
    width: 4.5rem;
    padding: 0.25rem 0.4rem;
}

/* Layout > Paragraph: Indent and Spacing, a column each, as Word's ribbon has them. */
.editor-paragraph-boxes {
    display: grid;
    grid-template-columns: repeat(2, auto);
    align-items: center;
    gap: 0.1rem 0.6rem;
}

.editor-paragraph-boxes .editor-menu-heading {
    padding: 0;
}

.editor-paragraph-label {
    min-width: 2.6rem;
    font-size: 0.8rem;
}

.editor-paragraph-input {
    width: 4rem;
    padding: 0.15rem 0.3rem;
}

.editor-paragraph-unit {
    font-size: 0.75rem;
    color: var(--morph-muted, #6c757d);
}

/* Insert > Symbol's palette. */
.editor-symbol-grid {
    display: grid;
    grid-template-columns: repeat(10, 1.9rem);
    gap: 3px;
    padding: 0.4rem 0.6rem;
}

.editor-symbol {
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    font-size: 1rem;
    cursor: pointer;
}

.editor-symbol:hover,
.editor-symbol:focus-visible {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -1px;
}

.editor-dialog-buttons {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1rem;
}

.editor-button {
    padding: 0.4rem 1rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-text, #333);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.editor-button:disabled {
    opacity: 0.45;
    cursor: default;
}

.editor-button-primary {
    border-color: var(--morph-primary, #2b579a);
    background: var(--morph-primary, #2b579a);
    color: white;
}

.editor-button-danger {
    border-color: var(--morph-change-accent, #d13438);
    color: var(--morph-change-accent, #d13438);
}

.editor-count {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.35rem 1.5rem;
    margin: 0;
    font-size: 0.9rem;
}

.editor-count dd {
    margin: 0;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.editor-dialog-note {
    margin: 0.75rem 0 0;
    color: var(--morph-muted, #6c757d);
    font-size: 0.8rem;
}

/* A document edited and not saved, kept by the browser, offered back. */
.editor-recover {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 0.75rem;
    max-width: 34rem;
    margin: 0 0 1rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-left: 4px solid var(--morph-primary, #2b579a);
    border-radius: 6px;
    background: var(--morph-surface, #ffffff);
    text-align: left;
}

.editor-recover > svg {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--morph-primary, #2b579a);
}

.editor-recover-text {
    flex: 1 1 14rem;
    overflow-wrap: anywhere;
}

.editor-start-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
}

.editor-start-new {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1.25rem;
    border: 1px solid var(--morph-primary, #2b579a);
    border-radius: 4px;
    background: var(--morph-surface, #ffffff);
    color: var(--morph-primary, #2b579a);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}

@media print {
    .editor-ribbon,
    .editor-status {
        display: none;
    }
}

/* A phone's ribbon folds most of its groups (foldRibbon) into smaller buttons, and leaves out their names
   under them; a group opened from one wraps its rows to the screen's width. Its tabs scroll sideways,
   leaving the quick buttons room. After the rules above, which it overrides. */
@media (max-width: 640px) {
    .editor-group {
        flex: none;
        min-height: 0;
        padding: 0 0.25rem;
    }

    .editor-group::after {
        display: none;
    }

    .editor-fold {
        min-width: 2.75rem;
        max-width: 4.5rem;
        padding: 0.15rem 0.25rem;
        font-size: 0.7rem;
    }

    /* As wide as it needs, not as the narrow group it hangs from, up to the screen's width. */
    .editor-group[data-fold="folded"][data-open] > .editor-group-body {
        width: max-content;
        max-width: calc(100vw - 1rem);
        flex-wrap: wrap;
    }

    .editor-group[data-open] .editor-row {
        flex-wrap: wrap;
    }

    .editor-tabs {
        flex: 1 1 auto;
        min-width: 0;
        overflow-x: auto;
    }

    .editor-file,
    .editor-tab {
        flex: none;
        padding: 0.4rem 0.55rem;
    }
}

/* MorphWopi: a file a WOPI host opened, filling the frame the host put it in — the host's breadcrumb and
   Close in a bar over the editor, which takes the rest. */
.wopi {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    background: var(--morph-background, #f8f9fa);
    color: var(--morph-text, #333);
}

.wopi > .viewer {
    flex: 1;
    height: auto;
    min-height: 0;
    border: none;
    border-radius: 0;
}

.wopi-bar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.375rem 0.75rem;
    background: var(--morph-surface, #ffffff);
    border-bottom: 1px solid var(--morph-border, #dee2e6);
    font-size: 0.875rem;
}

.wopi-crumbs {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
    flex: 1;
}

.wopi-crumb {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

a.wopi-crumb {
    color: var(--morph-primary, #2b579a);
    text-decoration: none;
}

a.wopi-crumb:hover {
    text-decoration: underline;
}

.wopi-file {
    font-weight: 600;
}

.wopi-separator {
    color: var(--morph-muted, #6c757d);
}

.wopi-status {
    white-space: nowrap;
    color: var(--morph-muted, #6c757d);
}

/* Who else is in the document: a dot in each one's colour, and their name. */
.wopi-users {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.wopi-user {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    white-space: nowrap;
}

.wopi-user::before {
    content: "";
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    background: var(--presence);
}

.wopi-close {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.625rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 4px;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.wopi-close:hover {
    background: var(--morph-background, #f8f9fa);
}

.wopi-message {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    flex: 1;
    padding: 2rem;
    text-align: center;
}

/* ---- The editor's grid: an Excel workbook (SheetEditor) ----
   The cells are paper, white whatever the theme, as a page is; the headers, bars and tabs follow it. A
   workbook's pages stay in the editor, hidden, for printing. */

.editor-sheet > .viewer-body,
.editor-sheet > .editor-ruler {
    display: none;
}

.sheet {
    position: relative;
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    background: var(--morph-surface, #ffffff);
}

.sheet-toolbar {
    position: relative;
    z-index: 6;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
}

.sheet-select {
    height: 1.75rem;
    padding: 0 0.25rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: var(--morph-surface, #ffffff);
    color: inherit;
    font: inherit;
    font-size: 0.8125rem;
}

.sheet-font {
    width: 9rem;
}

.sheet-size {
    width: 3.75rem;
}

.sheet-number {
    width: 8.5rem;
}

.sheet-text-button {
    min-width: 1.75rem;
    justify-content: center;
    font-weight: 600;
}

.sheet-menu {
    min-width: 11rem;
}

.sheet-bar,
.sheet-findbar {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.5rem;
    border-bottom: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
}

.sheet-name-box {
    width: 6.5rem;
    height: 1.625rem;
    padding: 0 0.375rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: var(--morph-surface, #ffffff);
    color: inherit;
    font: inherit;
    font-size: 0.8125rem;
}

.sheet-fx {
    padding: 0 0.25rem;
    color: var(--morph-muted, #6c757d);
    font-style: italic;
    font-family: Georgia, serif;
}

.sheet-formula,
.sheet-find {
    flex: 1;
    min-width: 0;
    height: 1.625rem;
    padding: 0 0.375rem;
    border: 1px solid var(--morph-border, #dee2e6);
    border-radius: 3px;
    background: var(--morph-surface, #ffffff);
    color: inherit;
    font: inherit;
    font-size: 0.8125rem;
}

.sheet-find {
    flex: 0 1 20rem;
}

.sheet-formula:focus,
.sheet-name-box:focus,
.sheet-find:focus {
    outline: 2px solid var(--morph-primary, #2b579a);
    outline-offset: -1px;
}

.sheet-scroll {
    position: relative;
    /* Its own stacking context, so the sticky headers never rise over the toolbar's menus. */
    isolation: isolate;
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: #ffffff;
    color: #000000;
}

.sheet-canvas {
    display: grid;
    position: relative;
}

.sheet-corner,
.sheet-column-heads,
.sheet-row-heads {
    background: #f3f3f3;
    color: #444444;
}

.sheet-corner {
    position: sticky;
    top: 0;
    left: 0;
    z-index: 8;
    grid-area: 1 / 1;
    border-right: 1px solid #c8c8c8;
    border-bottom: 1px solid #c8c8c8;
    cursor: cell;
}

.sheet-column-heads {
    position: sticky;
    top: 0;
    z-index: 7;
    grid-area: 1 / 2;
    border-bottom: 1px solid #c8c8c8;
}

.sheet-row-heads {
    position: sticky;
    left: 0;
    z-index: 7;
    grid-area: 2 / 1;
    border-right: 1px solid #c8c8c8;
}

.sheet-head {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    font: 0.75rem/1 system-ui, -apple-system, "Segoe UI", sans-serif;
    user-select: none;
}

.sheet-column-heads .sheet-head {
    top: 0;
    height: 100%;
    border-right: 1px solid #d4d4d4;
    cursor: s-resize;
}

.sheet-row-heads .sheet-head {
    left: 0;
    width: 100%;
    border-bottom: 1px solid #d4d4d4;
    cursor: e-resize;
}

.sheet-head-on {
    background: #d9d9d9;
    color: #1e6e3e;
    font-weight: 600;
}

.sheet-head-all {
    background: #c6e0d0;
    color: #155230;
    font-weight: 600;
}

.sheet-cells {
    position: relative;
    grid-area: 2 / 2;
    overflow: hidden;
    cursor: cell;
    font-family: Aptos, Calibri, "Segoe UI", sans-serif;
}

.sheet-gridline {
    position: absolute;
    z-index: 0;
    background: #e1e1e1;
    pointer-events: none;
}

.sheet-box {
    position: absolute;
    z-index: 1;
    box-sizing: border-box;
    pointer-events: none;
}

/* A merged area hides the gridlines through it, as Excel's does. */
.sheet-merge {
    background: #ffffff;
}

.sheet-text {
    position: absolute;
    z-index: 3;
    display: flex;
    overflow: hidden;
    padding: 0 2px;
    line-height: 1.2;
    white-space: pre;
    pointer-events: none;
}

.sheet-text > span {
    overflow: hidden;
    text-overflow: clip;
}

.sheet-wrap {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.sheet-wrap > span {
    width: 100%;
}

.sheet-selection {
    position: absolute;
    z-index: 2;
    box-sizing: border-box;
    border: 1px solid #217346;
    background: rgb(33 115 70 / 0.12);
    pointer-events: none;
}

.sheet-active {
    position: absolute;
    z-index: 4;
    box-sizing: border-box;
    border: 2px solid #217346;
    pointer-events: none;
}

.sheet-marquee {
    position: absolute;
    z-index: 4;
    box-sizing: border-box;
    border: 2px dashed #217346;
    pointer-events: none;
}

.sheet-pointed {
    position: absolute;
    z-index: 4;
    box-sizing: border-box;
    border: 2px dashed #2b6cc4;
    background: rgb(43 108 196 / 0.08);
    pointer-events: none;
}

/* The keyboard's focus: invisible and empty until a cell is being edited in it. */
.sheet-input {
    position: absolute;
    z-index: 5;
    box-sizing: border-box;
    margin: 0;
    padding: 1px 2px;
    overflow: hidden;
    border: none;
    outline: none;
    background: transparent;
    color: transparent;
    caret-color: transparent;
    font-family: Aptos, Calibri, "Segoe UI", sans-serif;
    line-height: 1.2;
    resize: none;
    white-space: pre;
    opacity: 0;
    pointer-events: none;
}

.sheet-input.editing {
    min-width: 2rem;
    border: 2px solid #217346;
    background: #ffffff;
    color: #000000;
    caret-color: #000000;
    opacity: 1;
    pointer-events: auto;
    box-shadow: 0 2px 6px rgb(0 0 0 / 0.2);
}

.sheet-guide {
    position: absolute;
    z-index: 6;
    background: #217346;
    pointer-events: none;
}

.sheet-guide[data-kind="column"] {
    width: 1px;
    height: 100%;
}

.sheet-guide[data-kind="row"] {
    width: 100%;
    height: 1px;
}

.sheet-chart-note {
    padding: 2rem;
    color: #6c757d;
    text-align: center;
}

.sheet-tabs {
    display: flex;
    gap: 2px;
    overflow-x: auto;
    padding: 0 0.5rem;
    border-top: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-background, #f8f9fa);
}

.sheet-tab {
    flex: none;
    padding: 0.3rem 0.9rem;
    border: none;
    border-bottom: 3px solid transparent;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.8125rem;
    cursor: pointer;
}

.sheet-tab:hover {
    background: var(--morph-surface, #ffffff);
}

.sheet-tab[aria-selected="true"] {
    border-bottom-color: #217346;
    background: var(--morph-surface, #ffffff);
    color: #217346;
    font-weight: 600;
}

.sheet-status {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 2rem;
    padding: 0.15rem 0.75rem;
    border-top: 1px solid var(--morph-border, #dee2e6);
    background: var(--morph-surface, #ffffff);
    color: var(--morph-muted, #6c757d);
    font-size: 0.8125rem;
}

.sheet-mode {
    min-width: 3rem;
}

.sheet-note {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sheet-status .editor-status-zoom {
    margin-left: auto;
}
