/* ADATool-License-Header
Copyright James C. Davis, 2026. All rights reserved.

This source file is part of the ADATool product (scholaccess.com). It is
delivered to your browser only as part of the running application. You do
not have permission to copy, modify, redistribute, reverse-engineer, or
otherwise re-use this code, in whole or in part, except as expressly
authorized in writing by the copyright holder. Use of the running
application is governed by the Terms of Service at
https://scholaccess.com/terms.
*/
/* ─── Editor page (loaded after style.css) ─────────────────────────────────
   The editor route extends the SPA's tokens (no new colors invented). All
   tokens come from style.css :root. The only escape valve here is layout —
   the editor needs full-bleed width and a fixed top-bar / status-bar; the
   main SPA's centered 1080-cap layout doesn't fit a canvas + sidebar.
   See docs/design/spa-a11y-editor-260430.md §5.14. */

/* ─── Z-index ladder ──────────────────────────────────────────────────────
   Single-source-of-truth for stacking-context priority. Declared in
   numerical order so the visual stack is obvious at a glance:

   2-5     overlay markers painted on top of the PDF preview
   10      pane splitter (above panes, below any popover)
   22-25   overlay badges and selected bboxes
   50-100  in-pane popovers + transparent loading overlay
   200-300 modal backdrops + the floating feedback FAB
   1000+   page-anchored popovers (type popover, insert marquee)
   2500    right-click context menu
   4000    undo toast
   8000+   screen-reader slide-over (backdrop + panel)
   9100    insert ctxmenu (sits above SR slide-over) */
:root {
    --z-overlay-bbox:            2;
    --z-overlay-bbox-active:     3;
    --z-splitter:               10;
    --z-overlay-badge:          22;
    --z-overlay-bbox-emphasis:  25;
    --z-zoom-dropdown:          50;
    --z-loading-overlay:       100;
    --z-overlay-tooltip:       100;
    --z-modal-backdrop:        200;
    --z-feedback-fab:          200;
    --z-feedback-backdrop:     300;
    --z-type-popover:         1000;
    --z-insert-marquee:       1100;
    --z-context-menu:         2500;
    --z-toast:                4000;
    --z-screen-reader-backdrop: 8000;
    --z-screen-reader-panel:    8050;
    --z-insert-ctxmenu:         9100;
    /* Editor-specific color tokens (not shared with the main SPA) */
    --white: #ffffff;              /* pure white for text-on-dark and fills */
    --black: #000000;              /* pure black for high-contrast focus rings */
    --bg-card-active: #dce8f8;     /* active/hover item bg in type-popover list */
    --bg-drag-over: #dce6f2;       /* soft blue-gray; empty-state drag-over hover */
    --bg-near-white: #fafbfc;      /* almost-white input/textarea area */
    --bg-subtle-alt: #f5f7f9;      /* alternate subtle background in disabled inputs */
    --border-zinc: #d4d4d8;        /* zinc-300; toast/card subtle border */
    --red-300: #fca5a5;            /* red-300; muted error tone (empty-alt tooltip) */
    --bg-info-light: #e0f2fe;      /* sky-100; lighter info bg for info toasts */
}

/* Width opt-out: the editor takes the full viewport. */
body.editor-route {
    max-width: none;
    margin: 0;
    padding: 0;
    /* Lock body to exactly the viewport — NOT min-height. Without `height` +
       `overflow: hidden`, a tall PDF canvas inside the preview pane stretches
       #editor-main past 100vh, the body grows to fit, the entire page gets a
       scrollbar, and both panes scroll as a unit (the user's "panes are not
       height-balanced" report — the symptom is one pane has visible content
       above the fold and the other doesn't, but the body scrolls them
       together). With `height: 100vh; overflow: hidden`, each .pane-body
       scrolls independently inside its pane and the panes stay equal-height
       within the viewport. */
    height: 100vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Editor toolbar (file name / undo / redo / save / help). Sits below the
   shared #top-bar-stack from style.css; height ~44 px.

   Issue 6: `flex-wrap: nowrap` + `overflow: hidden` keeps the toolbar
   anchored at one row even if a future addition pushes total width past
   the viewport. Items past the viewport are clipped — better than the
   pre-fix two-row layout that overlapped the editor body below. */
.editor-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: nowrap;
    overflow: hidden;
    gap: 16px;
    padding: 6px 16px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    flex: 0 0 auto;
}

.editor-toolbar-left,
.editor-toolbar-right {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 10px;
}

/* Audit F-08: iPad portrait (~768px) clips the right toolbar — 7 buttons
   don't fit alongside the file name. Hide the lowest-priority buttons
   (Swap panes — keyboard-only, Undo/Redo — Ctrl+Z works regardless,
   Help — Ctrl+? hotkey works regardless) under 768px. The remaining
   essential affordances are: attestation pill, Open, Save. */
@media (max-width: 768px) {
    #editor-swap-panes-btn,
    #editor-undo-btn,
    #editor-redo-btn,
    #editor-help-btn {
        display: none;
    }
}

/* Issue 6: page-nav + zoom controls relocated to the PDF preview pane header.
   This wraps them in a small flex container right-aligned to the right of
   the pane title. */
.editor-pane-header-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

/* Fix 260504: compact zoom-level pill in the PDF pane header.
   Mirrors .editor-status-zoom-btn shape but smaller so it fits
   inline between the − and + buttons. */
.editor-pane-zoom-level-btn {
    padding: 3px 8px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    min-width: 52px;
    text-align: center;
}


.editor-back-link {
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
    font-size: 14px;
}

.editor-back-link:hover { text-decoration: underline; }

.editor-toolbar-sep {
    width: 1px;
    height: 20px;
    background: var(--border);
}

.editor-file-name {
    color: var(--text);
    font-size: 14px;
    font-weight: 500;
    /* Truncate long filenames; the title attribute (set in JS) shows the full name. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 360px;
}

.editor-btn {
    /* Reuse .oauth-btn shape per §5.14 styling contract. */
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background 0.15s, box-shadow 0.15s;
}

.editor-btn:hover:not(:disabled) {
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
    background: var(--accent-light);
}

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

.editor-btn-primary {
    background: var(--accent);
    color: var(--white);
    border-color: var(--accent);
}

.editor-btn-primary:hover:not(:disabled) {
    background: var(--accent-hover);
}

.editor-btn-icon {
    width: 32px;
    height: 32px;
    padding: 0;
    justify-content: center;
    font-weight: 700;
}

/* Spinner state (used during save). */
.editor-btn.is-saving { opacity: 0.8; pointer-events: none; }
.editor-btn.is-saving::after {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(255, 255, 255, 0.6);
    border-top-color: var(--white);
    border-radius: 50%;
    animation: editor-spin 0.7s linear infinite;
    margin-left: 6px;
}
@keyframes editor-spin { to { transform: rotate(360deg); } }

/* ─── Main work area ────────────────────────────────────────────────────── */

#editor-main {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* ─── Empty-state hero ─────────────────────────────────────────────────── */

.editor-empty-state {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
}

.editor-empty-card {
    border: 2px dashed var(--accent);
    border-radius: var(--radius);
    background: var(--accent-light);
    padding: 48px 56px;
    max-width: 560px;
    width: 100%;
    text-align: center;
    transition: border-color 0.2s, background 0.2s;
}

.editor-empty-card.is-dragover {
    border-color: var(--accent-hover);
    background: var(--bg-drag-over);
}

.editor-empty-iconrow {
    margin-bottom: 16px;
    color: var(--text-muted);
}

.editor-empty-headline {
    font-size: 22px;
    font-weight: 700;
    color: var(--accent);
    margin-bottom: 8px;
    letter-spacing: -0.3px;
}

.editor-empty-sub {
    font-size: 15px;
    color: var(--text);
    margin-bottom: 12px;
    line-height: 1.5;
}

.editor-link-button {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--accent);
    text-decoration: underline;
    cursor: pointer;
    font-weight: 600;
}
.editor-link-button:hover { color: var(--accent-hover); }

.editor-empty-meta {
    font-size: 13px;
    color: var(--text-muted);
}

/* WHY: Safari (since ~16.x) silently no-ops `.click()` on a file input whose
   computed `display` is `none`. The toolbar "Open" button and the inline
   "click to browse" button both call `els.fileInput.click()` — both go dead
   in Safari if the input is `display:none`. The visually-hidden pattern
   below (absolute 1×1 + clip) keeps the input in the layout so .click()
   opens the OS picker, while remaining invisible to sighted users.
   Pinned by web/static/editor/test/smoke/safari-file-input-260505.spec.mjs. */
.editor-file-input-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    /* opacity:0 so even if a future CSS rule un-clips, the input stays
       invisible — defense in depth. */
    opacity: 0;
}

/* ─── Three-pane workspace ────────────────────────────────────────────────── */

.editor-workspace {
    flex: 1 1 auto;
    display: flex;
    flex-direction: row;
    min-height: 0;
    /* Pane widths are set directly on each .editor-pane by editor.js via flex-basis. */
}

.editor-workspace.hidden { display: none; }

/* WHY: .editor-empty-state has display:flex (specificity 0,1,0) which loads
 * after style.css's generic .hidden { display:none } (same specificity, but
 * editor.css is later in the <link> order). Without this rule the generic
 * .hidden is silently overridden and the empty-state hero stays visible after
 * showWorkspace() adds the class. Mirrors the pattern used for
 * .editor-workspace.hidden above. */
.editor-empty-state.hidden { display: none; }

/* Each pane is a flex column inside the flex row. */
.editor-pane {
    background: var(--surface);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    min-width: 0;
    position: relative;
    /* Smooth expand/collapse transitions. */
    transition: flex-basis 0.18s ease, width 0.18s ease;
    /* Prevent pane from shrinking below its set flex-basis. */
    flex-shrink: 0;
}

/* Pane header: title + collapse button + drag handle.
   min-height: 40px pins both pane headers to the same height so they stay
   visually equal even though the PDF pane header has more controls. */
