/*
 * LivePreviewEditor surface styling. Token-var only (mirrors MarkdownProse.css /
 * the tokens.css design contract) — no hard-coded hex/px so a future dark theme
 * needs no edits here. The CM6 EditorView theme (web/src/lib/cm/theme.ts) handles
 * the inner content typography; this file styles the host wrapper.
 */
.livepreview-editor {
  min-height: var(--editor-min-height);
  background: var(--color-bg);
}

.livepreview-editor .cm-editor {
  min-height: var(--editor-min-height);
}

/*
 * No focus ring around the editor surface itself — a full-bleed editor wrapped in
 * a 2px accent outline reads as a stray "violet box/line" that tracks the content
 * as it grows. The focus cue lives on the surrounding .pageeditor-surface border
 * instead (a subtle accent border on :focus-within). CM6's own default outline is
 * suppressed here.
 */
.livepreview-editor .cm-editor.cm-focused {
  outline: none;
}

/*
 * Centre the prose content column (the theme caps .cm-content at
 * --prose-max-width; centring it mirrors read mode's centred `.markdown-prose`).
 * Vertical rhythm for heading lines lives in the CM6 theme line decorations and
 * is layout-neutral with respect to marker reveal (a heading line is a heading
 * line whether or not its "# " marker shows), so neighbours never reflow.
 */
.livepreview-editor .cm-content {
  margin-left: auto;
  margin-right: auto;
}

/*
 * Inline image widget (ImageWidget.toDOM → <img class="cm-md-image">). Constrain to
 * the content column so a large image never overflows the editor; tokens only.
 */
