        :root {
            --mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace;
            --sans: 'Inter', -apple-system, sans-serif;
        }
        /* Colors (--bg, --panel, --text, --accent, ...) come from _Layout.cshtml,
           controlled by the auto/light/dark switch in the navbar. */
        * { box-sizing: border-box; }

        /* Breakout: lifts the editor out of the Bootstrap .container from _Layout,
           so it uses the full window width instead of the container's max width. */
        #editor-root {
            position: relative;
            left: 50%; right: 50%;
            margin-left: -50vw; margin-right: -50vw;
            width: 100vw;
        }
        #app {
            display: flex; flex-direction: column;
            /* Height is set exactly to the available space between navbar and footer
               via JS (fitAppHeight); min-height is just the floor. */
            min-height: 480px;
            background: var(--bg); color: var(--text); font-family: var(--sans);
        }

        .toolbar {
            display: flex; align-items: center; gap: 18px;
            padding: 10px 16px; background: var(--panel);
            border-bottom: 1px solid var(--border); flex-shrink: 0;
        }
        .brand { font-family: var(--mono); font-size: 13px; color: var(--text-dim); letter-spacing: 0.5px; margin-right: auto; }
        .brand b { color: var(--accent); }

        .seg { display: flex; background: var(--panel-alt); border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
        .seg button {
            background: transparent; border: none; color: var(--text-dim); font-family: var(--sans);
            font-size: 12.5px; font-weight: 600; padding: 7px 13px; cursor: pointer; transition: .15s;
        }
        .seg button:not(:last-child) { border-right: 1px solid var(--border); }
        .seg button:hover { color: var(--text); }
        .seg button.active { background: var(--accent); color: var(--accent-contrast); }

        /* Shown only to a (mock-)logged-in user (see updatePdfButtonVisibility) —
           prints the preview iframe, letting the browser's print dialog save it
           as a PDF, same button in Viewer.cshtml. */
        .pdf-btn {
            display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
            background: var(--panel-alt); border: 1px solid var(--border); color: var(--text);
            border-radius: 7px; padding: 7px 13px;
            font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; transition: .15s;
        }
        .pdf-btn:hover { border-color: var(--accent); color: var(--accent); }
        .pdf-btn[hidden] { display: none; }

        /* Toggles the currently open file's favorite status — mirrors the
           file-tree row's star (see toggleFavorite) but discoverable without
           opening the Dateien panel. */
        .favorite-toggle-btn {
            display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
            width: 32px; height: 32px;
            background: var(--panel-alt); border: 1px solid var(--border); color: var(--text-dim);
            border-radius: 7px; cursor: pointer; transition: .15s;
        }
        .favorite-toggle-btn:hover { border-color: #f5a623; color: #f5a623; }
        .favorite-toggle-btn.active { color: #f5a623; border-color: #f5a623; background: rgba(245,166,35,.12); }
        .favorite-toggle-btn.active svg { fill: currentColor; }
        .favorite-toggle-btn[hidden] { display: none; }

        .open-viewer-btn {
            display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
            background: var(--accent); color: var(--accent-contrast); text-decoration: none;
            border: none; border-radius: 7px; padding: 7px 13px;
            font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; transition: opacity .15s;
        }
        .open-viewer-btn:hover { opacity: .85; color: var(--accent-contrast); }

        /* Collaborator avatars next to the view-mode switch — a Word/Google Docs
           style stack of who has access to the current (shared) file, shown only
           once it's actually shared with someone. A preview of the real-time
           collaboration this is meant to lead into later; for now it's just a
           read of the file's mock share.invited list (see ensureShare/openShareModal).
           Beyond MAX_VISIBLE_AVATARS individuals, the rest collapse into a "+N"
           bubble whose hover popover lists everyone. */
        .collab-avatars { display: flex; align-items: center; flex-shrink: 0; }
        .collab-avatars[hidden] { display: none; }
        .collab-avatar {
            width: 27px; height: 27px; border-radius: 50%; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            font-family: var(--sans); font-size: 10.5px; font-weight: 700; color: #fff;
            border: 2px solid var(--panel); margin-left: -8px; cursor: default;
        }
        .collab-avatar:first-child { margin-left: 0; }
        .collab-avatar.you { box-shadow: 0 0 0 1px var(--accent); }
        .collab-avatar-more { background: var(--panel-alt); color: var(--text-dim); cursor: pointer; }
        .collab-popover {
            position: fixed; z-index: 50; width: 230px; max-height: 280px; overflow-y: auto;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 8px; display: none;
        }
        .collab-popover[data-open] { display: block; }
        .collab-popover-person { display: flex; align-items: center; gap: 8px; padding: 5px 4px; }
        .collab-popover-person .collab-avatar { margin-left: 0; width: 24px; height: 24px; font-size: 9.5px; }
        .collab-popover-person-info { flex: 1; min-width: 0; }
        .collab-popover-person-email {
            font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        }
        .collab-popover-person-role { font-size: 11px; color: var(--text-dim); }

        /* Pixel-precise remote cursors in the plain-textarea editor (markdown/Typst/
           LaTeX) — see collab-textarea-binding.js's mirror-div measurement. Positioned
           dynamically via inline left/top/height/background; only the static look
           (label pill) lives here. Solid, not blinking — a remote caret marks where
           someone else is, not an insertion point of your own to blink at. Absent for
           CodeMirror-backed code files, which render their own equivalent via
           y-codemirror instead. */
        .collab-caret { border-radius: 1px; }
        .collab-caret-label {
            font-family: var(--sans); font-size: 10px; font-weight: 600; color: #fff;
            padding: 1px 5px; border-radius: 3px 3px 3px 0; white-space: nowrap;
        }

        /* Formatting toolbar in the editor area: ribbon sections like in Word —
           each group is two rows tall, label underneath, groups side by side. */
        .format-bar {
            display: flex; align-items: stretch; background: var(--panel);
            border-bottom: 1px solid var(--border); flex-shrink: 0;
            overflow-x: auto;
            position: sticky; top: 0; z-index: 20;
        }
        .fmt-group {
            display: flex; flex-direction: column; align-items: center; justify-content: space-between;
            gap: 4px; padding: 6px 12px; border-right: 1px solid var(--border); flex-shrink: 0;
        }
        .fmt-group[hidden] { display: none; }
        .fmt-group:last-child { border-right: none; }
        .fmt-group-controls {
            display: grid; grid-template-rows: repeat(2, auto); grid-auto-flow: column;
            grid-auto-columns: max-content; align-items: center; gap: 4px;
        }
        .fmt-group-label {
            font-family: var(--mono); font-size: 10px; color: var(--text-dim);
            text-transform: uppercase; letter-spacing: .5px;
        }
        .format-bar button, .fmt-select {
            background: var(--panel-alt); border: 1px solid var(--border); color: var(--text);
            font-family: var(--sans); font-size: 12px; padding: 5px 9px; border-radius: 5px;
            cursor: pointer; transition: .15s;
        }
        /* Icon buttons: one size, the icon centred; a glyph (Σ, Ω, H⁺) sits like an icon. */
        .fmt-group-controls > button, .fmt-group-controls .dd-toggle {
            display: inline-flex; align-items: center; justify-content: center; gap: 4px;
            min-width: 32px; height: 28px; padding: 0 8px;
        }
        .fmt-group-controls > button svg, .fmt-group-controls .dd-toggle svg { display: block; flex-shrink: 0; }
        .fmt-glyph { font-family: var(--sans); font-size: 13.5px; font-weight: 600; line-height: 1; }
        .fmt-glyph sup { font-size: 9px; font-weight: 700; vertical-align: 0.55em; margin-left: 1px; }
        .fmt-caret { font-size: 9px; opacity: .8; }
        .format-bar button:hover, .fmt-select:hover { border-color: var(--accent); color: var(--accent); }
        .fmt-select { max-width: 168px; height: 28px; padding: 0 6px; }
        #headingSelect { width: 100%; min-width: 118px; }
        /* The text group is laid out by hand: the heading select two cells wide in the top
           row with italic and list beside it, the five small buttons underneath. */
        .fmt-group-text .fmt-group-controls { grid-auto-flow: row; grid-template-columns: repeat(5, max-content); }
        .fmt-group-text #headingSelect { grid-column: 1 / span 2; grid-row: 1; }
        .fmt-group-text button[data-fmt="italic"] { grid-column: 3; grid-row: 1; }
        .fmt-group-text button[data-fmt="list"] { grid-column: 4; grid-row: 1; }
        .fmt-group-text button[data-fmt="headingUp"] { grid-column: 1; grid-row: 2; }
        .fmt-group-text button[data-fmt="headingDown"] { grid-column: 2; grid-row: 2; }
        .fmt-group-text button[data-fmt="bold"] { grid-column: 3; grid-row: 2; }
        .fmt-group-text button[data-fmt="link"] { grid-column: 4; grid-row: 2; }
        .fmt-group-text button[data-fmt="quote"] { grid-column: 5; grid-row: 2; }
        .fmt-group-text button[data-fmt="code"] { grid-column: 5; grid-row: 1; }
        /* Diagrams: the select across the top, the three block buttons equally wide underneath. */
        .fmt-group-diagrams .fmt-group-controls { grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); }
        .fmt-group-diagrams #diagramSelect { grid-column: 1 / span 3; grid-row: 1; width: 100%; min-width: 132px; }
        .fmt-group-diagrams button { grid-row: 2; min-width: 0; }
        .dd-toggle.active { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }

        .toolbar-dd { position: relative; display: inline-flex; }
        /* position:fixed instead of absolute, with the position set via JS (see positionDropdown) —
           this lets the menu escape .format-bar's overflow-x:auto clipping, which would
           otherwise blow up the whole section and create a scrollbar. */
        .dd-menu {
            position: fixed; z-index: 30;
            display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
            width: 280px; padding: 8px; background: var(--panel);
            border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28);
        }
        .dd-menu[hidden] { display: none; }
        /* Fixed width rather than width:auto + align-items:stretch — that combination
           is a circular sizing dependency (container width depends on children that
           stretch to fill the container), which is exactly the kind of thing Safari's
           layout engine has been inconsistent about for position:fixed elements. The
           working symbol menu (.dd-menu) always used a fixed width; match that here. */
        .dd-menu-list { flex-direction: column; align-items: stretch; width: 190px; }
        .dd-menu-list button {
            display: flex; align-items: center; gap: 8px; text-align: left;
            background: transparent; border: none; color: var(--text); font-family: var(--sans);
            padding: 6px 8px; border-radius: 5px; font-size: 12.5px; cursor: pointer;
        }
        .dd-menu-list button:hover { background: var(--panel-alt); border-color: transparent; }
        .dd-menu-list button svg { flex-shrink: 0; }
        /* -- "Datei erstellen" submenu: an in-place swap within the same #filesAddMenu
           panel (not a flyout) — #filesAddMenuRoot/#filesAddMenuCreate toggle their
           `hidden` state instead of each being a separate positioned dropdown, so the
           existing positionDropdown/closeAllDropdowns logic still applies unchanged. -- */
        #filesAddMenuRoot, #filesAddMenuCreate { display: flex; flex-direction: column; gap: 4px; width: 100%; }
        .dd-submenu-arrow { margin-left: auto; color: var(--text-dim); }
        .dd-submenu-back { color: var(--text-dim); border-bottom: 1px solid var(--border); border-radius: 0; padding-bottom: 8px; margin-bottom: 2px; }
        /* Groups the "Datei erstellen" list into "Dokumente" (Markdown/Typst/LaTeX,
           then the nested "Office" sub-group — Text/Tabelle/Präsentation) and
           "Programmierung" (Java/Python/C/C++) — same style as .vault-menu-label,
           shared by both the +Add dropdown (static markup) and the right-click
           context menu's submenu (showFileCreateSubmenu). */
        .dd-menu-label {
            font-family: var(--mono); font-size: 10.5px; color: var(--text-dim);
            text-transform: uppercase; letter-spacing: .5px; margin: 8px 4px 2px;
        }
        .dd-menu-label:first-child { margin-top: 2px; }
        /* "Office" nested one level under "Dokumente" — tighter top margin (it
           follows LaTeX directly, not a section break) and indented to read as a
           sub-group rather than a sibling category. */
        .dd-menu-sublabel { margin-top: 4px; margin-left: 12px; }
        .symbol-group-label {
            flex-basis: 100%; font-family: var(--mono); font-size: 10.5px; color: var(--text-dim);
            text-transform: uppercase; letter-spacing: .5px; margin: 6px 0 0;
        }
        .symbol-group-label:first-child { margin-top: 0; }
        .symbol-btn {
            background: var(--panel-alt); border: 1px solid var(--border); color: var(--text);
            font-family: var(--mono); font-size: 13px; min-width: 26px; padding: 3px 6px;
            border-radius: 5px; cursor: pointer; transition: .15s;
        }
        .symbol-btn:hover { border-color: var(--accent); color: var(--accent); }

        #undoBtn, #redoBtn { font-size: 15px; line-height: 1; }

        .work { flex: 1; display: flex; min-height: 0; }
        .pane { flex: 1; min-width: 0; display: flex; flex-direction: column; }

        /* File explorer on the left: a thin always-visible toggle column plus a
           collapsible tree body. It's a normal flex child of .work (not
           position:fixed), so it never overlaps the header/footer and naturally
           shares width with the editor/preview panes when expanded. All icons are
           inline SVG (stroke="currentColor"), matching the navbar/theme buttons —
           no emoji. */
        .files-panel { display: flex; flex-shrink: 0; border-right: 1px solid var(--border); background: var(--panel); }
        .files-backdrop { display: none; } /* only positioned/shown on mobile, see media query */

        .files-body {
            width: 260px; min-width: 0; display: flex; flex-direction: column;
            background: var(--panel); /* explicit — needed once mobile makes this position:fixed
                                          and it's no longer visually "inside" .files-panel */
        }
        .files-body[hidden] { display: none; }
        /* One of these is visible at a time; each fills the body above the vault bar and
           scrolls internally (.panel-scroll), never the panel as a whole. */
        .panel-views { flex: 1; min-height: 0; display: flex; flex-direction: column; }
        .panel-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
        .panel-view[hidden] { display: none; }
        .panel-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 6px 0; }
        /* Which document the tab is showing — the file tree makes that obvious, the other
           three tabs don't. */
        .panel-doc-name {
            flex-shrink: 0; padding: 6px 10px; border-bottom: 1px solid var(--border);
            font-size: 11.5px; color: var(--text-dim);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        }
        .panel-empty { margin: 0; padding: 18px 12px; text-align: center; font-size: 12px; color: var(--text-dim); line-height: 1.5; }
        .panel-group-label {
            padding: 10px 10px 4px; font-family: var(--mono); font-size: 10px; letter-spacing: 1px;
            text-transform: uppercase; color: var(--text-dim);
        }

        /* Compose row shared by the comments textarea and the task input. */
        .panel-compose {
            flex-shrink: 0; display: flex; flex-direction: column; gap: 6px;
            padding: 8px; border-top: 1px solid var(--border); background: var(--panel);
        }
        .panel-compose-inline { flex-direction: row; align-items: center; border-top: none; border-bottom: 1px solid var(--border); }
        /* Needed because the display:flex above outranks the UA stylesheet's [hidden] rule —
           without it, hiding the compose row for an unsaved file (loadPanelComments/
           loadPanelTasks) would have no visible effect at all. */
        .panel-compose[hidden] { display: none; }
        .panel-compose textarea, .panel-compose input[type="text"] {
            width: 100%; min-width: 0; resize: vertical;
            background: var(--panel-alt); color: var(--text); border: 1px solid var(--border);
            border-radius: 7px; padding: 6px 8px; font-family: var(--sans); font-size: 12.5px; line-height: 1.5;
        }
        .panel-compose textarea:focus, .panel-compose input[type="text"]:focus { outline: none; border-color: var(--accent); }
        .panel-compose-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
        .panel-line-toggle {
            display: flex; align-items: center; gap: 5px; min-width: 0;
            font-size: 11.5px; color: var(--text-dim); cursor: pointer; user-select: none;
        }
        .panel-line-toggle input { accent-color: var(--accent); margin: 0; }
        .panel-line-toggle span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .panel-primary-btn {
            flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; gap: 4px;
            background: var(--accent); color: var(--bg); border: none; border-radius: 7px;
            padding: 5px 10px; font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer;
        }
        .panel-compose-inline .panel-primary-btn { width: 28px; height: 28px; padding: 0; }
        .panel-primary-btn:disabled { opacity: .5; cursor: default; }

        /* -- Comments -- */
        .comment-thread { padding: 8px 10px; border-bottom: 1px solid var(--border); }
        .comment-thread.resolved { opacity: .55; }
        .comment-item + .comment-item { margin-top: 8px; }
        .comment-reply { margin-left: 12px; padding-left: 8px; border-left: 2px solid var(--border); }
        .comment-head { display: flex; align-items: baseline; gap: 6px; }
        /* Name and time read as one quiet line; the comment itself is what carries the weight —
           the same balance the Mac client strikes. */
        .comment-author { font-size: 11px; font-weight: 600; color: var(--text-dim); }
        .comment-meta { font-size: 10.5px; color: var(--text-dim); }
        .comment-text { margin: 3px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--text); white-space: pre-wrap; overflow-wrap: anywhere; }
        .comment-actions { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
        .comment-action-sep { color: var(--text-dim); font-size: 11.5px; line-height: 1; }
        .comment-action {
            background: none; border: none; padding: 0; cursor: pointer;
            font-family: var(--sans); font-size: 11px; color: var(--text-dim);
        }
        .comment-action:hover { color: var(--accent); }
        .comment-action.danger:hover { color: var(--accent-warm); }
        /* The line anchor doubles as the jump-to-line control, so it reads as a link. */
        .comment-line-link {
            display: inline-flex; align-items: center; gap: 3px; margin-top: 3px;
            background: none; border: none; padding: 0; cursor: pointer;
            font-family: var(--mono); font-size: 10.5px; color: var(--accent);
        }
        /* The "…" menu on a comment, and the two emoji popups — same wrapper, so they all
           anchor and close the same way (see editor.js's toggleCommentPopup). */
        .comment-menu-wrap { position: relative; margin-left: auto; display: flex; align-items: center; }
        .comment-menu-btn, .reaction-add, .emoji-btn {
            display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; padding: 2px; border-radius: 5px;
            color: var(--text-dim); cursor: pointer;
        }
        .comment-menu-btn:hover, .reaction-add:hover, .emoji-btn:hover { color: var(--text); background: var(--panel-alt); }
        .comment-menu {
            position: absolute; top: 100%; right: 0; z-index: 30; min-width: 130px;
            display: flex; flex-direction: column; padding: 4px;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 8px 22px rgba(0,0,0,.35);
        }
        .comment-menu[hidden] { display: none; }
        .comment-menu button {
            text-align: left; background: none; border: none; border-radius: 6px;
            padding: 6px 8px; font-family: var(--sans); font-size: 12px; color: var(--text); cursor: pointer;
        }
        .comment-menu button:hover { background: var(--panel-alt); }
        .comment-menu button.danger { color: var(--accent-warm); }

        /* Reactions: chips for what's already there, then the add button. Wraps rather than
           scrolls — a comment with many different reactions should grow, not hide them. */
        .comment-reactions { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; }
        .reaction-chip {
            display: inline-flex; align-items: center; gap: 3px;
            background: var(--panel-alt); border: 1px solid var(--border); border-radius: 999px;
            padding: 1px 7px; font-size: 11.5px; line-height: 1.6; color: var(--text-dim); cursor: pointer;
        }
        .reaction-chip:hover { border-color: var(--accent); }
        /* Own reaction stands out — that's the one a click takes back. */
        .reaction-chip.mine { border-color: var(--accent); color: var(--text); background: var(--panel); }
        /* The add button sits in the same flow as the chips, so it must not push itself right.
           position:static hands the popup's positioning context up to the row: the button
           itself drifts rightwards (and onto a second line) as chips accumulate, and a popup
           anchored to *it* would eventually open past the panel's right edge — anchored to the
           row, it always starts at the comment's left margin. */
        .comment-reactions .comment-menu-wrap { margin-left: 0; position: static; }

        /* The one shared emoji picker (see editor.js's openEmojiPicker). position:fixed and a
           child of <body>, not of the comment it was opened from — the comment list scrolls,
           and an overflow container clips absolutely-positioned children, which used to cut
           the picker in half next to a reply box. Placement comes from positionDropdown, the
           same helper the toolbar dropdowns use, hence the shared .dd-menu class. */
        .emoji-popup {
            position: fixed; z-index: 60; width: 250px;
            display: flex; flex-direction: column; gap: 6px; padding: 8px;
            background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
            box-shadow: 0 12px 30px rgba(0,0,0,.4);
        }
        .emoji-popup[hidden] { display: none; }
        .emoji-search {
            width: 100%; background: var(--panel-alt); color: var(--text);
            border: 1px solid var(--border); border-radius: 7px; padding: 5px 8px;
            font-family: var(--sans); font-size: 12.5px;
        }
        .emoji-search:focus { outline: none; border-color: var(--accent); }
        .emoji-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); padding-bottom: 6px; }
        .emoji-tabs[hidden] { display: none; }
        .emoji-tabs button {
            flex: 1; background: none; border: none; border-radius: 6px; padding: 3px 0;
            font-size: 15px; line-height: 1.3; cursor: pointer; opacity: .55;
        }
        .emoji-tabs button:hover { background: var(--panel-alt); opacity: 1; }
        .emoji-tabs button.active { background: var(--panel-alt); opacity: 1; box-shadow: inset 0 -2px 0 var(--accent); }
        /* Fixed height rather than "as tall as the category": the popup must not resize under
           the pointer as the search narrows the list down. */
        .emoji-grid {
            display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
            height: 168px; overflow-y: auto;
        }
        .emoji-grid[hidden] { display: none; }
        .emoji-grid button {
            background: none; border: none; border-radius: 5px; padding: 2px;
            font-size: 17px; line-height: 1.25; cursor: pointer;
        }
        .emoji-grid button:hover { background: var(--panel-alt); }
        .emoji-empty { margin: 0; padding: 24px 4px; text-align: center; font-size: 12px; color: var(--text-dim); }
        .emoji-empty[hidden] { display: none; }

        .panel-compose-actions { display: flex; align-items: center; gap: 6px; }
        .comment-reply-form { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; }
        /* Emoji on the left of the reply box, cancel/send on the right. */
        .comment-reply-actions .comment-menu-wrap { margin-left: 0; margin-right: auto; }
        .comment-reply-form textarea {
            width: 100%; resize: vertical; background: var(--panel-alt); color: var(--text);
            border: 1px solid var(--border); border-radius: 6px; padding: 5px 7px;
            font-family: var(--sans); font-size: 12px; line-height: 1.45;
        }
        .comment-reply-form textarea:focus { outline: none; border-color: var(--accent); }
        .comment-reply-actions { display: flex; gap: 6px; justify-content: flex-end; }

        /* -- Tasks -- */
        .task-row { display: flex; align-items: flex-start; gap: 7px; padding: 5px 10px; }
        .task-row:hover { background: var(--panel-alt); }
        .task-row input[type="checkbox"] { margin: 2px 0 0; accent-color: var(--accent); cursor: pointer; flex-shrink: 0; }
        .task-body { flex: 1; min-width: 0; }
        .task-title { font-size: 12.5px; line-height: 1.45; color: var(--text); overflow-wrap: anywhere; }
        .task-row.done .task-title { text-decoration: line-through; color: var(--text-dim); }
        .task-meta { font-size: 10.5px; color: var(--text-dim); }
        .task-delete {
            flex-shrink: 0; background: none; border: none; padding: 0; cursor: pointer;
            color: var(--text-dim); opacity: 0; transition: opacity .15s, color .15s;
        }
        .task-row:hover .task-delete { opacity: 1; }
        .task-delete:hover { color: var(--accent-warm); }

        /* "Ich mach das": an empty outline until somebody takes the task on, that person's
           profile picture afterwards. Sized and shaped like .collab-avatar so the same face
           reads the same here as in the live-collaboration row. */
        .task-assignee {
            width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%; padding: 0;
            display: flex; align-items: center; justify-content: center; overflow: hidden;
            background: transparent; border: 1px dashed var(--border);
            color: var(--text-dim); cursor: pointer;
            font-family: var(--sans); font-size: 9px; font-weight: 700;
            opacity: .45; transition: opacity .15s, border-color .15s;
        }
        .task-row:hover .task-assignee { opacity: 1; }
        .task-assignee:hover { border-color: var(--accent); color: var(--text); }
        /* Taken: solid ring, always fully visible — this is information, not a hover control. */
        .task-assignee.claimed { border-style: solid; border-color: transparent; opacity: 1; color: #fff; }
        .task-assignee.mine { box-shadow: 0 0 0 1px var(--accent); }
        .task-assignee:disabled { cursor: default; }
        .task-assignee .user-avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
        .files-head {
            display: flex; align-items: center; justify-content: space-between;
            padding: 8px 10px; border-bottom: 1px solid var(--border); flex-shrink: 0;
            font-family: var(--mono); font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px;
        }
        .files-head-actions { display: flex; align-items: center; gap: 4px; }
        .files-add-btn {
            width: 22px; height: 22px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
            background: transparent; border: 1px solid var(--border); border-radius: 6px; padding: 0;
            color: var(--text-dim); cursor: pointer; transition: .15s;
        }
        .files-add-btn:hover, .files-add-btn.active { color: var(--text); border-color: var(--accent); background: var(--panel-alt); }
        .files-tree { flex: 1; overflow-y: auto; padding: 6px 0; }
        .files-tree.drop-root { background: var(--panel-alt); }

        /* Vault switcher, anchored at the bottom edge of the file panel — a name
           button (opens the vault list/create) plus a "…" button (rename/share/
           delete the current vault). Only shown to a (mock-)logged-in user; see
           updateVaultBarVisibility. */
        .vault-bar {
            display: flex; align-items: center; gap: 2px; flex-shrink: 0;
            padding: 6px; border-top: 1px solid var(--border); background: var(--panel);
        }
        .vault-bar[hidden] { display: none; }
        .vault-bar-current {
            flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px;
            background: transparent; border: none; color: var(--text); font-family: var(--sans);
            font-size: 12.5px; font-weight: 600; padding: 5px 6px; border-radius: 6px; cursor: pointer;
        }
        .vault-bar-current:hover { background: var(--panel-alt); }
        .vault-bar-current .vault-icon { flex-shrink: 0; display: flex; color: var(--text-dim); }
        .vault-bar-current span:not(.vault-icon) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
        .vault-bar-current svg:last-child { flex-shrink: 0; color: var(--text-dim); }
        .vault-bar-more {
            flex-shrink: 0; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; color: var(--text-dim); cursor: pointer; border-radius: 5px;
        }
        .vault-bar-more:hover { background: var(--panel-alt); color: var(--text); }

        .vault-menu {
            position: fixed; z-index: 50; width: 220px; max-height: 320px; overflow-y: auto;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 6px; display: none;
        }
        .vault-menu[data-open] { display: block; }
        .vault-menu-label {
            font-family: var(--mono); font-size: 10.5px; color: var(--text-dim);
            text-transform: uppercase; letter-spacing: .5px; margin: 8px 6px 4px;
        }
        .vault-menu-label:first-child { margin-top: 2px; }
        .vault-item {
            display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
            background: transparent; border: none; color: var(--text); font-family: var(--sans);
            padding: 6px 8px; border-radius: 6px; font-size: 12.5px; cursor: pointer;
        }
        .vault-item:hover { background: var(--panel-alt); }
        .vault-item.active { background: var(--accent); color: var(--accent-contrast); }
        .vault-item svg { flex-shrink: 0; }
        .vault-item span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .vault-menu-sep { height: 1px; background: var(--border); margin: 6px 2px; }
        .vault-menu-create {
            display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
            background: transparent; border: none; color: var(--accent); font-family: var(--sans);
            padding: 6px 8px; border-radius: 6px; font-size: 12.5px; font-weight: 600; cursor: pointer;
        }
        .vault-menu-create:hover { background: var(--panel-alt); }
        .file-row {
            display: flex; align-items: center; gap: 5px; padding: 4px 6px;
            cursor: grab; border-radius: 5px; margin: 0 4px; font-size: 12.5px; color: var(--text);
        }
        .file-row:hover { background: var(--panel-alt); }
        .file-row.active { background: var(--accent); color: var(--accent-contrast); }
        .file-row.dragging { opacity: .4; }
        .file-row.drop-into { background: var(--accent); color: var(--accent-contrast); outline: 2px solid var(--accent); outline-offset: -2px; }
        .file-row.drop-before { box-shadow: inset 0 2px 0 0 var(--accent); }
        .file-row.drop-after { box-shadow: inset 0 -2px 0 0 var(--accent); }
        .file-row .file-chevron {
            width: 12px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
            color: var(--text-dim); transition: transform .15s;
        }
        .file-row .file-chevron.open { transform: rotate(90deg); }
        .file-row.active .file-chevron { color: var(--accent-contrast); }
        .file-row .file-icon { flex-shrink: 0; display: flex; }
        .file-row .file-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .file-row .file-share { flex-shrink: 0; display: flex; opacity: .8; cursor: pointer; border-radius: 4px; }
        .file-row .file-share:hover { opacity: 1; background: rgba(127,127,127,.25); }
        /* Same color token as the "Öffentlich" badges on Browse/the homepage
           (.browse-badge-public/.badge-public) — a public-link file gets a
           visually distinct (warm) icon color instead of the plain share icon's
           inherited text color, so it reads as "public" at a glance in the tree. */
        .file-row .file-share.file-share-public { color: var(--accent-warm); opacity: 1; }
        .file-row .file-favorite { flex-shrink: 0; display: flex; align-items: center; justify-content: center; opacity: .6; cursor: pointer; border-radius: 4px; color: var(--text-dim); padding: 2px; }
        .file-row .file-favorite:hover { opacity: 1; background: rgba(127,127,127,.25); color: var(--text); }
        .file-row .file-favorite.active { opacity: 1; color: #f5a623; }
        .file-row .file-favorite.active:hover { color: #f5a623; background: rgba(245,166,35,.18); }
        .file-row .file-more {
            flex-shrink: 0; visibility: hidden; display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; color: inherit;
            cursor: pointer; padding: 2px; border-radius: 4px;
        }
        .file-row:hover .file-more, .file-row.menu-open .file-more { visibility: visible; }
        /* No hover on a touch screen: the ⋯ is always there, or the menu could not be reached. */
        @media (hover: none) { .file-row .file-more { visibility: visible; opacity: .55; } }
        .file-row .file-more:hover { background: rgba(127,127,127,.25); }

        .file-menu {
            position: fixed; z-index: 50; min-width: 170px; display: none;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 6px;
        }
        .file-menu[data-open] { display: block; }
        .file-menu button {
            display: block; width: 100%; text-align: left; background: transparent; border: none; color: var(--text);
            padding: 6px 8px; border-radius: 5px; font-size: 12.5px; cursor: pointer;
        }
        .file-menu button:hover { background: var(--panel-alt); }
        .file-menu button.danger { color: #d9534f; }
        .file-menu .file-menu-sep { height: 1px; background: var(--border); margin: 4px 2px; }
        /* -- "Datei erstellen" submenu (see showFileCreateSubmenu): fileMenu's content
           is swapped in place rather than opening a second flyout — .file-menu-create
           shows a trailing chevron, .file-menu-back is the row that swaps back. -- */
        .file-menu button.file-menu-create { display: flex; align-items: center; gap: 8px; }
        .file-menu button.file-menu-create > span:nth-child(2) { flex: 1; }
        .file-menu button.file-menu-item { display: flex; align-items: center; gap: 8px; }
        .file-menu-icon { display: inline-flex; width: 14px; height: 14px; align-items: center; justify-content: center; color: var(--text-dim); flex-shrink: 0; }
        .file-menu button.danger .file-menu-icon { color: inherit; }
        .file-menu-arrow { color: var(--text-dim); }
        .file-menu button.file-menu-back { color: var(--text-dim); border-bottom: 1px solid var(--border); border-radius: 0; padding-bottom: 8px; margin-bottom: 2px; }

        /* Editor right-click menu: a compact grid of icon-only buttons (formatting a
           selection, or inserting at the cursor if nothing's selected) — deliberately
           small, unlike .file-menu's full-width labeled rows, since it needs to stay
           out of the way of whatever text it was opened next to. */
        .editor-ctx-menu {
            position: fixed; z-index: 50; display: none; flex-wrap: wrap; gap: 2px;
            width: 132px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 4px;
        }
        .editor-ctx-menu[data-open] { display: flex; }
        .editor-ctx-menu button {
            width: 28px; height: 28px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; border-radius: 5px; color: var(--text);
            font-size: 15px; font-family: var(--sans); cursor: pointer;
        }
        .editor-ctx-menu button[hidden] { display: none; }
        .editor-ctx-menu button:hover { background: var(--panel-alt); color: var(--accent); }
        /* flex-basis:100% forces this onto its own row, wrapping whatever comes next
           — a plain divider line between groups, no label. */
        .editor-ctx-menu-sep { flex-basis: 100%; height: 1px; background: var(--border); margin: 2px 0; }

        /* Share-settings modal: mock public link + email invites with a role per
           person. There's no real backend behind any of this (no auth, no server-side
           sharing), same as the Login page — the public link is a stable but
           non-resolving URL, and invites just live in the file's own localStorage node. */
        .share-backdrop {
            position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,.45);
            display: flex; align-items: center; justify-content: center; padding: 16px;
        }
        .share-backdrop[hidden] { display: none; }
        .share-modal {
            width: 420px; max-width: 100%; max-height: calc(100vh - 64px); overflow-y: auto;
            background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
            box-shadow: 0 20px 60px rgba(0,0,0,.4); padding: 20px;
        }
        .share-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
        .share-modal-head h3 { margin: 0; font-size: 16px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .share-modal-sub { font-size: 12px; color: var(--text-dim); margin: 4px 0 0; }
        .share-modal-close {
            width: 26px; height: 26px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; color: var(--text-dim); cursor: pointer; border-radius: 6px;
        }
        .share-modal-close:hover { background: var(--panel-alt); color: var(--text); }
        .share-section { padding: 14px 0; border-top: 1px solid var(--border); }
        .share-section:first-of-type { border-top: none; padding-top: 12px; }
        .share-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
        .share-row-title { font-size: 13px; color: var(--text); font-weight: 600; }
        .share-row-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
        .share-switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
        .share-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
        .share-switch-track {
            position: absolute; inset: 0; background: var(--border); border-radius: 999px; cursor: pointer; transition: .15s;
        }
        .share-switch-track::before {
            content: ''; position: absolute; width: 14px; height: 14px; left: 3px; top: 3px;
            background: var(--panel); border-radius: 50%; transition: .15s;
        }
        .share-switch input:checked + .share-switch-track { background: var(--accent); }
        .share-switch input:checked + .share-switch-track::before { transform: translateX(16px); }
        .share-link-row { display: flex; gap: 6px; margin-top: 10px; }
        .share-link-row input {
            flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text-dim); font-family: var(--mono); font-size: 11.5px;
        }
        .share-link-row.disabled input { opacity: .5; }
        .share-link-row select {
            padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12px; font-family: var(--sans); flex-shrink: 0;
        }
        .share-link-row.disabled select { opacity: .5; }
        .share-link-row button {
            padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel-alt);
            color: var(--text); font-size: 12px; cursor: pointer; white-space: nowrap; font-family: var(--sans);
        }
        .share-link-row button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
        .share-link-row button:disabled { opacity: .5; cursor: not-allowed; }
        .share-link-email-row.disabled { opacity: .5; pointer-events: none; }
        .share-listed-row {
            display: flex; align-items: flex-start; gap: 8px; margin-top: 10px; cursor: pointer;
            font-size: 12px; color: var(--text-dim);
        }
        .share-listed-row input { margin-top: 2px; flex-shrink: 0; width: 16px; height: 16px; cursor: pointer; accent-color: var(--accent); }
        .share-listed-row.disabled { opacity: .5; pointer-events: none; }
        .share-link-password-row { display: flex; gap: 6px; margin-top: 10px; }
        .share-link-password-row input {
            flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12.5px; font-family: var(--sans);
        }
        .share-link-password-row button {
            padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel-alt);
            color: var(--text); font-size: 12px; cursor: pointer; white-space: nowrap; font-family: var(--sans);
        }
        .share-link-password-row button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
        .share-link-password-row button:disabled { opacity: .5; cursor: not-allowed; }
        .share-link-password-row.disabled { opacity: .5; pointer-events: none; }
        .share-link-password-status { color: var(--accent); font-size: 11.5px; margin: 6px 0 0; }
        .share-invite-row { display: flex; gap: 6px; margin-top: 10px; }
        .share-invite-row input[type="email"], .share-invite-row input[type="text"] {
            flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12.5px; font-family: var(--sans);
        }
        .share-invite-message { margin: 6px 0 0; font-size: 11.5px; color: #c0392b; }
        #vaultSharePeopleSection.share-owner-only-hidden { display: none; }
        .share-invite-row select {
            padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12px; font-family: var(--sans);
        }
        .share-invite-row button {
            padding: 6px 12px; border: none; border-radius: 6px; background: var(--accent);
            color: var(--accent-contrast); font-size: 12px; font-weight: 600; cursor: pointer; font-family: var(--sans);
        }
        .share-category-input {
            width: 100%; margin-top: 8px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12.5px; font-family: var(--sans); box-sizing: border-box;
        }
        .share-people { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
        .share-person { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
        .share-person .share-person-email { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
        .share-person select {
            padding: 4px 6px; border: 1px solid var(--border); border-radius: 5px;
            background: var(--panel-alt); color: var(--text-dim); font-size: 11.5px; font-family: var(--sans);
        }
        .share-person .share-person-remove {
            width: 22px; height: 22px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
            background: transparent; border: none; color: var(--text-dim); cursor: pointer; border-radius: 5px;
        }
        .share-person .share-person-remove:hover { background: var(--panel-alt); color: #d9534f; }

        .version-history-list, .trash-list { display: flex; flex-direction: column; gap: 6px; max-height: 360px; overflow-y: auto; }
        .version-history-row, .trash-row {
            display: flex; align-items: center; justify-content: space-between; gap: 10px;
            padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel-alt);
        }
        .version-history-info, .trash-info { min-width: 0; flex: 1; }
        .version-history-title, .trash-title { font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .version-history-sub, .trash-sub { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
        .version-history-badge {
            display: inline-block; margin-top: 4px; padding: 2px 7px; border-radius: 999px;
            background: var(--panel); color: var(--text-dim); font-size: 10.5px;
        }
        .version-history-row button, .trash-row button {
            flex-shrink: 0; padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel); color: var(--text); font-size: 11.5px; font-family: var(--sans); cursor: pointer;
        }
        .version-history-row button:hover, .trash-row button:hover { background: var(--panel-alt); }
        /* Same rows in the side panel, where 260px minus the rail leaves no room for
           "Version 7 — Name" and a restore button side by side: let the button wrap onto
           its own line instead of squeezing the title down to an ellipsis. */
        .panel-scroll .version-history-row { flex-wrap: wrap; margin: 0 8px 6px; }
        /* flex-wrap alone changes nothing here — the info block would just shrink to fit
           next to the button. Claiming the full line is what actually pushes the button
           onto its own row. */
        .panel-scroll .version-history-info { flex-basis: 100%; }
        .panel-scroll .version-history-row button { margin-left: auto; }
        .trash-row-actions { display: flex; gap: 6px; flex-shrink: 0; }
        .trash-row-actions .trash-delete-forever { color: #d9534f; border-color: #d9534f; }
        .trash-empty-message { font-size: 12.5px; color: var(--text-dim); text-align: center; padding: 20px 0; }

        .pane-head {
            font-family: var(--mono); font-size: 11px; color: var(--text-dim);
            padding: 6px 14px; border-bottom: 1px solid var(--border); background: var(--panel);
            text-transform: uppercase; letter-spacing: 1px; flex-shrink: 0;
        }
        .divider {
            width: 6px; background: var(--border); cursor: col-resize; flex-shrink: 0;
            position: relative; transition: background .15s;
        }
        .divider:hover, .divider.dragging { background: var(--accent); }
        .divider::after {
            content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
            width: 2px; height: 28px; background: var(--text-dim); border-radius: 2px;
        }

        /* Holds the line-number gutter and the textarea side by side. CodeMirror replaces the
           textarea in place for code files (fromTextArea), so its own element ends up in here
           too — hence flex:1 on both children rather than a fixed layout. */
        .editor-surface { flex: 1; min-height: 0; display: flex; position: relative; }
        /* The textarea steps aside for a .whiteboard file (see whiteboard.css / mountWhiteboard). */
        .editor-surface[hidden] { display: none; }
        .whiteboard-host { flex: 1; min-height: 0; display: flex; flex-direction: column; }
        .whiteboard-host[hidden] { display: none; }
        .editor-gutter {
            flex-shrink: 0; overflow: hidden; position: relative; user-select: none;
            /* Exactly as wide as its largest number: 1ch is a digit's width in this monospace
               font, and --gutter-digits is set from JS. */
            width: calc(var(--gutter-digits, 2) * 1ch + 20px);
            padding: 16px 8px 16px 12px; text-align: right;
            background: var(--panel-alt); border-right: 1px solid var(--border);
            font-family: var(--mono); font-size: 13.5px; line-height: 1.6; color: var(--text-dim);
        }
        .editor-gutter[hidden] { display: none; }
        /* Moved as one piece to follow the textarea's scrolling — the numbers are positioned
           absolutely inside it, at the offsets the text actually has (see updateLineNumbers,
           which measures wrapped lines rather than assuming one row each). */
        .editor-gutter-inner { position: absolute; top: 16px; right: 8px; left: 12px; will-change: transform; }
        .editor-gutter-line { position: absolute; right: 0; }

        textarea#src {
            flex: 1; min-width: 0; resize: none; border: none; outline: none; padding: 16px;
            background: var(--bg); color: var(--text); font-family: var(--mono); font-size: 13.5px;
            line-height: 1.6; tab-size: 2;
        }
        @keyframes srcFlash {
            0% { box-shadow: inset 0 0 0 3px var(--accent); }
            100% { box-shadow: inset 0 0 0 0 transparent; }
        }
        textarea#src.flash { animation: srcFlash 900ms ease-out; }
        textarea#src.drop-image-target { box-shadow: inset 0 0 0 2px var(--accent); }

        /* -- Code Playground: shown instead of the format-bar for .java/.py files
           (see updateToolbarForLang). The CodeMirror instance itself replaces
           textarea#src in the DOM (CodeMirror.fromTextArea) — styled here as a
           custom theme built from the app's own CSS variables so it follows
           light/dark switching automatically, without a second hardcoded theme. -- */
        .code-toolbar {
            display: flex; align-items: center; gap: 10px; padding: 8px 14px;
            border-bottom: 1px solid var(--border); background: var(--panel-alt); flex-shrink: 0;
        }
        .code-toolbar-lang {
            font-family: var(--mono); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
            color: var(--text-dim); background: var(--panel); border: 1px solid var(--border); border-radius: 5px; padding: 3px 8px;
        }
        .code-run-btn {
            display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
            background: var(--accent); color: var(--accent-contrast); border: none; border-radius: 7px; padding: 6px 12px;
            font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; transition: opacity .15s;
        }
        .code-run-btn:hover { opacity: .85; }
        .code-toolbar-hint { font-size: 11.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        /* Piston consumes stdin as one upfront buffer, not a live interactive stream — this
           textarea lets the whole input be typed/pasted (including multiple lines, for
           several input()/scanf() calls) before clicking "Ausführen", not mid-run. Tall
           enough to show two lines (the placeholder hint wraps to two) without clipping,
           and manually resizable for longer input. */
        .code-stdin-input {
            flex: 1; min-width: 100px; max-width: 360px; height: 46px; resize: vertical; overflow: auto;
            font-family: var(--mono); font-size: 12.5px; line-height: 1.4; padding: 6px 8px;
            border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--text);
        }
        .code-stdin-input:focus { outline: none; border-color: var(--accent); }
        .code-stdin-input::placeholder { color: var(--text-dim); }
        .CodeMirror {
            flex: 1; height: auto; background: var(--bg); color: var(--text);
            font-family: var(--mono); font-size: 13.5px; line-height: 1.6;
        }
        .CodeMirror-gutters { background: var(--panel-alt); border-right: 1px solid var(--border); }
        .CodeMirror-linenumber { color: var(--text-dim); }
        .CodeMirror-cursor { border-left-color: var(--text); }
        .CodeMirror-selected { background: var(--panel-alt); }
        /* Prefixed with .CodeMirror (not bare .cm-*) to match the specificity of
           CodeMirror's own built-in default theme (".cm-s-default .cm-keyword" etc,
           loaded from the CDN codemirror.min.css) — a bare single-class selector
           here loses to that two-class rule regardless of stylesheet order.
           Six token categories — keyword / string / number / comment / type /
           function — mirroring the hljs override in the preview/viewer iframe (see
           wrapDocument in editor.js/viewer.js) so both views read the same way;
           everything else (plain identifiers, operators, punctuation) is left at
           the inherited --text instead of the default theme's own per-token colors. */
        .CodeMirror .cm-keyword, .CodeMirror .cm-atom, .CodeMirror .cm-builtin, .CodeMirror .cm-meta { color: var(--code-keyword); }
        .CodeMirror .cm-string, .CodeMirror .cm-string-2 { color: var(--code-string); }
        .CodeMirror .cm-number { color: var(--code-number); }
        .CodeMirror .cm-comment { color: var(--code-comment); font-style: italic; }
        .CodeMirror .cm-def, .CodeMirror .cm-variable-3, .CodeMirror .cm-type { color: var(--code-type); }
        .CodeMirror .cm-variable-2 { color: var(--code-function); }
        .CodeMirror .cm-variable, .CodeMirror .cm-property, .CodeMirror .cm-qualifier,
        .CodeMirror .cm-tag, .CodeMirror .cm-attribute, .CodeMirror .cm-bracket { color: var(--text); }

        #preview { flex: 1; width: 100%; border: none; background: var(--bg); }

        /* Video/audio preview, rendered directly in the app page instead of inside
           #preview's sandboxed iframe — a server-streamed (GridFS) file's <video src>
           needs the auth cookie, which a sandboxed cross-origin iframe (no
           allow-same-origin) never sends, since it has no "site" the cookie's
           SameSite=Lax policy considers same-site with the top page. A plain
           <video>/<audio> element can't execute script either way, so there's
           nothing the iframe sandbox was actually protecting here. See
           showMediaPreview in editor.js. */
        .media-preview {
            flex: 1; width: 100%; display: none; align-items: center; justify-content: center;
            background: var(--bg); overflow: auto;
        }
        .media-preview[data-active] { display: flex; }
        .media-preview video { max-width: 100%; max-height: 100%; border-radius: 8px; background: #000; }
        .media-preview audio { width: min(480px, 90%); }
        .media-preview .pdf-preview-frame { width: 100%; height: 100%; border: 0; border-radius: 8px; background: #fff; }
        .media-preview-missing { color: var(--text-dim); font-size: 13px; font-family: var(--sans); }
        /* OnlyOffice/Collabora's own editor renders an <iframe> of its own inside this —
           same full-bleed treatment as the PDF frame above (see showOfficePreview). */
        .office-editor-container { width: 100%; height: 100%; }

        /* Custom right-click menu for the video/audio preview above — replaces the
           browser's native context menu (which offers "Save video/audio as…") with a
           small set of playback actions. */
        .video-menu {
            position: fixed; z-index: 50; min-width: 160px; display: none;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 6px;
        }
        .video-menu[data-open] { display: block; }
        .video-menu button {
            display: block; width: 100%; text-align: left; background: transparent; border: none; color: var(--text);
            padding: 6px 8px; border-radius: 5px; font-size: 12.5px; cursor: pointer; font-family: var(--sans);
        }
        .video-menu button:hover { background: var(--panel-alt); }

        /* Outline on the right edge: a tick per heading, sized by level, by default.
           Hovering the ticks themselves (not the empty space above/below them) hides
           them and shows the full title list instead (dropdown-style); moving out
           brings the ticks back. .toc-strip only exists to vertically center
           .toc-hover-zone within the header/footer band (top/bottom set via JS in
           fitAppHeight) — it's pointer-events:none so its own, mostly-empty, full-height
           box is never itself hoverable. .toc-hover-zone shrink-wraps whichever of
           .toc-ticks/.toc-panel is currently shown, and JS (not a CSS :hover
           self-toggle, which flickered under real mouse movement) swaps between them
           on its mouseenter/mouseleave. */
        .toc-strip {
            position: fixed; right: 10px; z-index: 25; pointer-events: none;
            display: flex; flex-direction: column; align-items: flex-end; justify-content: center;
        }
        .toc-strip[hidden] { display: none; }
        .toc-hover-zone { display: inline-flex; pointer-events: auto; }
        .toc-ticks { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; }
        .toc-tick {
            height: 2px; border-radius: 1px; background: var(--border); cursor: pointer;
            transition: background-color .15s;
        }
        .toc-tick.active { background: var(--accent); }
        .toc-panel {
            display: none;
            min-width: 190px; max-width: 280px; max-height: 70vh; overflow-y: auto;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); padding: 6px;
        }
        .toc-panel-item {
            display: flex; align-items: center; gap: 4px; width: 100%; border-radius: 5px;
        }
        .toc-panel-item:hover { background: var(--panel-alt); }
        .toc-panel-item.active .toc-panel-item-label { color: var(--accent); font-weight: 600; }
        .toc-panel-item-label {
            flex: 1; min-width: 0; background: transparent; border: none; color: var(--text);
            padding: 5px 8px; font-size: 12.5px; text-align: left; cursor: pointer;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        /* On narrow screens (phones) there isn't enough room for editor and preview
           side by side — in split mode they're stacked (preview on top, editor below)
           instead, and the divider is dropped. The format toolbar moves to the bottom
           edge of the screen and stays fixed there regardless of scrolling; #app leaves
           room for it via JS (fitAppHeight). The site footer is fixed below it (its own
           bottom:0), so the toolbar sits above the footer, not the other way around —
           the toolbar's exact bottom offset is set via JS to match the footer's height. */
        @media (max-width: 768px) {
            /* Safety net: without this, a single element that doesn't fit the
               screen width (the old failure mode below, in .toolbar/.seg) grows
               the browser's layout viewport itself, since nothing upstream ever
               clips horizontal overflow. Once that happens every 100vw/fixed-
               position calculation on the page (including fitAppHeight's own
               window.innerWidth/innerHeight reads) is off, not just the one
               overflowing element — so this stays even though the specific
               overflow below is now fixed, as a guard against the next one. */
            html, body { overflow-x: hidden; }

            /* The toolbar's items (brand, view-mode switch, pdf/viewer buttons)
               were sized for desktop and together are wider than a phone screen.
               .seg has overflow:hidden (see base rule), which — per the flexbox
               spec — resets its default min-width:auto to 0, so it was the one
               that silently absorbed the deficit: on a narrow screen it got
               squeezed down to a couple of px, making the edit/split/preview
               switch effectively unusable. Wrapping the row and giving the
               switch its own full-width line fixes that; the pdf/viewer-open
               buttons drop their text label and become icon-only to fit
               alongside the brand on the remaining line. */
            .toolbar { flex-wrap: wrap; row-gap: 8px; padding: 8px 10px; }
            .seg { order: 3; flex: 1 1 100%; }
            /* A whiteboard or media file has no edit/preview switch: the code parks it as
               visibility:hidden (space kept, for the desktop row) — on a phone that would
               be an empty row of its own, so it goes away entirely. */
            .seg[style*="visibility: hidden"] { display: none; }
            /* The transparent desktop labels ("Nur Bearbeitung") wrapped to two lines and
               doubled the row's height; the row is one line tall. */
            .seg button { white-space: nowrap; padding: 7px 4px; }
            /* Full-width labels ("Nur Bearbeitung"/"Nur Vorschau") don't fit three-
               across on a phone even with the row to themselves — swap in the
               short data-mobile-label via a positioned ::after instead of
               wrapping/truncating, keeping the original text for desktop/a11y. */
            .seg button { flex: 1; position: relative; color: transparent; }
            .seg button::after {
                content: attr(data-mobile-label);
                position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
                color: var(--text-dim);
            }
            .seg button.active::after { color: var(--accent-contrast); }
            .pdf-btn .btn-label, .open-viewer-btn .btn-label { display: none; }
            .pdf-btn, .open-viewer-btn { padding: 7px 9px; }

            .work { flex-direction: column-reverse; }
            .divider { display: none !important; }
            .format-bar {
                position: fixed; top: auto; left: 0; right: 0;
                border-top: 1px solid var(--border); border-bottom: none;
                z-index: 40;
            }
            footer.footer {
                position: fixed; left: 0; right: 0; bottom: 0;
                z-index: 41;
            }
            .files-body {
                position: fixed; left: 0; z-index: 45;
                width: 260px; max-width: 80vw;
                box-shadow: 4px 0 24px rgba(0,0,0,.35);
            }
            .files-backdrop {
                display: block; position: fixed; inset: 0; z-index: 44; background: rgba(0,0,0,.4);
            }
            .files-backdrop[hidden] { display: none; }
            /* The symbol/HTML/"+" dropdowns are normally positioned next to their
               toggle button via JS (getBoundingClientRect + visualViewport math) — on
               mobile Safari that ends up placing the menu somewhere off-screen (the
               toggle button itself still highlights as active, so the click handler is
               running fine; the box just never becomes visible). Sidestepping the math
               entirely on mobile is more robust than continuing to chase the exact
               cause: just center the menu on screen via plain CSS. The JS skips calling
               positionDropdown() on mobile so it doesn't set competing inline styles.
               !important is needed since positionDropdown may have left stale inline
               left/top on the element from a previous desktop-width open. */
            .dd-menu {
                top: 50% !important; left: 50% !important;
                transform: translate(-50%, -50%);
                max-width: calc(100vw - 32px); max-height: calc(100vh - 32px); overflow-y: auto;
            }
        }

        /* Shown in place of the whole app shell when a /e/{id} route resolves to a
           document/vault the caller has no rights to, or a session that's expired —
           see showAccessError in editor.js. */
        .access-error {
            display: flex; flex-direction: column; align-items: center; justify-content: center;
            gap: 10px; height: 100%; min-height: 60vh; text-align: center; padding: 24px;
        }
        .access-error h2 { margin: 0; font-size: 20px; color: var(--text); }
        .access-error p { margin: 0; color: var(--text-dim); font-size: 14px; max-width: 420px; }
        .access-error-btn {
            margin-top: 10px; padding: 8px 18px; border-radius: 6px; background: var(--accent);
            color: var(--accent-contrast); font-size: 13px; font-weight: 600; text-decoration: none;
        }
        button.access-error-btn { border: none; cursor: pointer; font-family: inherit; }
        .access-error-btn:hover { opacity: .9; }
        .access-error-password-form { display: flex; gap: 8px; margin-top: 4px; }
        .access-error-password-form input {
            padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 13px; font-family: var(--sans);
        }
        .access-error-password-error { margin: 0; color: #d9534f; font-size: 13px; }

        /* -- Favourites tab in the side panel: the vault name once, grey, above the first
              file of each group — same shape the Mac client's list has. -- */
        .fav-sort-row {
            display: flex; align-items: center; gap: 8px;
            padding: 6px 12px; border-bottom: 1px solid var(--border);
        }
        .fav-sort-row label { font-size: 11px; color: var(--text-dim); white-space: nowrap; }
        .fav-sort-row select {
            flex: 1; min-width: 0; padding: 3px 6px; font-size: 12px; font-family: var(--sans);
            background: var(--panel-alt); color: var(--text);
            border: 1px solid var(--border); border-radius: 5px;
        }

        .fav-vault-label {
            padding: 8px 12px 2px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
            color: var(--text-dim); user-select: none;
        }
        .fav-vault-label:first-child { padding-top: 2px; }
        .fav-doc-row {
            display: flex; align-items: center; gap: 7px; width: 100%;
            padding: 5px 12px 5px 18px; border: none; background: none; cursor: pointer;
            color: var(--text); font-size: 13px; font-family: var(--sans); text-align: left;
        }
        .fav-doc-row:hover { background: var(--panel-alt); }
        .fav-doc-row.active { background: var(--panel-alt); font-weight: 600; }
        .fav-doc-row .fav-doc-icon { display: inline-flex; color: var(--text-dim); flex: 0 0 auto; }
        .fav-doc-row .fav-doc-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

        /* -- Find & replace bar (Editor.cshtml #findBar, editor.js's find bar): sits between
           the format bar and the editing surface, one row for the search and — folded out
           with ⇄ or Ctrl+H — one for the replacement. -- */
        .find-bar { flex-shrink: 0; background: var(--panel); border-bottom: 1px solid var(--border); padding: 5px 8px; display: flex; flex-direction: column; gap: 4px; }
        .find-bar[hidden] { display: none; }
        .find-row { display: flex; align-items: center; gap: 4px; }
        .find-row[hidden] { display: none; }
        .find-input {
            flex: 1; min-width: 80px; max-width: 360px; height: 26px; padding: 0 8px;
            background: var(--panel-alt); border: 1px solid var(--border); border-radius: 5px; color: var(--text);
            font-family: var(--mono); font-size: 12.5px;
        }
        .find-input:focus { outline: none; border-color: var(--accent); }
        .find-input.find-input-error { border-color: #e05252; }
        .find-count { font-family: var(--mono); font-size: 11px; color: var(--text-dim); min-width: 52px; text-align: center; white-space: nowrap; }
        .find-count.find-count-none { color: #e05252; }
        .find-btn {
            height: 26px; min-width: 26px; padding: 0 6px; display: inline-flex; align-items: center; justify-content: center;
            background: var(--panel-alt); border: 1px solid var(--border); border-radius: 5px; color: var(--text);
            font-family: var(--sans); font-size: 12px; cursor: pointer; transition: .15s;
        }
        .find-btn:hover { border-color: var(--accent); color: var(--accent); }
        .find-btn.find-opt { font-family: var(--mono); font-size: 11px; }
        .find-btn.find-opt.active { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
        .find-close { font-size: 16px; line-height: 1; }
        .find-text-btn { padding: 0 10px; }
        .find-sep { width: 1px; height: 18px; background: var(--border); margin: 0 3px; }
        /* Every match, painted by CodeMirror's markText in a code file and by the layer behind
           the textarea otherwise; the current one stands out in orange. */
        .cm-find-match, .find-hl { background: rgba(255, 193, 7, .32); border-radius: 2px; }
        .cm-find-match-current, .find-hl-current { background: rgba(255, 140, 0, .6); outline: 1px solid rgba(255, 140, 0, .9); }
        .editor-text-wrap { flex: 1; min-width: 0; position: relative; display: flex; }
        .editor-find-layer {
            position: absolute; top: 0; left: 0; bottom: 0; overflow: hidden; pointer-events: none;
            padding: 16px; box-sizing: border-box; background: var(--bg);
            font-family: var(--mono); font-size: 13.5px; line-height: 1.6; tab-size: 2;
            white-space: pre-wrap; overflow-wrap: break-word; color: transparent;
        }
        .editor-find-layer[hidden] { display: none; }
        .editor-find-layer-inner { will-change: transform; }
        /* Bootstrap's reboot pads <mark> (.1875em) — that would make every highlight wider
           than its text and drift off the letters. */
        .editor-find-layer mark { color: transparent; padding: 0; margin: 0; }
        /* While the layer is up, the textarea shows it through: text on top, highlights behind. */
        .editor-text-wrap.find-active textarea#src { background: transparent; }
        /* The absolutely positioned layer would paint over a static sibling; the text stays on top. */
        .editor-text-wrap textarea#src { position: relative; z-index: 1; }
        @media (max-width: 640px) { .find-count { min-width: 0; } .find-sep { display: none; } }

        /* -- Template dialog (Editor/_TemplateModal.cshtml): list left, preview right. -- */
        .template-modal { width: 760px; }
        .template-body { display: flex; gap: 14px; margin-top: 14px; min-height: 320px; }
        .template-list { width: 220px; flex-shrink: 0; overflow-y: auto; max-height: 60vh; border: 1px solid var(--border); border-radius: 8px; padding: 6px; background: var(--panel-alt); }
        .template-group-label { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-dim); margin: 8px 6px 4px; }
        .template-group-label:first-child { margin-top: 2px; }
        .template-item {
            display: flex; align-items: center; gap: 6px; width: 100%; text-align: left; padding: 6px 8px;
            background: transparent; border: 1px solid transparent; border-radius: 6px; color: var(--text); cursor: pointer;
            font-family: var(--sans); font-size: 12.5px;
        }
        .template-item:hover { background: var(--panel); }
        .template-item.active { background: var(--panel); border-color: var(--accent); }
        .template-item-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .template-item-ext { font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); }
        .template-item-del { width: 18px; height: 18px; border: none; background: transparent; color: var(--text-dim); border-radius: 4px; cursor: pointer; font-size: 14px; line-height: 1; padding: 0; }
        .template-item-del:hover { background: rgba(224, 82, 82, .15); color: #e05252; }
        .template-side { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
        .template-preview {
            flex: 1; min-height: 240px; max-height: 50vh; overflow: auto; margin: 0; padding: 12px;
            background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
            font-family: var(--mono); font-size: 12px; line-height: 1.55; color: var(--text); white-space: pre-wrap; word-break: break-word;
        }
        .template-preview.empty { color: var(--text-dim); font-family: var(--sans); font-style: italic; }
        .template-create-row { display: flex; gap: 6px; }
        .template-name-input {
            flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
            background: var(--panel-alt); color: var(--text); font-size: 12.5px; font-family: var(--mono);
        }
        .template-name-input:focus { outline: none; border-color: var(--accent); }
        .template-create-btn {
            padding: 6px 14px; border: none; border-radius: 6px; background: var(--accent);
            color: var(--accent-contrast); font-size: 12px; font-weight: 600; cursor: pointer; font-family: var(--sans);
        }
        .template-create-btn:disabled { opacity: .5; cursor: not-allowed; }
        @media (max-width: 640px) {
            .template-body { flex-direction: column; }
            .template-list { width: auto; max-height: 30vh; }
        }
        .editor-toast {
            position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 10px); z-index: 80;
            padding: 8px 14px; border-radius: 8px; background: var(--panel); border: 1px solid var(--border);
            box-shadow: 0 8px 24px rgba(0,0,0,.25); color: var(--text); font-size: 12.5px; font-family: var(--sans);
            opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
        }
        .editor-toast.show { opacity: 1; transform: translate(-50%, 0); }

        /* -- Table bar (Editor.cshtml #tableBar) and the size picker under "Tabelle". -- */
        .table-bar {
            position: absolute; z-index: 24; display: flex; align-items: center; gap: 3px; padding: 3px;
            background: var(--panel); border: 1px solid var(--border); border-radius: 9px;
            box-shadow: 0 4px 16px rgba(0,0,0,.2); touch-action: manipulation; white-space: nowrap;
        }
        .table-bar[hidden] { display: none; }
        .table-btn.find-opt { font-family: var(--sans); font-size: 13px; }
        .table-btn-danger:hover { border-color: #e05252; color: #e05252; }
        .table-picker { width: auto; flex-direction: column; align-items: stretch; gap: 6px; }
        .table-picker-grid { display: grid; grid-template-columns: repeat(8, 18px); gap: 3px; }
        .table-picker-cell { width: 18px; height: 18px; border: 1px solid var(--border); border-radius: 3px; background: var(--panel-alt); cursor: pointer; }
        .table-picker-cell.on { background: var(--accent); border-color: var(--accent); opacity: .85; }
        .table-picker-label { font-size: 11.5px; color: var(--text-dim); text-align: center; font-family: var(--mono); }
        @media (max-width: 640px) { .table-bar-hint { display: none; } }

        /* -- Completion popup (Editor.cshtml #acPopup): at the caret, inside the editing pane. -- */
        .ac-popup {
            position: absolute; z-index: 25; min-width: 200px; max-width: 340px; max-height: 240px; overflow-y: auto;
            background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 4px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28);
        }
        .ac-popup[hidden] { display: none; }
        .ac-item {
            display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 5px 8px;
            background: transparent; border: none; border-radius: 5px; color: var(--text); cursor: pointer;
            font-family: var(--sans); font-size: 12.5px;
        }
        .ac-item:hover, .ac-item.active { background: var(--panel-alt); }
        .ac-kind { font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--accent); width: 44px; flex-shrink: 0; }
        .ac-kind.word { color: var(--text-dim); }
        .ac-label { font-family: var(--mono); font-size: 12.5px; white-space: nowrap; }
        .ac-detail { color: var(--text-dim); font-size: 11.5px; margin-left: auto; padding-left: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .ac-item mark { background: transparent; color: var(--accent); font-weight: 600; }

        /* -- CodeMirror's hint popup (addon/hint/show-hint) in the app's colours. -- */
        .CodeMirror-hints {
            z-index: 60; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 4px;
            box-shadow: 0 10px 28px rgba(0,0,0,.28); font-family: var(--mono); font-size: 12.5px; max-height: 240px;
        }
        .CodeMirror-hint { color: var(--text); padding: 4px 8px; border-radius: 5px; }
        li.CodeMirror-hint-active { background: var(--panel-alt); color: var(--accent); }
        .CodeMirror-hint.cm-hint-keyword::before { content: 'code'; font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--accent); margin-right: 8px; }
        .CodeMirror-hint.cm-hint-word::before { content: 'wort'; font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); margin-right: 8px; }
        html[lang^="en"] .CodeMirror-hint.cm-hint-word::before { content: 'word'; }

        /* -- Quick formatting over a selection (editor.js #selBar), like the table bar. -- */
        .sel-bar {
            position: absolute; z-index: 24; display: flex; align-items: center; gap: 3px; padding: 3px;
            background: var(--panel); border: 1px solid var(--border); border-radius: 9px;
            box-shadow: 0 4px 16px rgba(0,0,0,.2); touch-action: manipulation; white-space: nowrap;
        }
        .sel-bar[hidden] { display: none; }
        .sel-bar-btn { min-width: 28px; padding: 0 6px; }
        .sel-bar-btn .fmt-glyph { font-size: 13px; }
        .template-preview-board { white-space: normal; display: flex; align-items: center; justify-content: center; background: #fff; }
        .template-preview-board svg { max-width: 100%; max-height: 46vh; height: auto; }
        .ac-item .ac-label .ac-box { color: var(--text-dim); }