.pane-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 6px 10px;
    min-height: 40px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    flex: 0 0 auto;
    cursor: grab;
    user-select: none;
}

.pane-header:active { cursor: grabbing; }

.pane-title {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
}

.pane-collapse,
.pane-font-btn {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    padding: 0;
    font-size: 15px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border-color: transparent;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

.pane-font-btn {
    width: 26px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.5px;
}

.pane-collapse:hover,
.pane-font-btn:hover {
    background: var(--accent-light);
    color: var(--accent);
    border-color: var(--border);
    box-shadow: none;
}

.pane-header-controls {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}

/* Pane body scrolls independently. */
.pane-body {
    flex: 1 1 auto;
    overflow: auto;
    min-height: 0;
}

/* ── Collapsed pane state ──
   `!important` is required to override the inline flex-basis/width that
   pane-layout.js writes on every applyLayout() call; without it, the
   collapsed-32px state would never take effect when a user toggles
   `aria-expanded="false"`. */
.editor-pane[aria-expanded="false"] {
    flex: 0 0 32px !important;
    width: 32px !important;
    min-width: 32px !important;
}

.editor-pane[aria-expanded="false"] .pane-body { display: none; }
.editor-pane[aria-expanded="false"] .pane-splitter { display: none; }

.editor-pane[aria-expanded="false"] .pane-header {
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    height: 100%;
    cursor: pointer;
    border-bottom: none;
    border-right: 1px solid var(--border);
}

.editor-pane[aria-expanded="false"] .pane-title {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    white-space: nowrap;
    overflow: visible;
    text-overflow: clip;
    transform: rotate(180deg);
    flex: 1 1 auto;
}

.editor-pane[aria-expanded="false"] .pane-collapse {
    writing-mode: horizontal-tb;
    transform: none;
    font-size: 13px;
    margin: 0;
}

/* ── Drag-rearrange visual feedback ── */
.editor-pane.is-drag-source {
    opacity: 0.5;
}

.editor-pane.is-drag-target > .pane-header {
    outline: 2px solid var(--maroon);
    outline-offset: -2px;
}

/* ── Pane splitter — collapsed-by-default vertical drag handle.
   The user reported the prior 6px-wide colored bar with a centered grab-dot
   was "wasting space" (visible column of border-color across full height).
   Visual footprint: a 1-px hairline aligned with the pane edge, no centered
   dot. Hit area: 8 px wide so pointer/touch can grab it.

   Critical positioning constraint: `.editor-pane` has `overflow: hidden`,
   so the splitter MUST sit entirely inside the preview pane's box —
   otherwise the half outside the box is clipped (invisible AND
   pointer-events-dead). We anchor at right:0 (inside-right edge) and let
   the splitter extend 8 px LEFTWARD into the preview pane's rightmost
   column. The visible 1-px hairline rides on the outermost (rightmost)
   pixel so it visually marks the pane seam.

   Hover/focus: hairline thickens to 4px and lights up to var(--accent). */
.pane-splitter {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 8px;
    background: transparent;
    cursor: col-resize;
    z-index: var(--z-splitter);
    transition: background 0.15s;
    flex: 0 0 8px;
    /* Touch devices: opt out of the browser's native gesture so a one-finger
       drag on iPad / Android moves the splitter instead of scrolling the
       pane (audit F-05). pane-layout.js uses Pointer Events; touch-action
       is the spec-blessed way to declare ownership of the gesture. */
    touch-action: none;
}

/* The visible 1-px hairline runs the full height of the splitter at its
   rightmost pixel — that's the pane seam (preview.right === editor.left).
   In swap mode the override below moves the hairline to the LEFT edge. */
.pane-splitter::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 1px;
    background: var(--border);
    transition: width 0.15s, background 0.15s;
}

.pane-splitter:hover::before,
.pane-splitter:focus-visible::before {
    width: 4px;
    background: var(--accent);
}

/* When the workspace is swapped (preview on the RIGHT, structure on the LEFT),
   the splitter needs to sit on the preview pane's LEFT edge — that's the new
   seam between panes. Move both the hit area (left:0) and the hairline
   (::before { left:0 }). */
.editor-workspace[data-swapped="true"] #editor-pane-preview .pane-splitter {
    right: auto;
    left: 0;
}
.editor-workspace[data-swapped="true"] #editor-pane-preview .pane-splitter::before {
    right: auto;
    left: 0;
}

/* ── Inspector pane (opt-in 4th pane, right edge) ── */
.editor-pane-inspector {
    border-left: 1px solid var(--border);
    overflow-y: auto;
    flex: 0 0 280px;
    width: 280px;
}

.editor-pane-inspector .pane-body {
    padding: 12px 16px;
    overflow-y: auto;
}

.editor-pane-inspector.hidden { display: none; }


/* Keep old .editor-pane-pdf and .editor-pane-sidebar names as aliases for
   the new pane IDs, in case existing JS references them by class. */
.editor-pane-pdf {
    /* now the preview pane — kept for backward compat with JS selectors */
}

/* Pane body inside the preview pane wraps the existing PDF toolbar + scroll. */
#pane-preview-body {
    display: flex;
    flex-direction: column;
    padding: 0;
}

#pane-preview-body .editor-pdf-scroll {
    flex: 1 1 auto;
    min-height: 0;
}


/* ─── PDF pane ─────────────────────────────────────────────────────────── */

.editor-pdf-toolbar {
    flex: 0 0 auto;
    padding: 6px 12px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: 12px;
}

.editor-pdf-scroll {
    flex: 1 1 auto;
    overflow: auto;
    background: var(--bg);
    padding: 24px;
    display: flex;
    align-items: flex-start;
    justify-content: center;
}

.editor-pdf-scroll:focus-visible {
    /* Already covered by global :focus-visible, but make the inset visible against
       the page's surface color. */
    outline-offset: -2px;
}

.editor-pdf-pageframe {
    position: relative;
    background: var(--surface);
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
}

/* PR 2: multi-page scroll container — contains per-page .pdf-page-frame divs. */
#editor-pdf-pages {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 16px 0 32px 0;
    min-height: 100%;
}

#editor-pdf-canvas {
    display: block;
}

.editor-pdf-overlay {
    position: absolute;
    inset: 0;
    /* WHY: pointer-events: auto so click+drag on empty PDF area fires
       InsertFlowController's pointerdown/move/up handlers for rubber-band
       region creation. Individual .editor-overlay-bbox children also carry
       pointer-events: auto (explicit) so they remain clickable. */
    pointer-events: auto;
    cursor: crosshair;
}

/*
 * Structure-overlay box — colored hint over a tagged region of the PDF.
 * Inline styles supply background-color + border-color from the per-category
 * palette in overlays.js; the rules here cover positioning, hover/select
 * affordances, and the role-badge shape.
 */
/* Workspace-level toggle: when this class is set on #editor-workspace,
   ALL per-page overlay containers' bboxes are hidden in one shot.
   Multi-page mode renders overlays per-page, so a per-page clear on
   toggle would miss the other pages — this CSS rule is the simplest
   correct way to hide them everywhere. */
.editor-workspace.is-overlays-hidden .editor-overlay-bbox { display: none; }

.editor-overlay-bbox {
    position: absolute;
    border-width: 1.5px;
    border-style: solid;
    border-radius: 2px;
    pointer-events: auto;
    cursor: pointer;
    transition: filter 0.12s, box-shadow 0.12s, border-width 0.12s;
    /* Touch devices: opt out of native scroll so a long-press / drag on the
       overlay moves the bbox via drag-move.js instead of scrolling the
       page (audit F-05). drag-move.js uses Pointer Events + setPointerCapture;
       touch-action: none is the spec-blessed way to claim the gesture. */
    touch-action: none;
}

.editor-overlay-bbox:hover {
    /* Slight darkening + crisper border to signal "click target" without
       changing the per-tag hue. */
    filter: brightness(0.9) saturate(1.1);
    border-width: 2px;
}

.editor-overlay-bbox:focus-visible {
    outline: 2px solid var(--maroon, #6b1a1a);
    outline-offset: 1px;
}

.editor-overlay-bbox.is-selected {
    border-width: 2.5px;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25);
    z-index: var(--z-overlay-bbox);
    /* Boost the fill ~2x by stacking a second translucent layer. */
    filter: brightness(0.95) saturate(1.25);
}

/*
 * PR 3 — drag-to-move visual cue. Active drag participants render with a
 * grabbing cursor + dashed border + slight shadow so the user can see
 * which boxes are moving (especially in multi-select group drag).
 */
.editor-overlay-bbox.is-dragging {
    cursor: grabbing;
    border-style: dashed;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
    z-index: var(--z-overlay-bbox-active);
    /* Disable the brightness/saturate filter during drag so the bbox
       stays pin-sharp while the user is positioning it. */
    filter: none;
}

/*
 * Resize handles — 8 per box (corners + edges). Hidden by default; revealed
 * on hover or selection so they don't add visual noise to every overlay.
 * Each handle has its own cursor shape per the directional convention.
 *
 * Pointer events: handles intercept pointerdown so resize-move.js can pick
 * up the gesture; the box body's pointerdown still routes to drag-move.js
 * (the two controllers dispatch by event-target).
 */
