        :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;
        }
        .format-bar button:hover, .fmt-select:hover { border-color: var(--accent); color: var(--accent); }
        .fmt-select { max-width: 168px; }
        .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)
           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; }
        .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-toggle {
            width: 34px; flex-shrink: 0; display: flex; flex-direction: column; align-items: center;
            gap: 10px; padding-top: 12px;
            background: transparent; border: none; border-right: 1px solid var(--border);
            color: var(--text-dim); cursor: pointer;
        }
        .files-toggle:hover { color: var(--text); background: var(--panel-alt); }
        .files-toggle-icon { flex-shrink: 0; display: inline-flex; transition: transform .15s; }
        .files-toggle.expanded .files-toggle-icon { transform: rotate(180deg); }
        .files-toggle-label {
            writing-mode: vertical-rl;
            font-family: var(--mono); font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase;
            white-space: nowrap;
        }
        .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; }
        .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; }
        .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; justify-content: space-between; }
        .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); }
        .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;
        }

        textarea#src {
            flex: 1; 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-missing { color: var(--text-dim); font-size: 13px; font-family: var(--sans); }

        /* 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%; }
            /* 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;
            }
            /* The file panel's toggle stays put in the column-reverse stack (so it
               keeps landing near the bottom, right above the format toolbar — simplest
               to reach with a thumb); the body, once expanded, becomes a left-edge
               overlay instead of pushing the editor/preview out of the way. top/bottom
               are set via JS (fitAppHeight) to match the same header/footer band as
               everything else. The toggle itself switches from a tall vertical column
               (fine on desktop, where it just needs to fit the header/footer band) to a
               short horizontal bar — otherwise it eats into the limited vertical space
               of the stacked mobile layout. */
            .files-panel { border-right: none; border-top: 1px solid var(--border); }
            .files-toggle {
                flex-direction: row; width: 100%; height: 36px;
                padding: 0 14px; gap: 8px; justify-content: flex-start;
                border-right: none;
            }
            .files-toggle-label { writing-mode: horizontal-tb; }
            .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; }