.livepreview-editor .cm-md-image {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/*
 * Blocked-src fallback span (ImageWidget renders the RAW `![alt](src)` markdown as
 * plain mono text when sanitizeImageSrc rejects the src — never a broken <img>).
 */
.livepreview-editor .cm-md-image-raw {
  font-family: var(--font-family-mono);
  color: var(--color-text);
}

/*
 * GFM table widget (TableWidget.toDOM → <table class="cm-md-table">). Matches
 * MarkdownProse.css table styling token-for-token (border-collapse, 1px border in
 * --color-border, xs/sm cell padding) so Live mode renders a table identically to
 * read mode and the server's Goldmark GFM.
 */
.livepreview-editor .cm-md-table {
  border-collapse: collapse;
  /* No vertical margin: it is invisible to CM6's height oracle (which measures
   * offsetHeight, excluding margin), so it drifts posAtCoords/coordsAtPos below
   * this block. The mandatory blank line adjacent to a GFM table supplies the gap. */
}

.livepreview-editor .cm-md-table th,
.livepreview-editor .cm-md-table td {
  border: 1px solid var(--color-border);
  padding: var(--space-xs) var(--space-sm);
}

.livepreview-editor .cm-md-table th {
  background: var(--color-surface);
  font-weight: var(--font-weight-semibold);
  text-align: left;
}

.livepreview-editor .cm-md-table tbody tr:nth-child(even) {
  background: rgba(255, 255, 255, 0.02);
}

/* ── READ-MODE (clean render) prose ──────────────────────────────────────────
 * These classes only appear on the read surface (PageView), where the live-preview
 * runs with the cleanRender facet: list/quote/fence markers are hidden and replaced
 * by finished prose. Scoped to .livepreview-readonly so the editing surface is
 * untouched. */

/* Read mode fills its centered doc column (the .pageview max-width governs the
 * measure now), matching edit mode exactly so read and edit are pixel-identical
 * — same width, same left edge under the title. */
.livepreview-readonly .cm-content {
  max-width: 100%;
  margin-left: 0;
  margin-right: auto;
}

/* Unordered bullet (BulletWidget replaces the "-"/"*"/"+" ListMark). */
.livepreview-editor .cm-md-bullet {
  color: var(--color-accent-2);
  font-weight: var(--font-weight-semibold);
}

/* Blockquote line (QuoteMark hidden; the line carries cm-blockquote). A left rule +
 * muted text, Obsidian-style. */
.livepreview-editor .cm-blockquote {
  border-left: 3px solid var(--color-accent-border);
  padding-left: var(--space-md);
  color: var(--color-text-2);
  font-style: italic;
}

/* Fenced code block widget (CodeBlockWidget → <pre class="cm-md-codeblock">). A clean
 * mono block on the code background; the language (data-lang) shows as a small tab. */
.livepreview-editor .cm-md-codeblock {
  position: relative;
  /* margin:0 is EXPLICIT (not omitted): <pre> carries a user-agent `margin: 1em 0`
   * that would otherwise resurface and, being oracle-invisible, drift selection
   * coords below the block in read mode. The blank line CommonMark requires around a
   * fenced block supplies the visual gap. */
  margin: 0;
  padding: var(--space-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow-x: auto;
  font-family: var(--font-family-mono);
  font-size: var(--font-size-label);
  line-height: var(--line-height-body);
}

.livepreview-editor .cm-md-codeblock code {
  font-family: inherit;
  white-space: pre;
}

.livepreview-editor .cm-md-codeblock[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: 0;
  right: 0;
  padding: 2px var(--space-sm);
  font-family: var(--font-family-ui);
  font-size: 11px;
  color: var(--color-faint);
  text-transform: lowercase;
  letter-spacing: 0.02em;
  border-bottom-left-radius: var(--radius-sm);
}

/* Copy-to-clipboard button (EP-02): a small subtle button in the top-right
 * corner of the read-mode fenced code block. The button is a sibling of <code>
 * inside <pre>; built with createElement + textContent (no innerHTML). */
.livepreview-editor .cm-copy-btn {
  position: absolute;
  top: 0;
  right: 0;
  padding: 2px var(--space-sm);
  font-family: var(--font-family-ui);
  font-size: 11px;
  color: var(--color-text-muted);
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  /* Overlay chrome, not code — exclude it from a select-all/copy of the block so the
   * button label never lands in the user's clipboard (matches the button's own
   * this.code copy-on-click). */
  user-select: none;
  opacity: 0;
  transition: opacity 120ms ease-out;
}

.livepreview-editor .cm-md-codeblock:hover .cm-copy-btn {
  opacity: 1;
}

.livepreview-editor .cm-copy-btn:hover {
  color: var(--color-accent);
}

/* Syntax-highlight token colors (ED-04a). The ONE shared HighlightStyle
 * (lib/cm/highlight.ts) emits these `.tok-*` classes on token spans for BOTH
 * surfaces: inside the read CodeBlockWidget <pre> AND inside .cm-content (the
 * live editor's nested fenced code). Color is the ONLY property set per role
 * (tokens-only, no hex) — same font/size/padding as plain, so the
 * plain→highlighted swap is zero layout shift (D-08). Not scoped under
 * .livepreview-editor: the live-editor spans live in .cm-content which the
 * editor mounts, and these classes are intentionally global to cover both. */
.tok-keyword {
  color: var(--syntax-keyword);
}
.tok-string {
  color: var(--syntax-string);
}
.tok-comment {
  color: var(--syntax-comment);
  font-style: italic;
}
.tok-number {
  color: var(--syntax-number);
}
.tok-function {
  color: var(--syntax-function);
}

/* Plain→highlighted reveal: a subtle fade so the async re-highlight reads as
 * intentional, never a flicker (D-08). Only the <code> opacity animates — no
 * metric changes, so neighbors never reflow. Applied when the widget toggles
 * `--highlighted` after the lazy grammar resolves. */
@media (prefers-reduced-motion: no-preference) {
  .livepreview-editor .cm-md-codeblock.cm-md-codeblock--highlighted code {
    animation: tok-fade-in 160ms ease-out;
  }
}

@keyframes tok-fade-in {
  from {
    opacity: 0.55;
  }
  to {
    opacity: 1;
  }
}

/* Mermaid diagram block (ED-05a). The wrapper holds either the raw-code fallback
 * (a .cm-md-codeblock <pre>, before/instead of a successful render) or the rendered
 * <svg>. A min-height reserves space so the async fallback→svg swap reads as a fill,
 * not a jump (blunts layout shift; the widget also calls view.requestMeasure after the
 * swap). Dark surface via the same code background token as fenced code. */
.cm-md-mermaid {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 2.5rem;
  /* No vertical margin — oracle-invisible, drifts selection coords below the block.
   * The blank line adjacent to the ```mermaid fence supplies the gap. */
  padding: 0.75rem;
  border-radius: 6px;
  background: var(--color-code-bg, #1e1e1e);
  overflow-x: auto;
}

/* The injected diagram fits the column (the widget also sets max-width inline). */
.cm-md-mermaid svg {
  max-width: 100%;
  height: auto;
}

/* Fade the rendered diagram in when the swap lands (opacity only — no metric change,
 * so neighbors never reflow). Matches the Phase-25 code fade convention (D-08). */
@media (prefers-reduced-motion: no-preference) {
  .cm-md-mermaid.cm-md-mermaid--rendered svg {
    animation: tok-fade-in 160ms ease-out;
  }
}