.editor-resize-handle {
    position: absolute;
    width: 10px;
    height: 10px;
    background: var(--white);
    border: 1.5px solid var(--maroon, #6b1a1a);
    border-radius: 2px;
    pointer-events: auto;
    box-sizing: border-box;
    /* Always visible at low opacity so the user discovers them at a
       glance — full opacity on hover / select / resize. The previous
       opacity:0 default left users wondering whether elements were
       resizable at all. */
    opacity: 0.55;
    transition: opacity 0.1s, transform 0.1s;
    z-index: 1; /* keep handles above the box body so they remain clickable */
}
.editor-overlay-bbox:hover .editor-resize-handle,
.editor-overlay-bbox.is-selected .editor-resize-handle,
.editor-overlay-bbox:focus-visible .editor-resize-handle,
.editor-resize-handle:hover {
    opacity: 1;
}
.editor-overlay-bbox.is-resizing .editor-resize-handle { opacity: 1; }

/* Per-handle position + cursor. Translate by half-handle-size so each handle
   centers on its corner / edge midpoint. */
.editor-resize-handle.handle-nw { top: 0;       left: 0;     transform: translate(-50%, -50%); cursor: nwse-resize; }
.editor-resize-handle.handle-n  { top: 0;       left: 50%;   transform: translate(-50%, -50%); cursor: ns-resize; }
.editor-resize-handle.handle-ne { top: 0;       right: 0;    transform: translate( 50%, -50%); cursor: nesw-resize; }
.editor-resize-handle.handle-e  { top: 50%;     right: 0;    transform: translate( 50%, -50%); cursor: ew-resize; }
.editor-resize-handle.handle-se { bottom: 0;    right: 0;    transform: translate( 50%,  50%); cursor: nwse-resize; }
.editor-resize-handle.handle-s  { bottom: 0;    left: 50%;   transform: translate(-50%,  50%); cursor: ns-resize; }
.editor-resize-handle.handle-sw { bottom: 0;    left: 0;     transform: translate(-50%,  50%); cursor: nesw-resize; }
.editor-resize-handle.handle-w  { top: 50%;     left: 0;     transform: translate(-50%, -50%); cursor: ew-resize; }

.editor-overlay-bbox.is-resizing {
    border-style: dashed;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
    z-index: var(--z-overlay-bbox-active);
    filter: none;
}

/*
 * Rubber-band multi-select marquee — drawn on the overlay container during
 * a shift-drag in empty space. Distinguished from `.editor-insert-marquee`
 * (the insert-flow drag-to-create marquee) by hue + dashed pattern so the
 * user can tell at a glance which gesture they're performing.
 */
.editor-rubberband-marquee {
    position: absolute;
    border: 1.5px dashed var(--maroon, #6b1a1a);
    background: rgba(107, 26, 26, 0.08);
    pointer-events: none;
    z-index: var(--z-overlay-bbox-active);
}

/*
 * Upper-left controls cluster: role chip + reading-order chip. Sits
 * inside the bbox at top-left so the user finds both type and order
 * controls in one spot. Each child is interactive (button) and stops
 * propagation so a click never accidentally fires the parent overlay's
 * select / drag-to-create handlers.
 */
.editor-overlay-controlbar {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    display: flex;
    align-items: stretch;
    gap: 3px;
    pointer-events: none;
    z-index: var(--z-overlay-badge);
    /* The container itself has no pointer events; individual chips opt
       in (pointer-events: auto) so the rest of the overlay surface is
       still hit-testable for drag-to-create on empty canvas. */
}
.editor-overlay-controlbar > * {
    pointer-events: auto;
}

.editor-overlay-rolebadge {
    color: var(--white);
    font-size: 10px;
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 0 0 3px 0;
    line-height: 1.3;
    letter-spacing: 0.3px;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
    border: none;
    cursor: pointer;
    font-family: inherit;
    flex: 0 0 auto;
}
button.editor-overlay-rolebadge:hover { filter: brightness(1.1); }
button.editor-overlay-rolebadge:focus-visible {
    outline: 2px solid var(--white);
    outline-offset: 1px;
}

/*
 * Reading-order chip: white pill with up/down arrow buttons flanking
 * a numeric label. The chip sits next to the role chip in the upper-
 * left controls bar; its border-color is set inline from the per-tag
 * palette so the chip hue matches the bbox border.
 */
.editor-overlay-order-chip {
    display: inline-flex;
    align-items: center;
    gap: 0;
    background: var(--white);
    border: 1.5px solid currentColor;
    border-radius: 10px;
    padding: 0;
    height: 18px;
    line-height: 1;
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
}
.editor-overlay-order-num {
    padding: 0 4px;
    color: var(--gray-900);
    min-width: 14px;
    text-align: center;
}
.editor-overlay-order-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 100%;
    padding: 0;
    border: none;
    background: transparent;
    color: currentColor;
    font-size: 9px;
    cursor: pointer;
    font-family: inherit;
}
.editor-overlay-order-arrow.up    { border-radius: 8px 0 0 8px; }
.editor-overlay-order-arrow.down  { border-radius: 0 8px 8px 0; }
.editor-overlay-order-arrow:hover { background: rgba(0, 0, 0, .08); }
.editor-overlay-order-arrow:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: -2px;
}

/*
 * Toggle button in the PDF toolbar. Uses the SPA accent colors. The
 * indicator dot turns from a hollow ring (off) to a filled accent dot (on)
 * so the state is legible at a glance.
 */
.editor-pdf-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.editor-overlays-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    cursor: pointer;
}

.editor-overlays-toggle-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 2px solid var(--accent, #1a56a0);
    background: transparent;
    transition: background 0.12s;
}

.editor-overlays-toggle.is-on .editor-overlays-toggle-dot {
    background: var(--accent, #1a56a0);
}

.editor-overlays-toggle-label {
    font-size: 12px;
}


/* Small button variant used in sidebar view controls (issue 10). */
.editor-btn-sm {
    padding: 4px 10px;
    font-size: 12px;
}

/* ─── Sidebar sections ─────────────────────────────────────────────────── */

.editor-sidebar-section {
    margin-bottom: 20px;
}

.editor-sidebar-title {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-muted);
    margin-bottom: 8px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--border);
}

.editor-meta-list {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 4px 12px;
    font-size: 13px;
}
.editor-meta-list dt { color: var(--text-muted); }
.editor-meta-list dd { color: var(--text); margin: 0; }

.editor-struct-list {
    list-style: none;
    padding: 0;
    margin: 0;
    max-height: 320px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.editor-struct-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    font-size: 13px;
    background: var(--surface);
    color: var(--text);
}

.editor-struct-row:last-child { border-bottom: none; }
.editor-struct-row:hover { background: var(--accent-light); }
.editor-struct-row.is-selected {
    background: var(--accent-light);
    border-inline-start: 3px solid var(--accent);
    padding-inline-start: 7px;
    font-weight: 600;
}

.editor-struct-rolebadge {
    display: inline-block;
    background: var(--accent);
    color: var(--white);
    font-size: 10px;
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 3px;
    flex: 0 0 auto;
    min-width: 26px;
    text-align: center;
}

.editor-struct-text {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-struct-issue {
    /* Tiny coloured dot for issue indication. */
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: 0 0 auto;
}
.editor-struct-issue.issue-error    { background: var(--error); }
.editor-struct-issue.issue-warning  { background: var(--warning); }
.editor-struct-issue.issue-untagged { background: var(--text-muted); }

/* Sidebar view controls (issue 10) — compact nav + zoom row. */
.editor-sidebar-view-controls {
    margin-bottom: 12px;
}

.editor-sidebar-view-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.editor-sidebar-nav-group {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* ─── Edit panel ───────────────────────────────────────────────────────── */

.editor-edit-panel {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px;
    font-size: 13px;
}

.editor-edit-empty {
    color: var(--text-muted);
    margin: 0;
    font-style: italic;
}

.editor-edit-field { margin-bottom: 10px; }
.editor-edit-field:last-child { margin-bottom: 0; }
.editor-edit-field label {
    display: block;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 4px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}
.editor-edit-field .value {
    color: var(--text);
    word-break: break-word;
}
/* Editable controls inside the edit panel. */
.editor-edit-field select,
.editor-edit-field textarea {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 5px 8px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: var(--bg);
    resize: vertical;
}

.editor-edit-field select:focus,
.editor-edit-field textarea:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.editor-edit-field .editor-checkbox-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
}

.editor-edit-field .editor-checkbox-row input[type="checkbox"] {
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: var(--accent);
}

/* ─── Status bar ───────────────────────────────────────────────────────── */

.editor-statusbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 16px;
    background: var(--surface);
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-muted);
}

.editor-status-cell { white-space: nowrap; }
.editor-status-sep {
    width: 1px;
    height: 14px;
    background: var(--border);
}

.editor-status-storage {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.editor-storage-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--text-muted);
}
.editor-storage-dot.healthy { background: var(--success); }
.editor-storage-dot.saving  { background: var(--accent); }
.editor-storage-dot.warning { background: var(--amber-400); } /* matches existing env-banner amber */
.editor-storage-dot.error   { background: var(--error); }

.editor-brand-credit {
    margin-inline-start: auto;
    font-size: 12px;
    color: var(--text-muted);
}

/* ─── Hotkey legend modal (issue 4) ─────────────────────────────────────── */

.editor-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: var(--z-modal-backdrop);
}

.editor-modal-backdrop.hidden { display: none; }

.editor-modal {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
    min-width: 380px;
    max-width: 520px;
    max-height: 80vh;
    overflow-y: auto;
    padding: 24px;
}

.editor-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}

.editor-modal-title {
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.editor-modal-close {
    flex: 0 0 auto;
}

.editor-hotkey-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.editor-hotkey-table th {
    text-align: left;
    font-weight: 700;
    color: var(--text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 4px 8px 8px;
    border-bottom: 1px solid var(--border);
}

.editor-hotkey-table td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    color: var(--text);
}

.editor-hotkey-table tr:last-child td { border-bottom: none; }

/* Section-group headers within the hotkey table.
   FIXME: the `!important` overrides `.editor-hotkey-table td`'s padding;
   a higher-specificity selector (`.editor-hotkey-table .editor-hotkey-section-head`)
   would do the same job without `!important`. Keep until a deliberate
   pass through the hotkey-modal styles. */
.editor-hotkey-section-head {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-muted);
    padding: 10px 8px 4px !important;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.editor-hotkey-table kbd {
    display: inline-block;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 1px 5px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px;
    line-height: 1.5;
    color: var(--text);
}

/* ─── Loading overlay (issue 6) ─────────────────────────────────────────── */

.editor-loading-overlay {
    position: fixed;
    inset: 0;
    background: rgba(255, 255, 255, 0.82);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: var(--z-loading-overlay);
    /* Fade-out transition applied via JS by removing .hidden. */
    opacity: 1;
    transition: opacity 0.2s ease;
}

.editor-loading-overlay.hidden {
    display: none;
}

.editor-loading-overlay.is-hiding {
    opacity: 0;
    pointer-events: none;
}

.editor-loading-overlay.is-error .editor-loading-label {
    color: var(--error-text);
    max-width: 360px;
    text-align: center;
}

.editor-loading-overlay.is-error .editor-loading-spinner {
    border-top-color: var(--error-text);
    animation-play-state: paused;
}

.loading-retry-btn {
    margin-top: 4px;
}

.editor-loading-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

.editor-loading-spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: editor-spin 0.8s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .editor-loading-spinner { animation: none; border-top-color: var(--accent); }
    .editor-loading-overlay { transition: none; }
}

