/* ── Jaws document renderer ─────────────────────────────────────── */

/* Canvas: the scrolling viewport that holds all pages */
.jaws-canvas {
    position: relative;
    overflow: auto;
    flex: 1;
    min-height: 0; /* Allow flex parent to constrain us */
    background: var(--bg-tertiary, #1a1a1a);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 24px 16px;
    gap: 16px;
}

.jaws-canvas-inner {
    transform-origin: top center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

/* Page: a single InDesign page at real dimensions */
.jaws-page {
    position: relative;
    background: #fff;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
    overflow: hidden;
    color: #000;
    font-family: 'Times New Roman', 'Georgia', serif;
    font-size: 12pt;
    line-height: 1.2;
}

.jaws-page-label {
    position: absolute;
    bottom: -20px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 11px;
    color: var(--text-muted, #888);
    white-space: nowrap;
    pointer-events: none;
}

/* Phantom page: invisible placeholder occupying one page slot in a single-page spread row.
   Keeps 2-page spread rows at uniform width so Spreads view aligns consistently.
   Width/height are set inline from the sibling real page's dimensions. */
.jaws-phantom-page {
    flex-shrink: 0;
}

/* Frame: absolute-positioned within a page */
.jaws-frame {
    position: absolute;
    box-sizing: border-box;
}

/* Text frame inner: respects columns, insets, and vertical alignment.
   overflow is visible (default) so that right-aligned runs whose glyphs
   extend past the frame's right edge (e.g. a trailing ')' that the frame
   box clips short of) still render — matches InDesign's default frame
   behavior. We deliberately do NOT use `overflow-x: visible; overflow-y:
   hidden;` to clip vertical overset: per CSS Overflow L3, a visible value
   on one axis with a non-visible value on the other computes to auto,
   which would create a scroll container and defeat the horizontal spill.
   The red '+' overset marker in TextFrame.razor is the dedicated signal
   for vertical overset; overset text in a slice is a threading bug, not
   a normal case (StoryView.razor routes text by character ranges). */
.jaws-text-frame-inner {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow: visible;
}

/* Graphic frame: bordered placeholder */
.jaws-graphic-frame {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 1px dashed var(--border-secondary, #555);
    background: var(--bg-secondary, #2a2a2a);
    overflow: hidden;
}

.jaws-graphic-frame-info {
    font-size: 9px;
    color: var(--text-muted, #888);
    text-align: center;
    padding: 4px;
    word-break: break-all;
    max-height: 100%;
    overflow: hidden;
}

.jaws-graphic-frame .jaws-link-status {
    font-size: 8px;
    padding: 1px 4px;
    border-radius: 2px;
    margin-top: 2px;
}

.jaws-link-status-ok {
    background: var(--accent-success, #2d7);
    color: #000;
}

.jaws-link-status-missing {
    background: var(--accent-danger, #d44);
    color: #fff;
}

.jaws-link-status-modified {
    background: var(--accent-warning, #da3);
    color: #000;
}

/* Group frame: just a container */
.jaws-group-frame {
    position: relative;
    width: 100%;
    height: 100%;
}

/* Unknown frame: labeled fallback */
.jaws-unknown-frame {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px dashed var(--accent-warning, #da3);
    background: rgba(218, 163, 51, 0.1);
    font-size: 10px;
    color: var(--accent-warning, #da3);
    text-align: center;
    padding: 4px;
}

/* Overset marker */
.jaws-overset-marker {
    position: absolute;
    bottom: 2px;
    right: 2px;
    width: 10px;
    height: 10px;
    background: var(--accent-danger, #d44);
    border-radius: 2px;
    font-size: 8px;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

/* Threading continuation marker */
.jaws-thread-marker {
    font-size: 10px;
    color: var(--text-muted, #888);
    font-style: italic;
    padding: 4px;
}

/* Paragraph */
.jaws-paragraph {
    margin: 0;
    padding: 0;
    /* min-height: 1lh keeps empty paragraphs (which contain only a "\n" run) at one
       line tall — matches InDesign's behavior of rendering empty paragraphs as a full
       line of leading. Non-empty paragraphs are unaffected because their content
       already exceeds 1lh. */
    min-height: 1lh;
}

/* Run */
.jaws-run {
    /* Inherits from paragraph and character style classes */
}

/* ── Tab cells (modes follow InDesign SDK TabStop::Alignment enum) ──
   0 = kTabAlignLeft, 1 = kTabAlignCenter, 2 = kTabAlignRight,
   3 = kTabAlignChar. One tab-cell span per '\t' character in the run
   text. Cell width is set inline to the mm gap to the previous tab
   (or to the paragraph's left indent for the first tab). Mode maps
   to text-align within the fixed-width cell. */
.jaws-tab-cell {
    display: inline-block;
    vertical-align: bottom;
    white-space: pre;
    /* default — overridden per mode */
}
.jaws-tab-mode-0 { text-align: left; }     /* kTabAlignLeft — InDesign default */
.jaws-tab-mode-1 { text-align: center; }   /* kTabAlignCenter */
.jaws-tab-mode-2 { text-align: right; }    /* kTabAlignRight */
.jaws-tab-mode-3 { text-align: left; }     /* kTabAlignChar — CSS fallback; JS adjusts in wf-03-3-alignchar */
.jaws-tab-mode-4 { text-align: left; }     /* unassigned in SDK 21.3.0.60 */

/* Leader characters rendered via ::before on the cell, prefixed to the
   cell's text. The cell's own text content is empty when the leader
   is rendered here — LeaderText in RunView.razor returns the leader
   string verbatim, and ::before takes precedence in the visual. For
   cells without a leader, [data-leader=""] matches and emits nothing. */
.jaws-tab-cell[data-leader]::before {
    content: attr(data-leader);
    color: inherit;
}

/* Inline table break in paragraph flow */
.jaws-inline-table-break {
    display: block;
    margin: 4px 0;
}

/* Visibility overlay for hidden items */
.jaws-hidden-overlay {
    opacity: 0.25;
}

.jaws-hidden-overlay::after {
    content: '';
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(
        -45deg,
        transparent,
        transparent 4px,
        rgba(255, 255, 255, 0.08) 4px,
        rgba(255, 255, 255, 0.08) 8px
    );
    pointer-events: none;
}

/* Lock badge */
.jaws-lock-badge {
    display: none;
    position: absolute;
    top: 2px;
    right: 2px;
    font-size: 10px;
    color: var(--text-muted, #888);
    pointer-events: none;
    z-index: 100;
}

.jaws-frame:hover > .jaws-lock-badge {
    display: block;
}

/* ── Selection ─────────────────────────────────────────────────── */

/* Hover highlight on selectable elements */
[data-jaws-id]:hover {
    outline: 1px dashed rgba(100, 180, 255, 0.4);
    outline-offset: -1px;
    cursor: pointer;
}

/* Selected element — color coded by kind */
.jaws-selected {
    outline: 2px solid var(--accent-primary, #4a9eff) !important;
    outline-offset: -1px;
}
.jaws-selected[data-jaws-kind="page"] { outline-color: #8b8b8b !important; }
.jaws-selected[data-jaws-kind="text-frame"] { outline-color: #4a9eff !important; }
.jaws-selected[data-jaws-kind="graphic-frame"] { outline-color: #b44aff !important; }
.jaws-selected[data-jaws-kind="group"] { outline-color: #ff9e4a !important; }
.jaws-selected[data-jaws-kind="paragraph"] { outline-color: #4aff9e !important; }
.jaws-selected[data-jaws-kind="run"] { outline-color: #ff4a9e !important; }
.jaws-selected[data-jaws-kind="table"] { outline-color: #ffd84a !important; }
.jaws-selected[data-jaws-kind="cell"] { outline-color: #4affd8 !important; }

/* ── Inspector panel ───────────────────────────────────────────── */

.jaws-inspector {
    width: 320px;
    min-width: 280px;
    flex-shrink: 0;
    background: var(--bg-secondary, #222);
    border-left: 1px solid var(--border-primary, #333);
    overflow-y: auto;
    font-size: 12px;
    color: var(--text-secondary, #bbb);
}

.jaws-inspector-empty {
    padding: 24px 16px;
    text-align: center;
    color: var(--text-muted, #666);
    font-style: italic;
}

.jaws-inspector-header {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-primary, #333);
    display: flex;
    align-items: center;
    gap: 8px;
}

.jaws-inspector-kind {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #888);
    background: var(--bg-tertiary, #1a1a1a);
    padding: 2px 6px;
    border-radius: 3px;
}

.jaws-inspector-id {
    font-family: monospace;
    font-size: 11px;
    color: var(--text-muted, #888);
    word-break: break-all;
}

.jaws-inspector-section {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-primary, #333);
}

.jaws-inspector-section-title {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #888);
    margin-bottom: 6px;
}

.jaws-inspector-row {
    display: flex;
    justify-content: space-between;
    padding: 2px 0;
    gap: 8px;
}

.jaws-inspector-label {
    color: var(--text-muted, #888);
    white-space: nowrap;
}

.jaws-inspector-value {
    color: var(--text-primary, #eee);
    text-align: right;
    word-break: break-all;
    font-family: monospace;
    font-size: 11px;
}

/* Breadcrumbs */
.jaws-inspector-breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    align-items: center;
}

.jaws-inspector-crumb {
    font-size: 11px;
    color: var(--text-secondary, #bbb);
}

.jaws-inspector-crumb-sep {
    font-size: 10px;
    color: var(--text-muted, #666);
    margin: 0 2px;
}

.jaws-inspector-crumb-link {
    cursor: pointer;
    text-decoration: underline;
    text-decoration-color: transparent;
    transition: text-decoration-color 0.15s;
}

.jaws-inspector-crumb-link:hover {
    text-decoration-color: var(--accent-primary, #4a9eff);
    color: var(--accent-primary, #4a9eff);
}

/* ── Document view layout ──────────────────────────────────────── */

.jaws-spread-row {
    display: flex;
    gap: 2px;
    justify-content: center;
    margin-bottom: 16px;
}

.jaws-outline-story {
    background: var(--bg-primary, #fff);
    color: var(--text-primary, #000);
    padding: 16px 24px;
    border-radius: 4px;
}

.jaws-pasteboard-item {
    opacity: 0.4;
    outline: 1px dashed var(--text-muted, #666);
    outline-offset: -1px;
}

.jaws-doc-view {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.jaws-doc-body {
    display: flex;
    flex: 1;
    min-height: 0; /* Critical: allows canvas to scroll internally */
    overflow: hidden;
}

/* ── Table rendering ───────────────────────────────────────────── */

.jaws-table {
    border-collapse: collapse;
    table-layout: fixed;
}

.jaws-table td,
.jaws-table th {
    border: 0.5px solid #999;
    padding: 1px 3px;
    /* vertical-align is set per-cell from TableCell.VerticalJustification
       (CellView.razor). Do not override here — the default 'top' would mask
       InDesign's default 'bottom' alignment for table cells. */
    vertical-align: top;
    font-size: 9pt;
    overflow: visible;
    word-wrap: break-word;
}

/* Cell vertical-alignment override: only applies when the per-cell inline
   style is absent (merged-away cells with no VerticalJustification). */
.jaws-table td[data-jaws-kind="cell"]:empty {
    vertical-align: bottom;
}

.jaws-table thead td,
.jaws-table thead th {
    font-weight: bold;
}

/* ── Revision overlay (OD-02) ──────────────────────────────────── */

/* The overlay host is a viewport-fixed layer over the canvas scroll
   container. pointer-events:none so the canvas DOM underneath remains
   clickable (selection, contextual toolbar). z-index 5 puts the overlay
   above pages (z=auto/0) but below the selection hover / contextual
   toolbar (z>=100) — the overlay must never intercept clicks. */
.jaws-revision-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
}

/* Per-status marker: outline + translucent fill. The class is
   .jaws-rev-{state} where {state} is one of pending | in_progress |
   applied | conflict | withdrawn. Default = pending (amber). */
.jaws-revision-marker {
    position: absolute;
    box-sizing: border-box;
    pointer-events: none;
    border-radius: 2px;
}

.jaws-revision-marker.jaws-rev-pending {
    outline: 2px solid #ffa500;
    background: rgba(255, 165, 0, 0.12);
}
.jaws-revision-marker.jaws-rev-in_progress {
    outline: 2px solid #4a9eff;
    background: rgba(74, 158, 255, 0.14);
}
.jaws-revision-marker.jaws-rev-applied {
    outline: 2px solid #2d7;
    background: rgba(45, 221, 119, 0.12);
}
.jaws-revision-marker.jaws-rev-conflict {
    outline: 2px solid #d44;
    background: rgba(221, 68, 68, 0.18);
}
.jaws-revision-marker.jaws-rev-withdrawn {
    outline: 2px solid #888;
    background: rgba(136, 136, 136, 0.10);
}

/* PP-24 / RM-02 — per-state `color` rules for the three marker
   geometry classes. The rules use the same hue vocabulary as the
   existing construct outline / fill rules; the `color` property is
   NOT directly applied to the marker (it stays invisible to the
   canvas behind), but it makes `currentColor` resolve to the
   state hue for the `box-shadow: currentColor` selection halo +
   the textrange inset underline. Without these rules, the
   existing construct rule's `is-selected` box-shadow halo renders
   a generic black ring (the comment above the original rule
   describes the intended behaviour; this is the missing
   implementation that closes the loop). Cheap, additive, three
   marker classes — no other elements in the document are
   affected by the scoped selectors. */
.jaws-revision-marker.jaws-rev-pending,
.jaws-revision-textrange.jaws-rev-pending,
.jaws-revision-caret.jaws-rev-pending     { color: #ffa500; }
.jaws-revision-marker.jaws-rev-in_progress,
.jaws-revision-textrange.jaws-rev-in_progress,
.jaws-revision-caret.jaws-rev-in_progress { color: #4a9eff; }
.jaws-revision-marker.jaws-rev-applied,
.jaws-revision-textrange.jaws-rev-applied,
.jaws-revision-caret.jaws-rev-applied     { color: #2d7; }
.jaws-revision-marker.jaws-rev-conflict,
.jaws-revision-textrange.jaws-rev-conflict,
.jaws-revision-caret.jaws-rev-conflict    { color: #d44; }
.jaws-revision-marker.jaws-rev-withdrawn,
.jaws-revision-textrange.jaws-rev-withdrawn,
.jaws-revision-caret.jaws-rev-withdrawn   { color: #888; }

/* PP-24 / RM-02 — sub-paragraph text-range markers. Same
   per-state colour vocabulary as the construct outline but a
   different visual treatment so reviewers can scan a paragraph and
   tell span highlights from full-paragraph outlines at a glance:

   - translucent fill (highlighter-pen style) instead of an outline
     so the modified words still read through;
   - thin coloured underline on the baseline (inset shadow) so the
     affected word picks up an emphasised bottom edge even when the
     fill blends with the page background.

   Multi-line highlights: the JS renders one rect div per
   `range.getClientRects()` line, all sharing this class. The fill
   is denser than the construct outline (0.30–0.40 vs 0.10–0.18) so
   the eye reads the highlight as a primary signal, with the
   underline carrying the secondary per-state colour cue.

   Type-driven colour override for text.delete: the revision TYPE
   (text.insert / text.delete / text.replace) drives the primary
   colour, state drives a secondary cue. The override uses
   [data-revision-type="text.delete"] selectors keyed on the JS-side
   `dataset.revisionType` so a delete op keeps its red identity
   regardless of pending vs in_progress vs applied — the per-state
   class still flips the underlying hue via the per-state rules
   above, but the type-driven rule later in the source wins.

   pointer-events:auto is set INLINE by the JS module on each marker
   div so the OD-06 click delegate fires; the base class omits it
   (the host overlay is pointer-events:none so the canvas substrate
   underneath remains clickable for selection in View mode). */
.jaws-revision-textrange {
    position: absolute;
    box-sizing: border-box;
    pointer-events: none;
    border-radius: 3px;
}

.jaws-revision-textrange.jaws-rev-pending {
    background: rgba(255, 165, 0, 0.38);
    box-shadow: inset 0 -2px 0 #ffa500;
}
.jaws-revision-textrange.jaws-rev-in_progress {
    background: rgba(74, 158, 255, 0.32);
    box-shadow: inset 0 -2px 0 #4a9eff;
}
.jaws-revision-textrange.jaws-rev-applied {
    background: rgba(45, 221, 119, 0.32);
    box-shadow: inset 0 -2px 0 #2d7;
}
.jaws-revision-textrange.jaws-rev-conflict {
    background: rgba(221, 68, 68, 0.40);
    box-shadow: inset 0 -2px 0 #d44;
}
.jaws-revision-textrange.jaws-rev-withdrawn {
    background: rgba(136, 136, 136, 0.28);
    box-shadow: inset 0 -2px 0 #888;
}

/* PP-24 / RM-05 — type-driven primary colour for text.delete.
   The red identity (bg + inset underline + soft red glow) must
   hold across all five per-state classes. Specificity (0,2,1) —
   combining the per-state class with the type attribute —
   beats the (0,2,0) per-state rules above without `!important`.
   The `.is-selected` selector below at (0,3,0) still wins the
   cascade for selection box-shadow, so selecting a text.delete
   revision shows the standard selection halo on top of the red
   identity. */
.jaws-revision-textrange.jaws-rev-pending[data-revision-type="text.delete"],
.jaws-revision-textrange.jaws-rev-in_progress[data-revision-type="text.delete"],
.jaws-revision-textrange.jaws-rev-applied[data-revision-type="text.delete"],
.jaws-revision-textrange.jaws-rev-conflict[data-revision-type="text.delete"],
.jaws-revision-textrange.jaws-rev-withdrawn[data-revision-type="text.delete"] {
    background: rgba(221, 68, 68, 0.38);
    box-shadow:
        inset 0 -2px 0 #d44,
        0 0 8px 0 rgba(221, 68, 68, 0.35);
}

/* PP-24 / RM-07 — type-driven teal for text.replace. Same specificity
   pattern as the text.delete rule above (0,2,1): per-state class +
   type attribute. Teal reads distinct from the existing red (delete)
   and green (insert) so a scan of a marked-up paragraph makes the
   three text-level types pop apart. Selection halo (`.is-selected`,
   0,3,0) still wins for box-shadow on top of the type-driven rule.
   Hex anchored at one block so palette review can tune without
   touching individual rules. */
.jaws-revision-textrange.jaws-rev-pending[data-revision-type="text.replace"],
.jaws-revision-textrange.jaws-rev-in_progress[data-revision-type="text.replace"],
.jaws-revision-textrange.jaws-rev-applied[data-revision-type="text.replace"],
.jaws-revision-textrange.jaws-rev-conflict[data-revision-type="text.replace"],
.jaws-revision-textrange.jaws-rev-withdrawn[data-revision-type="text.replace"] {
    background: rgba(20, 184, 166, 0.38);
    box-shadow:
        inset 0 -2px 0 #14b8a6,
        0 0 8px 0 rgba(20, 184, 166, 0.35);
}

/* PP-24 / RM-07 — type-driven purple for the run family
   (`[data-revision-type^="char."]` covers char.bold, char.italic,
   char.color, …; `[data-revision-type="style.character"]` covers the
   single non-prefixed member of the family). Specificity (0,2,1)
   same as the rules above — per-state + type attribute — beats the
   per-state (0,2,0) base rules without `!important`. Selection halo
   wins via the (0,3,0) rule below.

   Run-family revisions never produce carets (collapsed ranges only
   come from text.insert in the locked taxonomy), so the run-family
   palette is intentionally scoped to `.jaws-revision-textrange` and
   not `.jaws-revision-caret`. The existing text.insert caret rule
   remains the caret's only type-driven override.

   Hex anchored at one block (Tailwind purple-500 / teal-500 in the
   matching rules). Palette review can tune these without touching
   per-state geometry. */
.jaws-revision-textrange.jaws-rev-pending[data-revision-type^="char."],
.jaws-revision-textrange.jaws-rev-in_progress[data-revision-type^="char."],
.jaws-revision-textrange.jaws-rev-applied[data-revision-type^="char."],
.jaws-revision-textrange.jaws-rev-conflict[data-revision-type^="char."],
.jaws-revision-textrange.jaws-rev-withdrawn[data-revision-type^="char."],
.jaws-revision-textrange.jaws-rev-pending[data-revision-type="style.character"],
.jaws-revision-textrange.jaws-rev-in_progress[data-revision-type="style.character"],
.jaws-revision-textrange.jaws-rev-applied[data-revision-type="style.character"],
.jaws-revision-textrange.jaws-rev-conflict[data-revision-type="style.character"],
.jaws-revision-textrange.jaws-rev-withdrawn[data-revision-type="style.character"] {
    background: rgba(168, 85, 247, 0.38);
    box-shadow:
        inset 0 -2px 0 #a855f7,
        0 0 8px 0 rgba(168, 85, 247, 0.35);
}

/* PP-24 / RM-02 / RM-05 — caret markers. A 5-pixel-wide vertical bar
   standing at the paragraph-local story offset of a text.insert
   op's collapsed locator. The JS computes width + height +
   left/top explicitly via the collapsed Range's
   `getBoundingClientRect()` (so the bar extends slightly above
   and below the line and is shifted left by half its width so
   its CENTRE sits on the insertion boundary — that way it never
   visually overlaps the letter that comes immediately after
   the insert point). `min-width: 5px` is just a defensive floor
   so any legacy positions that arrive with width<5 don't render
   as a hairline.

   Per-state colour: solid (not translucent) so the bar reads as a
   precise point on the text baseline. Text.insert drives the
   primary colour via [data-revision-type="text.insert"] below;
   non-insert revisions (none in the locked taxonomy, but kept
   safe) fall back to the per-state hue. */
.jaws-revision-caret {
    position: absolute;
    box-sizing: border-box;
    pointer-events: none;
    width: 5px;
    min-width: 5px;
    border-radius: 1px;
}

.jaws-revision-caret.jaws-rev-pending     { background: #ffa500; }
.jaws-revision-caret.jaws-rev-in_progress { background: #4a9eff; }
.jaws-revision-caret.jaws-rev-applied     { background: #2d7; }
.jaws-revision-caret.jaws-rev-conflict    { background: #d44; }
.jaws-revision-caret.jaws-rev-withdrawn   { background: #888; }

/* PP-24 / RM-05 — type-driven primary colour for text.insert.
   Green caret with a soft glow so the insert point reads
   unmistakably against both light and dark page backgrounds.
   Specificity (0,2,1) — combining the per-state class with the
   type attribute — beats the (0,2,0) per-state caret rules above
   without `!important`. The `.is-selected` selector below at
   (0,3,0) still wins for selection box-shadow. */
.jaws-revision-caret.jaws-rev-pending[data-revision-type="text.insert"],
.jaws-revision-caret.jaws-rev-in_progress[data-revision-type="text.insert"],
.jaws-revision-caret.jaws-rev-applied[data-revision-type="text.insert"],
.jaws-revision-caret.jaws-rev-conflict[data-revision-type="text.insert"],
.jaws-revision-caret.jaws-rev-withdrawn[data-revision-type="text.insert"] {
    background: #2d7;
    box-shadow: 0 0 6px 1px rgba(45, 221, 119, 0.6);
}

/* OD-06 — `is-selected` modifier on construct-outline markers. The
   host pushes the focused revision id; the JS module tags matching
   markers with this class. The visual is a thicker outline + a glow
   that reads across all statuses (the underlying state colour still
   drives the hue). Mirrors the .is-selected treatment on the list
   row so the canvas-side highlight agrees with the drawer-side.
   PP-24 / RM-02 — the text-range and caret variants use a separate
   rule below; the geometry of those highlights (translucent fill /
   thin bar) makes an outline-based selection modifier hard to read. */
.jaws-revision-marker.is-selected {
    outline-width: 3px;
    outline-offset: -1px;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.45),
                0 0 12px 2px currentColor;
}

/* PP-24 / RM-02 — the selection modifier on text-range / caret
   variants is a glow on the same `currentColor` vocabulary as the
   construct outline's rule, but expressed as a stronger outer halo
   + an inset ring so it reads on top of the translucent fill / bar.
   The glow is the same hue as the underlying state colour (because
   `currentColor` is driven by the `jaws-rev-{state}` class), so the
   selected highlight stays consistent across the three geometry
   variants. */
.jaws-revision-textrange.is-selected,
.jaws-revision-caret.is-selected {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.55),
        0 0 14px 2px currentColor;
}
.jaws-revision-textrange.is-selected {
    /* Re-declare the inset underline on top of the layered shadow so
       the state colour stays visible through the selection glow. */
    box-shadow:
        inset 0 -2px 0 currentColor,
        0 0 0 1px rgba(255, 255, 255, 0.55),
        0 0 14px 2px currentColor;
}

/* IS-05 — Edit mode click yield. When the host is in Edit mode
   (TM-01 toggle), the JS module sets `jaws-overlay-edit` on the
   overlay host; this rule makes all overlay markers
   click-transparent so the canvas selection substrate sees the
   click. Without `!important` the JS-side inline
   `style.pointerEvents = 'auto'` (the OD-06 marker affordance)
   wins and the marker still intercepts. The per-page change-bars
   are NOT matched (they live in the page margin, outside the
   text rect) so they retain their click affordance in both modes.
   Marker visuals are unchanged — the reviewer still SEES what has
   revisions; only hit-testing changes. PP-24 / RM-02 — the
   selector now covers all three marker classes so Edit mode
   yields construct outlines, text-range highlights, AND caret
   markers uniformly. */
.jaws-overlay-edit .jaws-revision-marker,
.jaws-overlay-edit .jaws-revision-textrange,
.jaws-overlay-edit .jaws-revision-caret {
    pointer-events: none !important;
}

/* PP-10 — "no draft round" banner. Renders inside the overlay host
   (position:absolute; inset:0) when the loaded rounds set has ≥1
   round but no draft round (the overlay is draft-only by spec, so
   the canvas would otherwise be silently empty while the revisions
   list shows the history rows). Top-center, muted background —
   the same colour vocabulary as .jaws-revision-list-empty so the
   two empty states read as one. pointer-events:none + z-index 6
   (above the marker layer at z:5, below the toolbar at z>=100) so
   it never intercepts clicks and the JS-side marker rendering
   stays authoritative. The data attribute is the test seam. */
.jaws-overlay-no-draft {
    position: absolute;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    padding: 6px 12px;
    background: rgba(40, 40, 40, 0.92);
    border: 1px solid var(--border-primary, #333);
    border-radius: 4px;
    color: var(--text-muted, #888);
    font-size: 11px;
    line-height: 1.4;
    pointer-events: none;
    z-index: 6;
    max-width: 80%;
    text-align: center;
    white-space: nowrap;
}

/* Per-page change-bar: a vertical bar in the page's left gutter. The
   JS module positions it at the page's left edge - 6px (so it sits
   clearly outside the page's box-shadow). 4px wide, full page height.
   Same per-status colors as the markers. */
.jaws-revision-changebar {
    position: absolute;
    box-sizing: border-box;
    pointer-events: none;
    border-radius: 1px;
}

.jaws-revision-changebar.jaws-rev-pending {
    background: #ffa500;
}
.jaws-revision-changebar.jaws-rev-in_progress {
    background: #4a9eff;
}
.jaws-revision-changebar.jaws-rev-applied {
    background: #2d7;
}
.jaws-revision-changebar.jaws-rev-conflict {
    background: #d44;
}
.jaws-revision-changebar.jaws-rev-withdrawn {
    background: #888;
}

/* Detached marker: small tag in the canvas gutter. The JS module
   positions these in a top-down stack at the overlay's top-left.
   Dashed border so it reads as 'not on canvas'. */
.jaws-revision-marker.jaws-revision-detached {
    border-style: dashed;
    border-width: 1px;
}

/* ── PP-24 / RM-03 — callout + leader + grouped hover ────────────
   The callout is a fixed-width box that surfaces a sub-paragraph
   text revision's payload (verb + struck-old + emphasised-new +
   italic reviewer note) on hover. The leader is a 1px SVG line
   joining the callout's nearest edge to the marker's nearest edge
   — the visual cue a printed proof uses to point a marginal note
   at a specific word.

   Default state (no hover): both hidden. The `.jaws-revision-hover-
   group` class on every element sharing the marker's
   `data-revision-id` reveals them; the JS module (RM-03) toggles
   that class on every mouseover / mouseout transition.

   Z-order on the overlay: markers (z:5) → leader (z:6) → callout
   (z:7) → toolbar (z>=100). The callout must be above the leader
   so the box hides the line endpoint, and the leader above the
   markers so the line stays visible when it crosses near a marker
   edge. */

/* Callout: anchored to the first fragment's right edge, positioned
   above by default (flipped below if it would clip the overlay
   top — see positionCalloutLeader in the JS module). The width is
   fixed at 200px in the JS (`CALLOUT_WIDTH_PX`); the height is
   measured at render time. */
.jaws-revision-callout {
    position: absolute;
    box-sizing: border-box;
    width: 200px;
    max-width: 240px;
    padding: 8px 10px;
    background: rgba(30, 30, 30, 0.96);
    border: 1px solid var(--border-primary, #444);
    border-radius: 4px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
    color: var(--text-primary, #eee);
    font-size: 11px;
    line-height: 1.4;
    pointer-events: none;        /* hidden state — let the marker behind catch mouse */
    z-index: 7;                  /* above the leader (6) and markers (5) */
    opacity: 0;
    transition: opacity 0.1s ease;
}

/* Reveal on grouped hover. The JS toggles this class on every
   element sharing the marker's data-revision-id (the marker
   fragments, the callout, the leader) so a single mouseover on
   one fragment shows the callout + leader + emphasised group. */
.jaws-revision-callout.jaws-revision-hover-group {
    opacity: 1;
    pointer-events: auto;        /* hovering the callout must keep the group alive */
}

/* Verb: small uppercase label at the top of the callout — matches
   the visual vocabulary of the per-page change-bar / status badges
   so the three surfaces read as one. */
.jaws-revision-callout-verb {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #888);
    margin-bottom: 4px;
}

/* Text body: the old→new payload. Replace shows both, with an
   arrow between; insert shows only the new text; delete shows
   only the old text (struck). The per-kind visibility is driven
   by the callout's [data-change-kind] attribute so the markup
   stays the same and only the visible spans differ. */
.jaws-revision-callout-text {
    font-size: 12px;
    line-height: 1.5;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

/* PP-24 / RM-09 — compact callout for show-all mode. The marker
   swatch + callout colour already convey the verb, so the header
   is redundant when every callout is on screen at once; dropping
   it + shrinking each box to its content (capped at 200px = the
   fixed CALLOUT_WIDTH_PX used in full mode) keeps the dense
   all-on view from burying the document. JS positions the box +
   leader against its measured offsetWidth so the right edge and
   leader centre stay aligned at the variable width. Single-hover
   (no .jaws-callouts-show-all on the overlay host) keeps the
   full 200px + verb header. */
.jaws-callouts-show-all .jaws-revision-callout {
    width: max-content;
    max-width: 200px;
}
.jaws-callouts-show-all .jaws-revision-callout-verb {
    display: none;
}

.jaws-revision-callout-old {
    text-decoration: line-through;
    color: #ffb8b8;
    background: rgba(255, 112, 112, 0.10);
    padding: 0 2px;
    border-radius: 2px;
}

.jaws-revision-callout-arrow {
    color: var(--text-muted, #888);
    padding: 0 4px;
}

.jaws-revision-callout-new {
    color: #b8e6bb;
    background: rgba(76, 175, 80, 0.12);
    padding: 0 2px;
    border-radius: 2px;
}

.jaws-revision-callout-empty {
    color: var(--text-muted, #888);
    font-style: italic;
}

/* PP-24 / RM-08 — format-revision callout body. The resolver emits
   `callout.formatSummary` for char.* / style.character revisions
   (e.g. "Bold", "24 pt", "Colour"); the JS module splits the body
   into a muted "Format:" prefix and a primary value span so the
   reviewer can scan the format details at a glance without
   confusing them with the old→new text the text family uses.
   The value span carries the same per-type colour vocabulary as
   the marker / leader so a format callout reads as one visual:
   verb ("BOLD") → "Format:" → value ("24 pt") in the type's hue.
   Specificity (0,1,1) on the per-type rules beats the (0,1,0)
   base. No !important — the base `color` is the fallback for
   callouts whose revisionType doesn't match a type-driven rule. */
.jaws-revision-callout-format-label {
    color: var(--text-muted, #888);
    margin-right: 4px;
}

.jaws-revision-callout-format-value {
    color: currentColor; /* inherits from per-state jaws-rev-{state} */
    font-weight: 600;
}

.jaws-revision-callout[data-revision-type="text.insert"] .jaws-revision-callout-format-value { color: #2d7; }
.jaws-revision-callout[data-revision-type="text.delete"] .jaws-revision-callout-format-value { color: #d44; }
.jaws-revision-callout[data-revision-type="text.replace"] .jaws-revision-callout-format-value { color: #14b8a6; }
.jaws-revision-callout[data-revision-type^="char."] .jaws-revision-callout-format-value,
.jaws-revision-callout[data-revision-type="style.character"] .jaws-revision-callout-format-value { color: #a855f7; }

/* Insert-only and delete-only collapse the unused side so a
   text.insert callout shows just the new text (no struck-old,
   no arrow), and a text.delete shows just the old text. */
.jaws-revision-callout[data-change-kind="insert"] .jaws-revision-callout-old,
.jaws-revision-callout[data-change-kind="insert"] .jaws-revision-callout-arrow {
    display: none;
}
.jaws-revision-callout[data-change-kind="delete"] .jaws-revision-callout-new,
.jaws-revision-callout[data-change-kind="delete"] .jaws-revision-callout-arrow {
    display: none;
}

/* Note: the reviewer's free-text annotation, separated by a thin
   border so the visual hierarchy is verb / payload / note. Only
   renders when entry.callout.note is non-empty (the JS module
   omits the element otherwise — the CSS is a defensive fallback
   for empty note text). */
.jaws-revision-callout-note {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--border-primary, #333);
    font-size: 11px;
    color: var(--text-secondary, #bbb);
    font-style: italic;
    line-height: 1.4;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

/* Leader: 1px SVG line in `currentColor` so the per-state colour
   (jaws-rev-{state} class sets the value) flows through. The SVG
   itself is positioned at the leader's bounding box; the line's
   x1/y1/x2/y2 are set per-render to the callout's nearest-edge
   center and the marker's nearest-edge center. PP-24 / RM-08 — the
   leader now wears the per-TYPE colour (insert / delete / replace /
   formatting) instead of the per-state hue, so the line and the
   marker it points to share an identity. Without a default `color`
   the SVG inherits from the parent overlay (typically undefined),
   leaving the stroke black-on-dark or invisible — the default
   below sets a safe accent for any callout that hasn't been styled
   by a type-driven rule. The type-driven rules are scoped to the
   data-revision-type attribute the JS module stamps on the SVG at
   build time. */
.jaws-revision-leader {
    position: absolute;
    pointer-events: none;        /* line is a visual aid, not interactive */
    overflow: visible;           /* the 1px stroke needs 0.5px on each side of the path */
    z-index: 6;                  /* above markers (5), below callout (7) */
    opacity: 0;
    color: var(--accent-primary, #4a9eff); /* fallback when no type-driven rule matches */
    transition: opacity 0.1s ease;
}

.jaws-revision-leader.jaws-revision-hover-group {
    opacity: 1;
}

/* PP-24 / RM-08 — type-driven leader colour matching the marker
   palette (RM-07). Specificity (0,1,1) — element + attribute —
   beats the (0,1,0) base rule without `!important`. Each rule
   uses the same hex as the marker's `box-shadow: inset 0 -2px 0`
   and the soft outer glow, so a hover-group callout reads as one
   connected visual: marker fill → leader stroke → callout accent.
   Hover-group / selection halo on the marker still wins the
   cascade for box-shadow because those rules are scoped at
   (0,2,0) / (0,3,0) — `color` only affects the leader's stroke
   and the marker halo's `currentColor`. */
.jaws-revision-leader[data-revision-type="text.insert"] { color: #2d7; }
.jaws-revision-leader[data-revision-type="text.delete"] { color: #d44; }
.jaws-revision-leader[data-revision-type="text.replace"] { color: #14b8a6; }
.jaws-revision-leader[data-revision-type^="char."],
.jaws-revision-leader[data-revision-type="style.character"] { color: #a855f7; }

/* Grouped-hover emphasis on the markers themselves. The class is
   toggled on every element sharing the marker's
   data-revision-id, so a single mouseover on a wrapped text-range
   fragment highlights every fragment of the same change with the
   same glow. The `currentColor` vocabulary is the same one the
   per-state rules above use, so the hue stays consistent with the
   marker's resting state. The base outline width is unchanged;
   only the outer glow is amplified, so the marker still reads as
   a marker — just "emphatically the same marker as the others". */
.jaws-revision-textrange.jaws-revision-hover-group,
.jaws-revision-caret.jaws-revision-hover-group {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.55),
        0 0 16px 3px currentColor;
}

/* Text-range + hover-group: re-declare the inset underline on top
   of the layered shadow so the per-state colour stays visible
   through the hover glow. Without this re-declaration the
   layered shadows would override the inset shadow from the
   per-state rules above. */
.jaws-revision-textrange.jaws-revision-hover-group {
    box-shadow:
        inset 0 -2px 0 currentColor,
        0 0 0 1px rgba(255, 255, 255, 0.55),
        0 0 16px 3px currentColor;
}

/* Edit mode click-yield must extend to the callout + leader. The
   existing rule covers the three marker classes; the callout /
   leader also need to be click-transparent in Edit mode so the
   canvas selection substrate sees the click. The leader already
   has pointer-events:none; the callout is the new vector. The
   class-on-host selector mirrors the existing pattern so the rule
   is mode-conditional. */
.jaws-overlay-edit .jaws-revision-callout {
    /* PP-32 / CB-01 — callouts stay click-transparent in Edit mode (the
       canvas selection substrate sees the click) but DO reveal on hover /
       show-all now. Removing the prior `opacity:0 !important` reverses the
       earlier "callouts are noise while editing" decision — the reviewer
       wants revision context while editing. */
    pointer-events: none !important;
}

.jaws-snapshot-picker {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 1000;
    min-width: 240px;
    max-height: 300px;
    overflow-y: auto;
    background: var(--bg-secondary, #222);
    border: 1px solid var(--border-primary, #333);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
    margin-top: 4px;
}

.jaws-snapshot-picker-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 12px;
    font-size: 12px;
    color: var(--text-secondary, #bbb);
    text-decoration: none;
    border-bottom: 1px solid var(--border-primary, #333);
    cursor: pointer;
    gap: 12px;
}

.jaws-snapshot-picker-item:hover {
    background: var(--bg-tertiary, #1a1a1a);
    color: var(--text-primary, #eee);
}

.jaws-snapshot-picker-item:last-child {
    border-bottom: none;
}

.jaws-snapshot-picker-active {
    background: rgba(74, 158, 255, 0.1);
    color: var(--accent-primary, #4a9eff);
}

/* ── Revisions list (OD-03) — right-drawer tab ──────────────────────── */

/* The list lives in a right-hand drawer (a thin column next to the
   inspector). Width is fixed so the canvas doesn't reflow when the
   list grows; scroll happens inside the list. */
.jaws-revision-list-drawer {
    display: flex;
    flex-direction: column;
    width: 320px;
    flex-shrink: 0;
    border-left: 1px solid var(--border-primary, #333);
    background: var(--bg-secondary, #1e1e1e);
    min-height: 0;
    overflow: hidden;
}

.jaws-revision-list {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

/* Header: drawer tab title + per-state counts. The conflict count
   gets a red tint when > 0 so the reviewer sees it from across
   the room. */
.jaws-revision-list-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px 8px;
    border-bottom: 1px solid var(--border-primary, #333);
    flex-shrink: 0;
}

.jaws-revision-list-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-primary, #eee);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    display: flex;
    align-items: center;
    gap: 6px;
}

.jaws-revision-list-counts {
    display: flex;
    gap: 6px;
    font-size: 11px;
}

.jaws-revision-list-count {
    padding: 2px 6px;
    border-radius: 10px;
    background: var(--bg-tertiary, #1a1a1a);
    color: var(--text-muted, #888);
    min-width: 18px;
    text-align: center;
}

.jaws-revision-list-count.has-conflicts {
    background: rgba(220, 80, 80, 0.2);
    color: #ff8080;
}

/* PP-24 / RM-04 — "show all change tips" toggle. A single tiny
   icon-only checkbox at the right end of the list header — no
   label, no border, no padding; just a 14×14 native box that
   inherits the header's vertical alignment. The label wraps the
   input so the entire 14×14 hit area registers the click. The
   6px left-margin separates it from the count badge block; the
   muted text colour on the input's check accent (the browser's
   default for an unchecked checkbox on a dark background) keeps
   it reading as a quiet control without an explicit accent rule.
   The aria-label + title attributes carry the semantics / tooltip
   so the visible affordance stays at one glyph. */
.jaws-revision-list-show-all {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    cursor: pointer;
}

.jaws-revision-list-show-all input[type="checkbox"] {
    margin: 0;
    padding: 0;
    cursor: pointer;
    /* The browser's default checkbox is ~13px; one tiny bump so
       it reads at 14px and stays clickable at the panel's
       cramped 360px width. No background / border / accent
       rules — the native widget on a dark panel reads as a
       single muted box, which is the design intent. */
    width: 14px;
    height: 14px;
    accent-color: var(--accent-primary, #4a9eff);
}

/* Sort selector: a small dropdown next to the header. */
.jaws-revision-list-sort {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border-primary, #333);
    font-size: 11px;
    color: var(--text-muted, #888);
    flex-shrink: 0;
}

.jaws-revision-list-sort select {
    background: var(--bg-tertiary, #1a1a1a);
    color: var(--text-secondary, #bbb);
    border: 1px solid var(--border-primary, #333);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 11px;
    cursor: pointer;
}

.jaws-revision-list-sort select:focus {
    outline: 1px solid var(--accent-primary, #4a9eff);
    outline-offset: 1px;
}

/* Rows: one per revision. Clickable; selected row gets a highlight
   matching the list's selection (OD-06's three-way linkage will
   drive this from outside). The withdrawable action is rendered
   as a small button on draft rows. */
.jaws-revision-list-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 10px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border-primary, #333);
    cursor: pointer;
    align-items: start;
    transition: background-color 0.1s ease;
}

.jaws-revision-list-row:hover {
    background: var(--bg-tertiary, #1a1a1a);
}

.jaws-revision-list-row.is-selected {
    background: rgba(74, 158, 255, 0.12);
    border-left: 3px solid var(--accent-primary, #4a9eff);
    padding-left: 13px;
}

.jaws-revision-list-row.is-withdrawn {
    opacity: 0.55;
}

/* Icon column: a leading Unicon glyph in muted color, tinted by the
   revision's visual state. */
.jaws-revision-list-icon {
    color: var(--text-muted, #888);
    font-size: 16px;
    line-height: 1.4;
    flex-shrink: 0;
    width: 20px;
    text-align: center;
}

.jaws-revision-list-row.jaws-rev-pending .jaws-revision-list-icon     { color: #6aa9ff; }
.jaws-revision-list-row.jaws-rev-in_progress .jaws-revision-list-icon { color: #d8a64a; }
.jaws-revision-list-row.jaws-rev-applied .jaws-revision-list-icon     { color: #4caf50; }
.jaws-revision-list-row.jaws-rev-conflict .jaws-revision-list-icon    { color: #ff7070; }
.jaws-revision-list-row.jaws-rev-withdrawn .jaws-revision-list-icon   { color: #777; }

/* Body: summary (top line) + snippet (smaller, muted). */
.jaws-revision-list-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.jaws-revision-list-summary {
    font-size: 12px;
    color: var(--text-primary, #eee);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.jaws-revision-list-snippet {
    font-size: 11px;
    color: var(--text-muted, #888);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-style: italic;
}

/* Action column: status badge + (for drafts) the WITHDRAW button. */
.jaws-revision-list-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    flex-shrink: 0;
}

/* Status badge: a small pill whose background + text colour match
   the visual state. Same vocabulary as the overlay (OD-02). */
.jaws-revision-state-badge {
    font-size: 10px;
    padding: 2px 6px;
    border-radius: 8px;
    background: var(--bg-tertiary, #1a1a1a);
    color: var(--text-muted, #888);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    line-height: 1;
}

.jaws-revision-state-badge.jaws-rev-pending     { background: rgba(106, 169, 255, 0.18); color: #6aa9ff; }
.jaws-revision-state-badge.jaws-rev-in_progress { background: rgba(216, 166, 74, 0.18); color: #d8a64a; }
.jaws-revision-state-badge.jaws-rev-applied     { background: rgba(76, 175, 80, 0.18); color: #4caf50; }
.jaws-revision-state-badge.jaws-rev-conflict    { background: rgba(255, 112, 112, 0.18); color: #ff7070; }
.jaws-revision-state-badge.jaws-rev-withdrawn   { background: rgba(120, 120, 120, 0.18); color: #999; }

/* WITHDRAW button: small, ghost-styled. Only renders on draft rows
   (the component hides it otherwise; this is the visible affordance
   when it's there). */
.jaws-revision-list-withdraw {
    background: transparent;
    border: 1px solid var(--border-primary, #444);
    color: var(--text-muted, #888);
    font-size: 10px;
    padding: 2px 6px;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.jaws-revision-list-withdraw:hover {
    background: rgba(255, 112, 112, 0.1);
    border-color: #ff7070;
    color: #ff7070;
}

/* Empty state: shown when there are no rounds OR no revisions. */
.jaws-revision-list-empty {
    padding: 32px 16px;
    text-align: center;
    color: var(--text-muted, #888);
    font-size: 12px;
}

.jaws-revision-list-empty i {
    font-size: 24px;
    display: block;
    margin-bottom: 8px;
    opacity: 0.5;
}

/* ── Round groups (PP-12) — per-round group headers in the list ────
   One section per round. The header is a button (so it's keyboard
   accessible) with a chevron + title + status pill; below it, a
   timestamps row (Created always; Submitted / Applied when set).
   Rounds are emitted by the projection newest-first; the visual
   flow matches the same direction (newest at the top, oldest at
   the bottom). Draft rounds wear a left border + a tinted
   background so the user can find "the round I'm working on" at
   a glance. The `.is-collapsed` modifier hides the entries
   container + rotates the chevron via a class swap (the Razor
   controls the icon class). */

.jaws-round-group {
    display: flex;
    flex-direction: column;
    border-bottom: 1px solid var(--border-primary, #333);
}

.jaws-round-group:last-child {
    border-bottom: none;
}

.jaws-round-group.is-draft {
    background: rgba(106, 169, 255, 0.05);
    border-left: 3px solid var(--accent-primary, #4a9eff);
}

.jaws-round-group-header {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 10px 12px 6px;
    background: transparent;
    border: none;
    color: var(--text-primary, #eee);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.1s ease;
}

.jaws-round-group-header:hover {
    background: var(--bg-tertiary, #1a1a1a);
}

.jaws-round-group.is-draft .jaws-round-group-header:hover {
    background: rgba(74, 158, 255, 0.10);
}

.jaws-round-group-chevron {
    font-size: 14px;
    color: var(--text-muted, #888);
    flex-shrink: 0;
    width: 14px;
    text-align: center;
}

.jaws-round-group-title {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
    min-width: 0;
}

/* Round status pill: reuses the per-revision badge vocabulary so a
   draft round wears the same amber "pending" pill the draft
   revisions inside it wear. The text is the CSS-friendly state
   label (e.g. "pending" for a draft round, "in progress" for an
   applying round, "applied" for a completed round). */
.jaws-round-group-status {
    font-size: 9px;
    padding: 2px 6px;
    border-radius: 8px;
    background: var(--bg-tertiary, #1a1a1a);
    color: var(--text-muted, #888);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    line-height: 1.1;
    flex-shrink: 0;
}

.jaws-round-group-status.jaws-rev-pending     { background: rgba(106, 169, 255, 0.18); color: #6aa9ff; }
.jaws-round-group-status.jaws-rev-in_progress { background: rgba(216, 166, 74, 0.18); color: #d8a64a; }
.jaws-round-group-status.jaws-rev-applied     { background: rgba(76, 175, 80, 0.18); color: #4caf50; }
.jaws-round-group-status.jaws-rev-conflict    { background: rgba(255, 112, 112, 0.18); color: #ff7070; }
.jaws-round-group-status.jaws-rev-withdrawn   { background: rgba(120, 120, 120, 0.18); color: #999; }

/* Timestamps row: a tight line under the header, only the non-null
   lifecycle events are rendered. The pipe is a small visual
   separator between Created and Submitted / Applied so the eye
   parses the three as one row rather than three loose labels. */
.jaws-round-group-timestamps {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    padding: 0 12px 8px 30px;
    font-size: 10px;
    color: var(--text-muted, #888);
    line-height: 1.4;
}

.jaws-round-group-timestamp {
    white-space: nowrap;
}

.jaws-round-group-entries {
    display: flex;
    flex-direction: column;
}

/* When collapsed, hide the entries container. The header itself
   stays visible so the user can click to expand. No animation —
   the reviewer's reading the list, not watching it. */

/* ── Revisions panel (right-side tabbed drawer) ───────────────────
   Replaces the v0 sibling layout (Inspector + RevisionsList as
   flex-row children). The right column is now a single panel
   hosting two tabs. The tab strip sits at the top; the active
   tab's child fills the rest. The panel owns the outer border +
   width; the inner components (jaws-inspector, jaws-revision-list-drawer)
   drop their own border-left + fixed width when inside the panel,
   so the panel reads as one frame rather than three nested ones. */

.jaws-revisions-panel {
    display: flex;
    flex-direction: column;
    width: 360px;
    min-width: 300px;
    flex-shrink: 0;
    background: var(--bg-secondary, #1e1e1e);
    border-left: 1px solid var(--border-primary, #333);
    overflow: hidden;
    min-height: 0;
}

/* Tab strip: a horizontal row of tab buttons. Border-bottom
   separates the strip from the active tab's content. */
.jaws-revisions-panel-tabs {
    display: flex;
    flex-shrink: 0;
    border-bottom: 1px solid var(--border-primary, #333);
    background: var(--bg-primary, #1a1a1a);
}

/* Individual tab. Inactive tabs are muted; hovering surfaces the
   label colour. The active tab gets the accent underline + accent
   text colour so the reviewer sees which surface is current. */
.jaws-revisions-panel-tab {
    flex: 1;
    padding: 8px 12px;
    background: transparent;
    border: none;
    border-right: 1px solid var(--border-primary, #333);
    color: var(--text-muted, #888);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    transition: color 0.1s ease, background-color 0.1s ease;
}

.jaws-revisions-panel-tab:last-child {
    border-right: none;
}

.jaws-revisions-panel-tab:hover:not(.is-active) {
    color: var(--text-secondary, #bbb);
    background: var(--bg-tertiary, #1a1a1a);
}

.jaws-revisions-panel-tab.is-active {
    color: var(--accent-primary, #4a9eff);
    background: var(--bg-secondary, #222);
    box-shadow: inset 0 -2px 0 var(--accent-primary, #4a9eff);
}

/* Active tab content. flex:1 + min-height:0 so the inner
   component (jaws-inspector OR jaws-revision-list-drawer) can
   manage its own overflow rather than letting the panel scroll. */
.jaws-revisions-panel-content {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Inside the panel, the inspector and revisions list should NOT
   carry their own border-left or fixed width — the panel's outer
   border + width is the visible frame. The inner flex:1 makes
   them fill the content area vertically. */
.jaws-revisions-panel .jaws-inspector,
.jaws-revisions-panel .jaws-revision-list-drawer {
    width: 100%;
    min-width: 0;
    border-left: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

/* OD-FIX — Revisions tab content: a vertical split that hosts the
   RevisionsList on top and the RevisionDiff as a fixed bottom
   strip under it. Two regions inside a flex column:

   - .jaws-revisions-list-region — the list, fills the available
     space above the diff. Owns its own vertical scroll.
   - .jaws-revisions-diff-region — the diff bottom strip, capped
     height (50% of the panel) with a min-height for the empty
     / not-selected state. The diff component itself owns the
     internal scroll so a long diff doesn't push the list out.

   The border-top on the diff region separates the two surfaces
   visually so the list and the diff read as distinct panes.

   The list + diff are both rendered together — clicking a row
   leaves the list visible AND the diff appears under it. The
   user never has to navigate away from the list to see what
   the revision does. (Was a tab in v0; became a split when
   reviewers complained about losing the list on every click.) */
.jaws-revisions-content-stack {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.jaws-revisions-list-region {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    overflow: hidden;
}

.jaws-revisions-diff-region {
    /* Option B — min-height strip that grows up to a cap, then
       scrolls internally. The cap is 50% of the panel height so
       the list keeps at least half the space. The min-height
       keeps short diffs / the empty-state message readable. */
    flex: 0 1 auto;
    min-height: 120px;
    max-height: 50%;
    display: flex;
    overflow: hidden;
    border-top: 1px solid var(--border-primary, #333);
    background: var(--bg-secondary, #1e1e1e);
}

/* The diff component lives inside the diff region; the region
   supplies the border and the height cap, the diff supplies the
   internal layout + scroll. The diff already has overflow-y:auto
   so this just makes it fill its parent region cleanly. */
.jaws-revisions-diff-region .jaws-revision-diff {
    width: 100%;
    min-height: 0;
    max-height: 100%;
}

/* ── OD-06 — Revisions panel header ────────────────────────────────
   A thin row above the tab strip holding the SUBMIT affordance +
   its guard-aware label. Visible only when the host supplies an
   OnSubmit callback (otherwise the panel's header is empty and the
   tab strip rises to fill the space). The button is muted when
   canSubmit is false; the muted label clarifies why ("no draft
   round" / "edits in progress") without an explicit tooltip. */
.jaws-revisions-panel-header {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-primary, #333);
    background: var(--bg-primary, #1a1a1a);
    flex-shrink: 0;
}

.jaws-revisions-panel-header-status {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #888);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.jaws-revisions-panel-submit {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 4px 12px;
    border-radius: 4px;
    border: 1px solid var(--accent-primary, #4a9eff);
    background: var(--accent-primary, #4a9eff);
    color: #fff;
    cursor: pointer;
    transition: opacity 0.1s ease, background-color 0.1s ease;
}

.jaws-revisions-panel-submit:hover:not(:disabled) {
    background: #6ab4ff;
}

.jaws-revisions-panel-submit:disabled {
    background: transparent;
    color: var(--text-muted, #888);
    border-color: var(--border-primary, #333);
    cursor: not-allowed;
    opacity: 0.7;
}

/* ── Revision diff (off-canvas before->after, OD-04) ────────────────
   The diff lives inside the right-side revisions panel as a third
   tab. It's a track-changes-style read of the selected revision's
   STORED op data — text ins/del, format field rows, annotate
   callout, structural action label. Free to reflow (off-canvas),
   so the projection is unaffected.

   The header carries the same .jaws-rev-{state} class the list /
   overlay use so the diff and the list agree on a colour at a
   glance. The body is a vertical stack of segments; each
   segment kind has its own row style. */

/* Outer wrapper. flex column with no own border (the panel
   supplies the frame). */
.jaws-revision-diff {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-width: 0;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    background: var(--bg-secondary, #1e1e1e);
    padding: 12px 16px;
    gap: 12px;
}

/* Header: the per-type icon + summary, tinted by the revision's
   visual state. Mirrors the row's icon + summary exactly so the
   diff and the row read the same way. */
.jaws-revision-diff-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary, #eee);
    border-bottom: 1px solid var(--border-primary, #333);
    padding-bottom: 8px;
    flex-shrink: 0;
}

.jaws-revision-diff-header i {
    font-size: 16px;
    color: var(--text-muted, #888);
}

.jaws-revision-diff-header.jaws-rev-pending     .jaws-revision-diff-header-summary { color: #6aa9ff; }
.jaws-revision-diff-header.jaws-rev-in_progress .jaws-revision-diff-header-summary { color: #d8a64a; }
.jaws-revision-diff-header.jaws-rev-applied     .jaws-revision-diff-header-summary { color: #4caf50; }
.jaws-revision-diff-header.jaws-rev-conflict    .jaws-revision-diff-header-summary { color: #ff7070; }
.jaws-revision-diff-header.jaws-rev-withdrawn   .jaws-revision-diff-header-summary { color: #999; }

.jaws-revision-diff-header-summary {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Body: the per-op segment stack. Each segment is its own block —
   text bodies wrap, format bodies list rows, annotate bodies
   are callouts, structural bodies are single-line action labels. */
.jaws-revision-diff-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

/* Text body: the LCS output as inline equal/insert/delete spans.
   The body wraps naturally (text is long when the op is long);
   each chunk is an inline span styled by op. */
.jaws-revision-diff-text {
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-primary, #eee);
    background: var(--bg-tertiary, #1a1a1a);
    padding: 8px 10px;
    border-radius: 4px;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

.jaws-revision-diff-text-empty {
    color: var(--text-muted, #888);
    font-style: italic;
}

/* Insert: green-on-green, no strike — the "added text" visual. */
.jaws-diff-insert {
    background: rgba(76, 175, 80, 0.22);
    color: #b8e6bb;
    padding: 0 1px;
    border-radius: 2px;
    text-decoration: none;
}

/* Delete: red-on-red, strikethrough — the "removed text" visual. */
.jaws-diff-delete {
    background: rgba(255, 112, 112, 0.22);
    color: #ffb8b8;
    padding: 0 1px;
    border-radius: 2px;
    text-decoration: line-through;
}

/* Format body: a vertical list of "Field: value" rows. The
   field name is muted (the implementation detail), the value
   is primary (what the user sees in the diff). Multiple rows
   from a single op stack — the diff shows every changed
   FormatDelta field, not just one. */
.jaws-revision-diff-format {
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: var(--bg-tertiary, #1a1a1a);
    padding: 8px 10px;
    border-radius: 4px;
}

.jaws-revision-diff-format-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: 12px;
    line-height: 1.4;
}

.jaws-revision-diff-format-name {
    color: var(--text-muted, #888);
    flex-shrink: 0;
    min-width: 60px;
}

.jaws-revision-diff-format-sep {
    color: var(--text-muted, #888);
    flex-shrink: 0;
}

.jaws-revision-diff-format-value {
    color: var(--text-primary, #eee);
    word-break: break-word;
}

/* Annotate body: a callout with the target context as the muted
   anchor + the reviewer note as the primary content. Same
   visual language as the inline-error callouts in the editor
   (annotate, edit, style errors) so the diff matches. */
.jaws-revision-diff-annotate {
    display: flex;
    flex-direction: column;
    gap: 6px;
    background: rgba(106, 169, 255, 0.08);
    border-left: 3px solid #6aa9ff;
    padding: 10px 12px;
    border-radius: 0 4px 4px 0;
}

.jaws-revision-diff-annotate-context {
    font-size: 11px;
    color: var(--text-muted, #888);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.jaws-revision-diff-annotate-note {
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-primary, #eee);
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

.jaws-revision-diff-annotate-empty {
    color: var(--text-muted, #888);
    font-style: italic;
}

/* Structural body: a single row with a leading arrow + the
   action label. Visual language matches the rest of the diff
   (muted text + a primary label), with the arrow cueing the
   "this is a one-line action, not a payload". */
.jaws-revision-diff-structural {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-secondary, #bbb);
    background: var(--bg-tertiary, #1a1a1a);
    padding: 8px 10px;
    border-radius: 4px;
}

.jaws-revision-diff-structural i {
    color: var(--text-muted, #888);
    font-size: 14px;
}

/* Empty / not-found states. Mirrors the revisions-list's
   empty state so the three tabs (list / diff / inspector)
   agree on what "no content" looks like. */
.jaws-revision-diff-empty,
.jaws-revision-diff-not-found {
    padding: 32px 16px;
    text-align: center;
    color: var(--text-muted, #888);
    font-size: 12px;
}

.jaws-revision-diff-empty i,
.jaws-revision-diff-not-found i {
    font-size: 24px;
    display: block;
    margin-bottom: 8px;
    opacity: 0.5;
}

.jaws-revision-diff-not-found i {
    color: #d8a64a;
    opacity: 0.7;
}

/* The diff surface is mounted inside the revisions panel; the
   panel's inner content already drops the border-left + fixed
   width on the inner children. The diff doesn't need its own
   border — it fills the panel's content area. */
.jaws-revisions-panel .jaws-revision-diff {
    border-left: none;
    width: 100%;
}