.editor-loading-label {
    font-size: 15px;
    font-weight: 500;
    color: var(--text);
    margin: 0;
}

/* ─── Page navigation toolbar (issue 8) ─────────────────────────────────── */

.editor-toolbar-page-indicator {
    display: flex;
    align-items: center;
    gap: 3px;
    font-size: 13px;
    color: var(--text-muted);
}

.editor-page-of { white-space: nowrap; }

.editor-page-input {
    width: 40px;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 2px 4px;
    font-size: 12px;
    font-family: inherit;
    text-align: center;
    color: var(--text);
    background: var(--bg);
    /* Remove the browser spinner arrows. */
    -moz-appearance: textfield;
}
.editor-page-input::-webkit-outer-spin-button,
.editor-page-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ─── Zoom controls (issue 7) ────────────────────────────────────────────── */

/* Zoom +/- buttons in the toolbar. */
.editor-toolbar-zoom {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* Clickable zoom percentage in status bar. */
.editor-status-zoom-btn {
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius);
    padding: 1px 5px;
    font: inherit;
    font-size: 12px;
    color: var(--text-muted);
    cursor: pointer;
    white-space: nowrap;
}

.editor-status-zoom-btn:hover {
    border-color: var(--border);
    background: var(--accent-light);
    color: var(--text);
}

/* Zoom preset dropdown. */
.editor-zoom-dropdown {
    position: absolute;
    bottom: 100%;
    left: 0;
    margin-bottom: 4px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
    min-width: 160px;
    z-index: var(--z-zoom-dropdown);
    padding: 4px 0;
    list-style: none;
    margin-left: 0;
}

.editor-zoom-dropdown.hidden { display: none; }

.editor-zoom-dropdown li {
    padding: 0;
}

.editor-zoom-dropdown button {
    width: 100%;
    text-align: left;
    padding: 6px 14px;
    font-size: 13px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text);
    font-family: inherit;
}

.editor-zoom-dropdown button:hover { background: var(--accent-light); }
.editor-zoom-dropdown button.is-active { font-weight: 700; color: var(--accent); }

.editor-zoom-dropdown .editor-zoom-custom-row {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 4px 14px 6px;
    border-top: 1px solid var(--border);
}

.editor-zoom-custom-input {
    width: 52px;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 2px 6px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text);
    background: var(--bg);
}

.editor-zoom-custom-go {
    font-size: 12px;
    padding: 3px 8px;
}

/* Anchor the dropdown to the status-bar zoom cell. */
.editor-status-cell.editor-status-zoom-wrap {
    position: relative;
}

/* ─── Tablet adjustments below 900 px ─── */

@media (max-width: 900px) {
    .editor-file-name { max-width: 180px; }
}

/* ─── Phone: prevent .editor-modal from clipping off-screen ──────────────────
   On phones narrower than 480px (iPhone SE, Galaxy Fold cover) the 380px
   min-width causes the modal to overflow the right edge, hiding the close
   button. Remove the hard min-width and instead fill the viewport minus a
   12px margin on each side. Applies to both the hotkey modal and the
   attestation modal because both share the .editor-modal selector. */
@media (max-width: 480px) {
    .editor-modal {
        min-width: unset;
        width: calc(100vw - 24px);
        max-width: 100vw;
        padding: 16px;
        box-sizing: border-box;
    }
}

/* ─── Editor toast (op-apply errors, save status, untagged-PDF hint) ─── */

.editor-toast {
    margin: 8px;
    padding: 8px 12px;
    background: var(--warning-bg);
    border: 1px solid var(--amber-400);
    border-radius: var(--radius);
    font-size: 12px;
    color: var(--text);
}

.editor-toast[data-type="error"] {
    background: var(--error-bg);
    border-color: var(--error-text);
}

.editor-toast[data-type="info"] {
    background: var(--bg-info-light);
    border-color: var(--info-border);
}

.editor-toast[data-type="success"] {
    background: var(--success-bg);
    border-color: var(--success);
}

/* ─── Attestation pill ────────────────────────────────────────────────── */

.attestation-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 12px;
    border-radius: 999px;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    background: var(--success-bg);
    color: var(--success);
    border: 1px solid var(--success);
    cursor: pointer;
    transition: background 0.15s, box-shadow 0.15s;
    white-space: nowrap;
}

.attestation-pill:hover {
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
    background: var(--success-hover-bg);
}

/* When unattested the pill uses a neutral muted style instead of green. */
.attestation-pill.is-unattested {
    background: var(--surface);
    color: var(--text-muted);
    border-color: var(--border);
}

.attestation-pill.is-unattested:hover {
    background: var(--accent-light);
    color: var(--text);
    border-color: var(--accent);
}

/* ─── Attestation modal (Phase 3e) ───────────────────────────────────────── */

.attestation-modal {
    max-width: 480px;
    width: 100%;
}

.attestation-input {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 6px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: var(--bg);
}

.attestation-input:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.attestation-textarea {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 6px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: var(--bg);
    resize: vertical;
}

.attestation-textarea:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.attestation-required {
    color: var(--error);
    margin-left: 2px;
}

.attestation-optional {
    font-weight: 400;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: 0;
    font-size: 11px;
}

.attestation-error {
    background: var(--error-bg);
    color: var(--error);
    border-radius: 4px;
    padding: 8px 10px;
    font-size: 13px;
    margin-bottom: 8px;
}

.attestation-form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.attestation-revoke-btn {
    color: var(--error);
    border-color: var(--error);
    margin-right: auto;
}

.attestation-revoke-btn:hover:not(:disabled) {
    background: var(--error-bg);
    box-shadow: none;
}

/* ─── Card-GUI ─────────────────────────────────────────────────────────────
   Card list — the primary edit surface. Mockup reference:
   tmp/editor-mockup-card-gui-260501.html.
   Design: docs/design/editor-overhaul-260501.md + editor-ux-redesign-260501.md §6.
*/

:root {
    --brand-green: #2d6a4f;
    --brand-green-hover: #1b4332;
    --col-h1: #1a56a0;
    --col-h2: #2563eb;
    --col-h3: #3b82f6;
    --col-p: #374151;
    --col-figure: #7c3aed;
    --col-caption: #92400e;
    --col-list: #0f766e;
    --col-li: #10b981;
    --col-table: #0e7490;
    --col-note: #9d174d;
    --col-link: #0369a1;
    --col-audio: #db2777;
    --col-video: #be185d;
    --col-formula: #7e22ce;
    --col-span: #6b7280;
    --col-artifact: #9ca3af;
}

/*
 * High-contrast palette — committed in docs/design/spa-a11y-editor-260430.md
 * §10.2: "When prefers-contrast: more is set, overlay squares get higher-
 * contrast colours." Triggers on Windows High Contrast Mode (forced colors
 * also map onto this query in modern browsers) and on macOS "Increase
 * contrast" + Linux equivalents. We swap the role-tinted backgrounds for
 * fully-saturated near-black-or-white pairs so badges and chips stay legible
 * when the OS over-rides hover/saturation effects. The role hue is preserved
 * via a thicker, higher-saturation border on overlay bboxes; the chip text
 * goes white-on-saturated for max contrast against the underlying surface.
 */
@media (prefers-contrast: more) {
    :root {
        --col-h1:       #001a4d;
        --col-h2:       #002a8c;
        --col-h3:       #1b3fbf;
        --col-p:        #111827;
        --col-figure:   #4c0d99;
        --col-caption:  #5a2400;
        --col-list:     #00524d;
        --col-li:       #006e3f;
        --col-table:    #00404d;
        --col-note:     #66062e;
        --col-link:     #002b66;
        --col-audio:    #99003d;
        --col-video:    #800033;
        --col-formula:  #4a008c;
        --col-span:     #1f2937;
        --col-artifact: #374151;
    }
    .editor-overlay-bbox {
        /* Bump border weight + remove translucent filter so the box stands
           out against any background a high-contrast user has chosen. */
        border-width: 3px;
    }
    .editor-overlay-bbox.is-selected {
        border-width: 4px;
    box-shadow: 0 0 0 3px var(--black);
    }
    .editor-overlay-rolebadge,
    .editor-card-typechip,
    .editor-card-issue-badge {
        /* Force opaque high-contrast badge surfaces. */
        text-shadow: none;
    outline: 1px solid var(--white);
    }
}

/* Card list container */
.editor-card-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px;
    user-select: text;
}

.editor-cards-empty {
    margin: 24px 16px;
    padding: 16px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
    font-style: italic;
}

.editor-card-para-edit-note {
    margin-top: 4px;
    font-size: 11px;
    font-style: italic;
    color: var(--text-muted);
}

.editor-card {
    display: flex;
    align-items: stretch;
    background: var(--white);
    border: 1.5px solid var(--gray-300);
    border-radius: 10px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .07), 0 0 0 1px rgba(0, 0, 0, .04);
    min-height: 56px;
    overflow: hidden;
    position: relative;
    transition: box-shadow .15s, border-color .15s, transform .1s;
    user-select: none;
}
.editor-card:hover { box-shadow: 0 3px 10px rgba(0, 0, 0, .09); }

.editor-card.is-expanded {
    box-shadow: 0 6px 20px rgba(0, 0, 0, .13), 0 0 0 2px var(--accent-color, #1a56a0);
    border-color: var(--accent-color, #1a56a0);
}

.editor-card.is-selected {
    border-width: 4px;
    border-color: var(--brand-green);
    box-shadow: 0 0 0 3px rgba(45, 106, 79, .35), 0 4px 12px rgba(45, 106, 79, .18);
    background: rgba(45, 106, 79, .08);
}

.editor-card.is-dragging { opacity: .45; transform: scale(.97); }
.editor-card.drag-over-above { border-top: 3px solid var(--brand-green); }
.editor-card.drag-over-below { border-bottom: 3px solid var(--brand-green); }

.editor-card.is-flash-card { animation: editor-flash-card .85s ease forwards; }
@keyframes editor-flash-card {
 0% { background: var(--white); box-shadow: 0 1px 4px rgba(0, 0, 0, .07); }
 15% { background: var(--blue-200); box-shadow: 0 0 0 4px rgba(26, 86, 160, .4); }
 70% { background: var(--blue-100); box-shadow: 0 0 0 2px rgba(26, 86, 160, .15); }
 100% { background: var(--white); box-shadow: 0 1px 4px rgba(0, 0, 0, .07); }
}

/* Drag handle (left strip) */
.editor-card-handle {
    flex: 0 0 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    border-right: 1px solid var(--gray-200);
    color: var(--gray-400);
    font-size: 13px;
    line-height: 1;
    letter-spacing: -2px;
    user-select: none;
    transition: background .1s, color .1s;
}
.editor-card-handle:hover { background: var(--blue-50); color: var(--accent-color, #1a56a0); }
.editor-card-handle:active { cursor: grabbing; }

/* Type-tinted color bar */
.editor-card-typebar { flex: 0 0 4px; background: var(--col-p); }
.editor-card[data-type="H1"]        .editor-card-typebar { background: var(--col-h1); }
.editor-card[data-type="H2"]        .editor-card-typebar { background: var(--col-h2); }
.editor-card[data-type="H3"]        .editor-card-typebar { background: var(--col-h3); }
.editor-card[data-type="H4"]        .editor-card-typebar,
.editor-card[data-type="H5"]        .editor-card-typebar,
.editor-card[data-type="H6"]        .editor-card-typebar { background: var(--col-h3); }
.editor-card[data-type="Paragraph"] .editor-card-typebar { background: var(--col-p); }
.editor-card[data-type="Figure"]    .editor-card-typebar { background: var(--col-figure); }
.editor-card[data-type="Caption"]   .editor-card-typebar { background: var(--col-caption); }
.editor-card[data-type="List"]      .editor-card-typebar { background: var(--col-list); }
.editor-card[data-type="ListItem"]  .editor-card-typebar { background: var(--col-li); }
.editor-card[data-type="Table"]     .editor-card-typebar { background: var(--col-table); }
.editor-card[data-type="Note"]      .editor-card-typebar { background: var(--col-note); }
.editor-card[data-type="Link"]      .editor-card-typebar { background: var(--col-link); }
.editor-card[data-type="Audio"]     .editor-card-typebar { background: var(--col-audio); }
.editor-card[data-type="Video"]     .editor-card-typebar { background: var(--col-video); }
.editor-card[data-type="Formula"]   .editor-card-typebar { background: var(--col-formula); }
.editor-card[data-type="Span"]      .editor-card-typebar { background: var(--col-span); }
.editor-card[data-type="Artifact"]  .editor-card-typebar { background: var(--col-artifact); }

.editor-card-body {
    flex: 1 1 auto;
    padding: 8px 12px 9px 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.editor-card-toprow {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    row-gap: 5px;
    min-width: 0;
}

/* Type chip — colored, role-tinted dropdown trigger. No chevron, no badge:
   role color + click affordance + popover-on-click is enough. */
.editor-card-typechip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-weight: 700;
    color: var(--white);
    padding: 3px 9px;
    border-radius: 4px;
    cursor: pointer;
    border: none;
    font-family: inherit;
    flex: 0 0 auto;
    background: var(--col-p);
    transition: filter .1s, box-shadow .1s;
}
.editor-card-typechip:hover { filter: brightness(1.12); }

/*
 * Reading-order chip on each card. Sits immediately to the right of
 * the type chip in the card's top row. Same shape as the overlay's
 * order chip so the user has consistent affordance language across
 * panes.
 */
.editor-card-order-chip {
    display: inline-flex;
    align-items: center;
    gap: 0;
    background: var(--white);
    border: 1.5px solid var(--gray-500);
    border-radius: 10px;
    padding: 0;
    height: 18px;
    line-height: 1;
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--gray-900);
    flex: 0 0 auto;
}
.editor-card-order-num {
    padding: 0 4px;
    min-width: 14px;
    text-align: center;
    color: inherit;
}
.editor-card-order-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 100%;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--gray-500);
    font-size: 9px;
    cursor: pointer;
    font-family: inherit;
}
.editor-card-order-arrow.up    { border-radius: 8px 0 0 8px; }
.editor-card-order-arrow.down  { border-radius: 0 8px 8px 0; }
.editor-card-order-arrow:hover { background: rgba(0, 0, 0, .08); color: var(--gray-900); }
.editor-card-order-arrow:focus-visible {
    outline: 2px solid var(--accent-color, #1a56a0);
    outline-offset: -2px;
}
.editor-card-typechip:focus {
    outline: none;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, .7), 0 0 0 4px var(--accent-color, #1a56a0);
}
.editor-card-typechip[data-role="H1"]       { background: var(--col-h1); }
.editor-card-typechip[data-role="H2"]       { background: var(--col-h2); }
.editor-card-typechip[data-role="H3"]       { background: var(--col-h3); }
.editor-card-typechip[data-role="P"]        { background: var(--col-p); }
.editor-card-typechip[data-role="Figure"]   { background: var(--col-figure); }
.editor-card-typechip[data-role="Caption"]  { background: var(--col-caption); }
.editor-card-typechip[data-role="L"]        { background: var(--col-list); }
.editor-card-typechip[data-role="LI"]       { background: var(--col-li); }
.editor-card-typechip[data-role="Table"]    { background: var(--col-table); }
.editor-card-typechip[data-role="Note"]     { background: var(--col-note); }
.editor-card-typechip[data-role="Link"]     { background: var(--col-link); }
.editor-card-typechip[data-role="Audio"]    { background: var(--col-audio); }
.editor-card-typechip[data-role="Video"]    { background: var(--col-video); }
.editor-card-typechip[data-role="Formula"]  { background: var(--col-formula); }
.editor-card-typechip[data-role="Span"]     { background: var(--col-span); }
.editor-card-typechip[data-role="Artifact"] { background: var(--col-artifact); }

/* Issue badge ("⚠ No alt text", "⚠ Loose caption") on cards */
.editor-card-issue-badge {
    font-size: 10px;
    font-weight: 600;
    color: var(--error-text);
    background: var(--error-bg-light);
    border: 1px solid var(--error-bg-hover);
    border-radius: 4px;
    padding: 2px 7px;
    cursor: pointer;
    font-family: inherit;
    flex: 0 0 auto;
    transition: background .12s, border-color .12s;
}
.editor-card-issue-badge:hover {
    background: var(--error-bg);
    border-color: var(--error-bg-hover);
}

/* Issue-explanation popover (anchored to a card's issue badge) */
.editor-issue-popover {
    position: fixed;
    z-index: 1000;
    width: 320px;
    max-width: 90vw;
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 12px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    font-size: 13px;
    line-height: 1.4;
}
.editor-issue-popover-message {
    color: var(--gray-700);
    margin-bottom: 8px;
}
.editor-issue-popover-fix {
    background: var(--gray-800);
    color: var(--white);
    border: none;
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    font-family: inherit;
}
.editor-issue-popover-fix:hover {
    background: var(--gray-900);
}

.editor-card-jump-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--gray-500);
    font-size: 13px;
    padding: 1px 4px;
    border-radius: 3px;
    margin-left: auto;
    flex: 0 0 auto;
    transition: color .1s, background .1s;
}
.editor-card-jump-btn:hover {
    color: var(--accent-color, #1a56a0);
    background: var(--bg-card-active);
}

/* Compact preview text */
.editor-card-preview {
    font-size: 12px;
    color: var(--gray-500);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    padding: 3px 6px;
    border-radius: 4px;
    transition: background .1s;
}
.editor-card-preview:hover {
    background: var(--blue-50);
    color: var(--accent-color, #1a56a0);
}
.editor-card-preview.is-empty-alt {
    color: var(--error-text);
    font-style: italic;
}

/* Expanded fields */
.editor-card-fields {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}
.editor-card-field-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .4px;
    color: var(--gray-500);
    margin-bottom: 1px;
}
.editor-card-field-note {
    font-size: 11px;
    color: var(--gray-400);
    font-style: italic;
}
.editor-card-text,
.editor-card-alt-text {
    font-family: inherit;
    font-size: 12px;
    border: 1px solid var(--gray-300);
    border-radius: 4px;
    padding: 5px 8px;
    background: var(--gray-100);
    color: var(--gray-900);
    width: 100%;
    resize: vertical;
    transition: border-color .1s, box-shadow .1s;
    user-select: text;
}
.editor-card-alt-text {
    min-height: 60px;
    max-height: 200px;
    overflow-y: auto;
}
.editor-card-text:focus,
.editor-card-alt-text:focus {
    outline: none;
    border-color: var(--accent-color, #1a56a0);
    box-shadow: 0 0 0 2px rgba(26, 86, 160, .15);
    background: var(--white);
}
.editor-card-decorative-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--gray-700);
    margin-top: 4px;
    cursor: pointer;
    user-select: none;
}

/* ─── Type popover (TEXT / VISUAL / MEDIA / OTHER) ───────────────────── */
.editor-type-popover {
    position: fixed;
    z-index: var(--z-type-popover);
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, .18);
    width: 320px;
    display: none;
    flex-direction: column;
    overflow: hidden;
    font-family: inherit;
    color: var(--gray-900);
}
.editor-type-popover.is-open { display: flex; }

.editor-type-popover-search { padding: 8px 10px 0; }
.editor-type-popover-search input {
    width: 100%;
    font-family: inherit;
    font-size: 12px;
    border: 1px solid var(--gray-300);
    border-radius: 5px;
    padding: 5px 10px;
    background: var(--gray-100);
    color: var(--gray-900);
}
.editor-type-popover-search input:focus {
    outline: none;
    border-color: var(--accent-color, #1a56a0);
    box-shadow: 0 0 0 2px rgba(26, 86, 160, .15);
}

.editor-type-popover-list {
    overflow-y: auto;
    max-height: 360px;
    padding: 4px 0;
}

.editor-type-section-header {
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .8px;
    color: var(--gray-400);
    padding: 8px 12px 3px;
    border-top: 1px solid var(--gray-200);
    margin-top: 2px;
    user-select: none;
    pointer-events: none;
}
.editor-type-section-header.is-first {
    border-top: none;
    margin-top: 0;
    padding-top: 6px;
}
.editor-type-section-header.hidden { display: none; }

.editor-type-option {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 7px 12px;
    cursor: pointer;
    transition: background .08s;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
}
.editor-type-option:hover,
.editor-type-option.is-active-item { background: var(--blue-50); }
.editor-type-option.is-current { background: var(--bg-card-active); }
.editor-type-option.hidden { display: none; }
.editor-type-option-chip {
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 700;
    color: var(--white);
    padding: 2px 7px;
    border-radius: 4px;
    margin-top: 1px;
    min-width: 54px;
    text-align: center;
    background: var(--col-p);
}
.editor-type-option-chip[data-role="H1"]       { background: var(--col-h1); }
.editor-type-option-chip[data-role="H2"]       { background: var(--col-h2); }
.editor-type-option-chip[data-role="H3"]       { background: var(--col-h3); }
.editor-type-option-chip[data-role="P"]        { background: var(--col-p); }
.editor-type-option-chip[data-role="Figure"]   { background: var(--col-figure); }
.editor-type-option-chip[data-role="Caption"]  { background: var(--col-caption); }
.editor-type-option-chip[data-role="L"]        { background: var(--col-list); }
.editor-type-option-chip[data-role="LI"]       { background: var(--col-li); }
.editor-type-option-chip[data-role="Table"]    { background: var(--col-table); }
.editor-type-option-chip[data-role="Note"]     { background: var(--col-note); }
.editor-type-option-chip[data-role="Link"]     { background: var(--col-link); }
.editor-type-option-chip[data-role="Audio"]    { background: var(--col-audio); }
.editor-type-option-chip[data-role="Video"]    { background: var(--col-video); }
.editor-type-option-chip[data-role="Formula"]  { background: var(--col-formula); }
.editor-type-option-chip[data-role="Span"]     { background: var(--col-span); }
.editor-type-option-chip[data-role="Artifact"] { background: var(--col-artifact); }
.editor-type-option-text { flex: 1 1 auto; min-width: 0; }
.editor-type-option-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--gray-900);
}
.editor-type-option-desc {
    font-size: 11px;
    color: var(--gray-500);
    line-height: 1.35;
    margin-top: 1px;
}

/* ─── Overlay: reading-order badge + alt-text tooltip ─────────────────── */
.editor-overlay-bbox.is-selected {
    outline: 4px solid var(--brand-green);
    outline-offset: -1px;
    box-shadow: 0 0 0 3px rgba(45, 106, 79, .45), 0 0 0 6px rgba(45, 106, 79, .18);
    z-index: var(--z-overlay-bbox-emphasis);
}
.editor-overlay-bbox.is-flash-overlay {
    animation: editor-flash-overlay .85s ease forwards;
}
@keyframes editor-flash-overlay {
    0%   { box-shadow: none; }
    15%  { box-shadow: 0 0 0 6px rgba(26, 86, 160, .6), inset 0 0 0 1000px rgba(26, 86, 160, .07); }
    70%  { box-shadow: 0 0 0 3px rgba(26, 86, 160, .2); }
    100% { box-shadow: none; }
}

.editor-overlay-order-badge {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--white);
    color: var(--gray-900);
    font-size: 11px;
    font-weight: 800;
    line-height: 22px;
    text-align: center;
    border: 2px solid currentColor;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    pointer-events: none;
    z-index: var(--z-overlay-badge);
    font-variant-numeric: tabular-nums;
}

.editor-overlay-alt-tooltip {
    position: absolute;
    left: 0;
    top: calc(100% + 6px);
    width: 280px;
    max-width: 90vw;
    background: rgba(17, 24, 39, .88);
    color: var(--gray-50);
    font-size: 11px;
    line-height: 1.45;
    padding: 7px 10px;
    border-radius: 5px;
    pointer-events: none;
    z-index: var(--z-overlay-tooltip);
    opacity: 0;
    transition: opacity .15s;
    white-space: normal;
    backdrop-filter: blur(4px);
}
.editor-overlay-alt-tooltip::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 16px;
    border: 5px solid transparent;
    border-bottom-color: rgba(17, 24, 39, .88);
}
.editor-overlay-alt-tooltip.is-visible { opacity: 1; }
/* Flip-above variant (set when overlay is near viewport bottom).
   Mockup ref: tmp/editor-mockup-card-gui-260501.html §.alt-tooltip-above. */
.editor-overlay-alt-tooltip.editor-overlay-alt-tooltip-above {
    top: auto;
    bottom: calc(100% + 6px);
}
.editor-overlay-alt-tooltip.editor-overlay-alt-tooltip-above::before {
    bottom: auto;
    top: 100%;
    border-bottom-color: transparent;
    border-top-color: rgba(17, 24, 39, .88);
}
.editor-overlay-alt-tooltip-label {
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--gray-400);
    margin-bottom: 3px;
}
.editor-overlay-alt-tooltip-empty {
    font-style: italic;
    color: var(--red-300);
}

/* ─── Feedback FAB + modal ────────────────────────────────────────────── */
.editor-feedback-fab {
    position: fixed;
    bottom: 24px;
    right: 24px;
    background: var(--brand-green);
    color: var(--white);
    border: none;
    border-radius: 50px;
    padding: 11px 20px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    box-shadow: 0 4px 16px rgba(45, 106, 79, .4), 0 1px 4px rgba(0, 0, 0, .18);
    z-index: var(--z-feedback-fab);
    transition: background .12s, box-shadow .12s, transform .1s;
}
.editor-feedback-fab:hover {
    background: var(--brand-green-hover);
    transform: translateY(-1px);
    box-shadow: 0 6px 20px rgba(45, 106, 79, .5), 0 2px 6px rgba(0, 0, 0, .2);
}
.editor-feedback-fab:active { transform: translateY(0); }

.editor-feedback-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .5);
    z-index: var(--z-feedback-backdrop);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 16px;
}
.editor-feedback-backdrop.is-open { display: flex; }

.editor-feedback-modal {
    background: var(--white);
    border-radius: 12px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .28), 0 4px 16px rgba(0, 0, 0, .12);
    width: 480px;
    max-width: 100%;
    padding: 28px 28px 22px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    color: var(--gray-900);
    font-family: inherit;
}
.editor-feedback-modal-title {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -.2px;
    color: var(--gray-900);
}
.editor-feedback-modal-subtitle {
    font-size: 13px;
    color: var(--gray-500);
    margin-top: -10px;
    line-height: 1.5;
}
.editor-feedback-modal-textarea {
    font-family: inherit;
    font-size: 14px;
    line-height: 1.5;
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 12px 14px;
    background: var(--white);
    color: var(--gray-900);
    width: 100%;
    resize: vertical;
    min-height: 120px;
    transition: border-color .12s, box-shadow .12s;
}
.editor-feedback-modal-textarea:focus {
    outline: none;
    border-color: var(--brand-green);
    box-shadow: 0 0 0 3px rgba(45, 106, 79, .15);
}
.editor-feedback-modal-toggles {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.editor-feedback-toggle-row {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--bg-near-white);
    border: 1px solid var(--gray-200);
    border-radius: 8px;
    padding: 10px 12px;
    cursor: pointer;
    transition: border-color .12s, background .12s;
}
.editor-feedback-toggle-row:hover {
    border-color: var(--gray-300);
    background: var(--bg-subtle-alt);
}
.editor-feedback-toggle-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.editor-feedback-toggle-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--gray-900);
}
.editor-feedback-toggle-desc {
    font-size: 12px;
    color: var(--gray-500);
    line-height: 1.4;
    margin-top: 1px;
}
.editor-feedback-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding-top: 4px;
}
.editor-feedback-modal-cancel {
    background: transparent;
    border: 1px solid transparent;
    border-radius: 7px;
    padding: 9px 16px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    color: var(--gray-500);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
}
.editor-feedback-modal-cancel:hover {
    background: var(--gray-100);
    border-color: var(--gray-300);
    color: var(--gray-900);
}
.editor-feedback-modal-send {
    background: var(--brand-green);
    color: var(--white);
    border: none;
    border-radius: 7px;
    padding: 9px 22px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, box-shadow .12s;
    box-shadow: 0 1px 3px rgba(45, 106, 79, .3);
}
.editor-feedback-modal-send:hover {
    background: var(--brand-green-hover);
    box-shadow: 0 2px 6px rgba(45, 106, 79, .4);
}
.editor-feedback-modal-send:disabled {
    opacity: .6;
    cursor: not-allowed;
}
.editor-feedback-modal-error {
    color: var(--error-text);
    background: var(--error-bg-light);
    border: 1px solid var(--error-bg-hover);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
}

/* ─── PR 1.5: Multi-select visuals ─────────────────────────────────────── */
/* Cards in a multi-selection: same brand-green family as single-select +
   a slight halo shift so the user can tell at a glance "this is part of a
   group" vs "this is the single focus". */
.editor-card.is-multi-selected {
    border-width: 4px;
    border-color: var(--brand-green);
    background: rgba(45, 106, 79, .10);
    box-shadow: 0 0 0 3px rgba(45, 106, 79, .25), 0 4px 10px rgba(45, 106, 79, .12);
}

/* Overlay multi-selection: heavier outline + dotted secondary border per
   UX memo §7.2. The dotted border makes the multi-state distinguishable
   from the single-select solid outline at a glance. */
.editor-overlay-bbox.is-multi-selected {
    outline: 4px solid var(--brand-green);
    outline-offset: -1px;
    box-shadow:
        0 0 0 3px rgba(45, 106, 79, .45),
        0 0 0 6px rgba(45, 106, 79, .18);
    /* `!important` is required because overlays.js writes the role-color
       background-color as an inline style; the multi-select tint must win
       over that inline value while the cards remain selected. */
    background-color: rgba(45, 106, 79, .18) !important;
    z-index: var(--z-overlay-bbox-emphasis);
}
.editor-overlay-bbox.is-multi-selected::after {
    content: "";
    position: absolute;
    inset: 2px;
    border: 2px dotted rgba(45, 106, 79, .85);
    pointer-events: none;
    border-radius: 1px;
}

/* ─── PR 1.5: Right-click context menu ────────────────────────────────── */
.editor-ctx-menu {
    position: fixed;
    z-index: var(--z-context-menu);
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 6px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, .15);
    min-width: 220px;
    padding: 4px 0;
    display: none;
    font-size: 13px;
}
.editor-ctx-menu.is-open { display: block; }

.editor-ctx-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 7px 14px;
    background: none;
    border: 0;
    cursor: pointer;
    font: inherit;
    text-align: left;
    white-space: nowrap;
}
.editor-ctx-item:hover {
    background: rgba(45, 106, 79, .08);
    color: var(--brand-green);
}
.editor-ctx-item.is-disabled {
    color: var(--gray-400);
    cursor: default;
}
.editor-ctx-item.is-disabled:hover {
    background: none;
    color: var(--gray-400);
}
.editor-ctx-item.is-danger {
    color: var(--error-text);
}
.editor-ctx-item.is-danger:hover {
    background: var(--error-bg-light);
    color: var(--error);
}

.editor-ctx-item-shortcut {
    font-size: 11px;
    color: var(--gray-500);
    font-variant-numeric: tabular-nums;
}
.editor-ctx-item-arrow {
    font-size: 10px;
    color: var(--gray-500);
}

.editor-ctx-sep {
    height: 1px;
    background: var(--gray-200);
    margin: 3px 0;
}

.editor-ctx-has-sub {
    position: relative;
}
.editor-ctx-submenu {
    position: absolute;
    top: -4px;
    left: 100%;
    min-width: 280px;
    max-height: 360px;
    overflow-y: auto;
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 6px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, .15);
    padding: 4px 0;
    display: none;
}
.editor-ctx-has-sub:hover .editor-ctx-submenu,
.editor-ctx-has-sub:focus-within .editor-ctx-submenu {
    display: block;
}

.editor-ctx-section-header {
    font-size: 10px;
    font-weight: 700;
    color: var(--gray-500);
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 8px 12px 3px;
    margin-top: 4px;
    border-top: 1px solid var(--gray-100);
}
.editor-ctx-section-header.is-first {
    border-top: 0;
    margin-top: 0;
}

.editor-ctx-type-option {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    width: 100%;
    padding: 6px 12px;
    background: none;
    border: 0;
    cursor: pointer;
    font: inherit;
    text-align: left;
}
.editor-ctx-type-option:hover {
    background: rgba(45, 106, 79, .08);
}
.editor-ctx-type-option.is-current {
    background: rgba(45, 106, 79, .12);
}
.editor-ctx-type-option-chip {
    flex: 0 0 36px;
    text-align: center;
    background: var(--gray-500);
    color: var(--white);
    font-size: 10px;
    font-weight: 700;
    padding: 2px 4px;
    border-radius: 3px;
    margin-top: 1px;
}
.editor-ctx-type-option-chip[data-role="H1"] { background: var(--col-h1); }
.editor-ctx-type-option-chip[data-role="H2"] { background: var(--col-h2); }
.editor-ctx-type-option-chip[data-role="H3"] { background: var(--col-h3); }
.editor-ctx-type-option-chip[data-role="P"]  { background: var(--col-p); }
.editor-ctx-type-option-chip[data-role="Figure"]  { background: var(--col-figure); }
.editor-ctx-type-option-chip[data-role="Caption"] { background: var(--col-caption); }

.editor-ctx-type-option-text {
    flex: 1 1 auto;
    min-width: 0;
}
.editor-ctx-type-option-name {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--gray-900);
}
.editor-ctx-type-option-desc {
    font-size: 11px;
    color: var(--gray-500);
    margin-top: 1px;
    line-height: 1.35;
}

/* ─── PR 1.5: Undo/Redo toast ──────────────────────────────────────────── */
.editor-undo-toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: var(--gray-800);
    color: var(--gray-100);
    padding: 9px 16px;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .25);
    opacity: 0;
    pointer-events: none;
    transition: opacity .18s, transform .22s;
    z-index: var(--z-toast);
    max-width: 70%;
}
.editor-undo-toast.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ─── PR 2: Multi-page continuous scroll ────────────────────────────────── */

.pdf-page-frame {
    background: var(--white);
    border: 1px solid var(--border-zinc);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
    margin: 0 auto;
    overflow: hidden;
}
.pdf-page-frame[data-zone="stub"] .pdf-page-stub {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--gray-400);
    font-size: 13px;
    font-style: italic;
    background: repeating-linear-gradient(
 45deg, var(--gray-50), var(--gray-50) 8px, var(--gray-100) 8px, var(--gray-100) 16px
    );
}
.pdf-page-frame[data-zone="canvas"] .pdf-page-stub,
.pdf-page-frame[data-zone="overlays"] .pdf-page-stub {
    display: none;
}
.pdf-page-label {
    text-align: center;
    color: var(--gray-500);
    font-size: 11px;
    padding: 4px 0 8px 0;
    user-select: none;
}

/* ─── PR 2: Insert flow (click-drag + right-click) ──────────────────────── */

.editor-insert-marquee {
    position: absolute;
    border: 2px dashed var(--gray-400);
    background: rgba(251, 191, 36, 0.08);
    pointer-events: none;
    box-sizing: border-box;
    z-index: var(--z-insert-marquee);
}
.editor-insert-marquee.is-snapped {
    border-color: var(--blue-600);
    background: rgba(37, 99, 235, 0.08);
}
/* Per-side snap cues — paint only the magnetized edge in brand-green so
   the user sees WHICH side latched (vs. the freeform yellow). Mockup ref:
   tmp/editor-mockup-card-gui-260501.html §.insert-rubberband.snap-{l,r,t,b}. */
.editor-insert-marquee.is-snapped-l {
    border-left-color: var(--brand-green);
    border-left-style: solid;
    box-shadow: -3px 0 0 0 rgba(45, 106, 79, 0.45);
}
.editor-insert-marquee.is-snapped-r {
    border-right-color: var(--brand-green);
    border-right-style: solid;
    box-shadow: 3px 0 0 0 rgba(45, 106, 79, 0.45);
}
.editor-insert-marquee.is-snapped-t {
    border-top-color: var(--brand-green);
    border-top-style: solid;
}
.editor-insert-marquee.is-snapped-b {
    border-bottom-color: var(--brand-green);
    border-bottom-style: solid;
}
/* When two or more sides snap at once, replace the per-side shadows with
   a uniform halo so the visual doesn't get noisy. */
.editor-insert-marquee.is-snapped-l.is-snapped-r,
.editor-insert-marquee.is-snapped-l.is-snapped-t,
.editor-insert-marquee.is-snapped-l.is-snapped-b,
.editor-insert-marquee.is-snapped-r.is-snapped-t,
.editor-insert-marquee.is-snapped-r.is-snapped-b,
.editor-insert-marquee.is-snapped-t.is-snapped-b {
    box-shadow: 0 0 0 2px rgba(45, 106, 79, 0.35);
}
.editor-insert-ctxmenu {
    background: var(--white);
    border: 1px solid var(--gray-300);
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    padding: 4px 0;
    z-index: var(--z-insert-ctxmenu);
    min-width: 180px;
}
.editor-insert-ctxmenu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    padding: 8px 14px;
    font-family: inherit;
    font-size: 13px;
    color: var(--gray-900);
    cursor: pointer;
}
.editor-insert-ctxmenu-item:hover { background: var(--gray-100); }

/* UNDEFINED-state overlay (newly inserted, awaiting type).
   `!important` is required because overlays.js writes the role-color
   border + background as inline styles; the UNDEFINED treatment must
   visually mark the bbox as still pending. */
.editor-overlay-bbox.is-undefined {
    border: 2px dashed var(--gray-400) !important;
    background: repeating-linear-gradient(
        45deg, rgba(251, 191, 36, 0.10), rgba(251, 191, 36, 0.10) 6px,
        transparent 6px, transparent 12px
    ) !important;
}
.editor-overlay-bbox.is-undefined .editor-overlay-order-badge::before,
.editor-overlay-bbox.is-undefined .editor-overlay-order-num::before {
    content: "?";
}
.editor-overlay-bbox.is-undefined .editor-overlay-order-badge,
.editor-overlay-bbox.is-undefined .editor-overlay-order-chip {
    color: var(--amber-700) !important;
    background: var(--warning-bg);
    border-color: var(--amber-400);
}

/* Save button blocked-state (Save while UNDEFINEDs exist) */
#editor-save-btn.is-blocked-undef {
    background: var(--amber-500);
    color: var(--amber-900);
    border-color: var(--amber-400);
}

/* UNDEFINED card — newly inserted, awaiting type. Mirrors the matching
   .editor-overlay-bbox.is-undefined treatment so the unresolved
   insertion is unmissable from either pane.
   Mockup ref: tmp/editor-mockup-card-gui-260501.html §.el-card.is-undefined. */
.editor-card.is-undefined {
    border-color: var(--yellow-600);
    background: var(--amber-50);
    box-shadow: 0 0 0 2px rgba(202, 138, 4, 0.25);
}
.editor-card.is-undefined .editor-card-typebar { background: var(--yellow-600); }
.editor-card.is-undefined .editor-card-typechip {
    background: var(--yellow-600);
    color: var(--white);
}
/* Undef-prompt block: replaces the compact preview on UNDEFINED cards.
   Same shape as the issue badge but slot-aware so the "Choose type"
   button is always visible — the user shouldn't have to hover or expand
   to discover the next action. */
.editor-card-undef-prompt {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 12px;
    font-weight: 600;
    color: var(--amber-900);
    background: var(--warning-bg);
    border: 1px solid var(--amber-200);
    border-radius: 6px;
    padding: 7px 10px;
    min-width: 0;
}
.editor-card-undef-prompt-icon { font-size: 14px; flex: 0 0 auto; }
.editor-card-undef-prompt-text { flex: 1 1 120px; min-width: 0; }
.editor-card-undef-choose-btn {
    margin-left: auto;
    background: var(--yellow-600);
    color: var(--white);
    border: none;
    border-radius: 4px;
    padding: 4px 12px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    flex: 0 0 auto;
}
.editor-card-undef-choose-btn:hover { background: var(--yellow-700); }
.editor-card-undef-choose-btn:focus-visible {
    outline: 2px solid var(--amber-900);
    outline-offset: 2px;
}

/* ─── PR 2: Screen-reader slide-over ────────────────────────────────────── */

.sr-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.18);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s ease;
    z-index: var(--z-screen-reader-backdrop);
}
.sr-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
}
.sr-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 380px;
    max-width: 90%;
    background: var(--white);
    border-left: 1px solid var(--gray-200);
    box-shadow: -4px 0 18px rgba(15, 23, 42, 0.12);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: var(--z-screen-reader-panel);
}
.sr-panel.is-open { transform: translateX(0); }
.sr-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-bottom: 1px solid var(--gray-200);
    background: var(--gray-50);
}
.sr-panel-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--gray-900);
}
.sr-close-btn {
    background: transparent;
    border: none;
    color: var(--gray-500);
    cursor: pointer;
    font-size: 14px;
}
.sr-panel-controls {
    display: flex;
    gap: 8px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--gray-200);
    align-items: center;
}
.sr-play-btn,
.sr-stop-btn,
.sr-verbose-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--gray-300);
    border-radius: 6px;
    background: var(--white);
    font-size: 12px;
    cursor: pointer;
    color: var(--gray-900);
}
.sr-play-btn:hover,
.sr-stop-btn:hover,
.sr-verbose-btn:hover { background: var(--gray-100); }
.sr-play-btn.is-playing { background: var(--blue-100); border-color: var(--blue-500); }
.sr-stop-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.sr-verbose-btn.is-skim { background: var(--blue-500); color: var(--white); border-color: var(--blue-600); }
.sr-verbose-btn.is-skim:hover { background: var(--blue-600); }
.sr-panel-status {
    padding: 6px 14px;
    color: var(--gray-500);
    font-size: 11px;
    min-height: 18px;
    border-bottom: 1px solid var(--gray-100);
}
.sr-transcript {
    flex: 1 1 auto;
    overflow-y: auto;
    margin: 0;
    padding: 8px 0;
    list-style: none;
    counter-reset: sr-line;
}
.sr-line {
    display: block;
    position: relative;
    padding: 6px 14px 6px 38px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--gray-900);
    cursor: pointer;
    border-left: 3px solid transparent;
    counter-increment: sr-line;
}
.sr-line::before {
    content: counter(sr-line);
    position: absolute;
    left: 8px;
    top: 6px;
    font-size: 10px;
    color: var(--gray-400);
    width: 22px;
    text-align: right;
}
.sr-line:hover { background: var(--gray-50); border-left-color: var(--gray-200); }
.sr-line.is-now-speaking { background: var(--blue-100); border-left-color: var(--blue-600); }
.sr-line-li { padding-left: 56px; }
.sr-line-li::before { left: 24px; }
.sr-line-undef { background: var(--warning-bg); border-left-color: var(--amber-400); }
/* Page section header in the cards pane — sticky, shows "Page N · M
   elements" and a "Scroll to page" jump button. Mockup ref:
   tmp/editor-mockup-card-gui-260501.html §.page-section-label +
   tmp/editor-mockup-multi-page-260501.html §.page-group-header. */
.editor-card-page-header {
    position: sticky;
    top: 0;
    background: var(--gray-100);
    border-top: 1px solid var(--gray-200);
    border-bottom: 1px solid var(--gray-200);
    padding: 5px 8px;
    margin: 6px -4px 4px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--gray-500);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    z-index: 5;
    user-select: none;
}
.editor-card-page-header:first-child { margin-top: 0; }
.editor-card-page-header-label { flex: 1; }
.editor-card-page-header-jump {
    background: none;
    border: none;
    color: var(--accent, #1a56a0);
    font-family: inherit;
    font-size: 10.5px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
    padding: 1px 4px;
    border-radius: 3px;
}
.editor-card-page-header-jump:hover {
    text-decoration: underline;
    background: var(--blue-50);
}
.editor-card-page-header-jump:focus-visible {
    outline: 2px solid var(--accent, #1a56a0);
    outline-offset: 1px;
}

/* Statusbar counts — element / issue / selection cells.
   Mockup ref: tmp/editor-mockup-card-gui-260501.html §statusbar. */
.editor-status-issue-count.has-issues {
    color: var(--error-text);
    font-weight: 600;
}
.editor-status-sel-count {
    color: var(--accent, #1a56a0);
    font-weight: 600;
}
.editor-status-sel-count:empty { display: none; }

/* SR transcript hover-mirror — when the user mouses over a transcript line
   the matching .editor-card on the right gets a thin accent outline so the
   cards-pane echoes which line is being read. Mockup ref:
   tmp/editor-mockup-card-gui-260501.html §.el-card.sr-hover-mirror. */
.editor-card.sr-hover-mirror {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Link card optional-description toggle. Mockup ref:
   tmp/editor-mockup-card-gui-260501.html §.link-add-desc-btn. */
.editor-card-link-add-desc-btn {
    align-self: flex-start;
    background: none;
    border: none;
    padding: 2px 0;
    font: inherit;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--accent, #1a56a0);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.editor-card-link-add-desc-btn:hover { color: var(--accent-hover, #134180); }
.editor-card-link-desc-block {
    margin-top: 4px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.sr-pre {
    font-weight: 600;
    color: var(--blue-600);
}
.sr-pre-warning { color: var(--amber-700); }
.sr-pre-error { color: var(--error-text); }
.sr-text { color: var(--gray-900); }
.sr-text-empty {
    color: var(--error-text);
    text-decoration: line-through;
    font-style: italic;
}
.sr-editable {
    border-bottom: 1px dotted var(--gray-400);
    cursor: text;
}
.sr-text.is-editing {
    outline: 2px solid var(--blue-600);
    background: var(--white);
    border-bottom-color: transparent;
    padding: 0 2px;
}
.sr-spacer { white-space: pre; }
.sr-panel.no-speech .sr-play-btn,
.sr-panel.no-speech .sr-stop-btn { display: none; }

/* Tri-directional flash classes used by screen-reader / cards / overlays
   when the user clicks a transcript line. The class lives ~600ms then
   self-removes via setTimeout. */
.flash-card {
    animation: sr-flash-card 0.55s ease-out;
}
.flash-ov {
    animation: sr-flash-ov 0.55s ease-out;
}
@keyframes sr-flash-card {
    0% { background-color: rgba(252, 211, 77, 0.55); }
    100% { background-color: transparent; }
}
@keyframes sr-flash-ov {
    0% { box-shadow: 0 0 0 6px rgba(252, 211, 77, 0.55); }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* Screen reader toggle button (cards-pane header) */
.cards-pane-sr-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border: 1px solid var(--gray-300);
    border-radius: 5px;
    background: var(--white);
    color: var(--gray-700);
    font-size: 12px;
    cursor: pointer;
}
.cards-pane-sr-toggle:hover { background: var(--gray-100); }
.cards-pane-sr-toggle.is-active {
    background: var(--blue-600);
    color: var(--white);
    border-color: var(--blue-600);
}

/* PR 2: SR toggle in pane header (id=editor-sr-toggle-btn). */
.editor-sr-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    letter-spacing: -0.2px;
    padding: 4px 10px;
    border: 1px solid var(--gray-300);
    border-radius: 4px;
    background: var(--white);
    color: var(--gray-700);
    cursor: pointer;
    white-space: nowrap;
}
.editor-sr-toggle-icon { flex: 0 0 auto; }
.editor-sr-toggle-label { font-weight: 500; }
.editor-sr-toggle-btn:hover { background: var(--gray-100); }
.editor-sr-toggle-btn.is-active {
    background: var(--blue-600);
    color: var(--white);
    border-color: var(--blue-600);
}

/* PR 2: Save button amber state when pending inserts block save. */
#editor-save-btn.is-save-blocked {
    background: var(--amber-500);
    color: var(--amber-900);
    border-color: var(--amber-400);
}

/* Skip-to-main-content link: visually hidden until keyboard-focused (a11y). */
.skip-link {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    z-index: 1000;
}
.skip-link:focus {
    position: fixed;
    left: 8px;
    top: 8px;
    width: auto;
    height: auto;
    padding: 8px 12px;
    background: var(--color-brand, #0d6efd);
    color: white;
    text-decoration: underline;
    border-radius: 4px;
}
