/* ============================================================
   Editor page styles (editor.html)
   Phase 2: provides the shell; Phase 3 wires TipTap into
   #editor-root and adds rich-text styles here.
   ============================================================ */

/* v2 — calm writing room. Page canvas + opaque panes; Newsreader for
   the writing surface, Space Mono for status chrome, VT323 for panel
   labels. Tokens live in _www-tokens.css. */
body[data-page="editor"] {
  background: var(--bg-page);
}

.editor-layout {
  display: grid;
  /* Phase 3d: 3-column track (main · aux for TOC/SEO · frontmatter).
     When both aux panels close the column collapses — see the Phase 3d
     block at the end of this file for the override. */
  grid-template-columns: minmax(0, 1fr) 260px 340px;
  gap: 16px;
  align-items: stretch;
  min-height: calc(100dvh - 130px);
}

.editor-pane {
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  /* `clip` (not `hidden`) keeps the rounded-corner clipping but does NOT make
     the pane a scroll container — so the sticky toolbar below can stick
     relative to the real scroller (.stage) instead of being trapped here. */
  overflow: clip;
  position: relative;
  min-width: 0;
}
/* Focused-editor ring. `:focus-within` matches whether focus arrived by
   click OR keyboard (unlike `:focus-visible`, which ignores mouse), so
   clicking into either the WYSIWYG (ProseMirror) or source (CodeMirror)
   surface shows a clear accent ring on the pane. */
.editor-pane:focus-within {
  border-color: var(--accent);
  box-shadow:
    0 0 0 3px var(--accent-soft),
    var(--shadow-card);
}
/* The pane ring is the editor's focus indicator, so suppress the inner
   surfaces' own focus outline to avoid a doubled ring on keyboard focus
   (the global :focus-visible rule would otherwise add one inside). */
.editor-pane .ProseMirror:focus-visible,
.editor-pane .cm-content:focus-visible {
  outline: none !important;
}

.editor-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line-www);
  flex-wrap: wrap;
}
.ed-pill {
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.18em;
  padding: 2px 10px;
  border-radius: 999px;
  text-transform: uppercase;
  color: var(--warn-strong, var(--warn));
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  background: var(--warn-soft);
  font-weight: 400;
}
.ed-pill.pub {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: var(--accent-soft);
}
/* Live deploy status pill, shown after a publish (Building… → Live ✓). */
.ed-deploy {
  font-family: var(--font-mono-www);
  font-size: 11px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-mute);
  background: var(--surface-2, transparent);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ed-deploy[hidden] {
  display: none;
}
.ed-deploy.building {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: var(--accent-soft);
}
.ed-deploy.building::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
  .ed-deploy.building::before {
    animation: ed-deploy-pulse 1.1s ease-in-out infinite;
  }
}
@keyframes ed-deploy-pulse {
  0%,
  100% {
    opacity: 0.35;
  }
  50% {
    opacity: 1;
  }
}
.ed-deploy.ok {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: var(--accent-soft);
}
.ed-deploy.fail {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 40%, transparent);
  background: var(--danger-soft);
}
.ed-deploy[href]:hover {
  text-decoration: underline;
}
.ed-saved {
  font-family: var(--font-mono-www);
  font-size: 11px;
  color: var(--ink-mute);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ed-saved .pip {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-bg);
  display: inline-block;
}
.editor-head-r {
  margin-left: auto;
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.ed-title-wrap {
  padding: 30px 40px 14px;
  border-bottom: 1px solid var(--line-www);
}
.ed-title {
  width: 100%;
  background: transparent;
  border: 0;
  outline: 0;
  font-family: var(--font-read);
  font-size: 42px;
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--ink);
  line-height: 1.06;
  margin: 0 0 10px;
  padding: 0;
}
.ed-title::placeholder {
  color: var(--ink-faint);
}
.ed-slug {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--font-mono-www);
  font-size: 12px;
  color: var(--ink-mute);
}
.ed-slug .root {
  color: var(--ink-mute);
}
.ed-slug input {
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--accent);
  font-family: var(--font-mono-www);
  font-size: 12px;
  flex: 1;
  min-width: 0;
  padding: 0;
}
.ed-slug-sync {
  flex: 0 0 auto;
  padding: 2px 8px;
  font-family: var(--font-ui);
  font-size: 11px;
  white-space: nowrap;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: 999px;
  cursor: pointer;
}
.ed-slug-sync:hover {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
}

/* Phase 3a: TipTap WYSIWYG + CodeMirror source view mount here.
   The pre-rendered <textarea id="editor-fallback"> is replaced
   (and hidden) by the bundle's mount() the moment editor.bundle.js
   loads. If the bundle never loads, the textarea stays visible
   and serves as a no-JS / no-build fallback. */
.ed-body {
  padding: 24px 40px 32px;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 320px;
}
#editor-root {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 320px;
}
#editor-fallback {
  flex: 1;
  width: 100%;
  background: transparent;
  border: 0;
  outline: 0;
  resize: vertical;
  font-family: var(--font-read);
  font-size: 20px;
  line-height: 1.7;
  color: var(--ink);
  padding: 0;
  min-height: 320px;
}
#editor-fallback::placeholder {
  color: var(--ink-faint);
}
/* The bundle keeps a hidden textarea inside #editor-root as the
   Markdown source-of-truth. Force it out of the flow so it never
   contributes scroll-height. */
#editor-fallback[hidden],
#editor-root .te-editor #editor-fallback {
  display: none !important;
}

/* ============================================================
   Phase 3a editor chrome
   ============================================================ */

.te-editor {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 320px;
  gap: 12px;
}

.te-editor-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  /* Follow the writer down the page. Sticks to the top of the scrolling
     .stage (the topbar is a separate, non-scrolling grid row, so top:0 lands
     just beneath it). Depends on .editor-pane using overflow:clip so the pane
     isn't a scroll container that would trap this. The contextual image/video
     groups live inside this toolbar, so they ride along automatically. */
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  /* Opaque so body text (and proofreader squiggles) pass UNDER the bar; the
     .te-editor gap below keeps the first line of text clear of it. */
  background: var(--surface);
  padding: 8px 0;
  border-bottom: 1px solid var(--line-www);
}
.te-editor-toolbar-spacer {
  flex: 1;
}

.te-editor-mode-toggle {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--line-www);
  border-radius: 999px;
  padding: 3px;
  background: var(--surface-2);
}
.te-editor-mode-btn {
  appearance: none;
  background: transparent;
  border: 0;
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: 4px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: 120ms;
}
.te-editor-mode-btn:hover {
  color: var(--ink);
}
.te-editor-mode-btn.active {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
.te-editor-mode-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.te-editor-stack {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 280px;
  position: relative;
}
.te-editor-wysiwyg,
.te-editor-source {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 280px;
}

/* ─── ProseMirror (TipTap WYSIWYG) ───────────────────────────── */
.ProseMirror {
  flex: 1;
  outline: none;
  font-family: var(--font-read);
  font-size: 20px;
  line-height: 1.7;
  color: var(--ink);
  padding: 0;
  min-height: 280px;
}
.ProseMirror:focus {
  outline: none;
}
.ProseMirror p {
  margin: 0 0 14px;
}
.ProseMirror h1,
.ProseMirror h2,
.ProseMirror h3,
.ProseMirror h4,
.ProseMirror h5,
.ProseMirror h6 {
  font-family: var(--font-read);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.18;
  color: var(--ink);
  margin: 28px 0 10px;
}
.ProseMirror h1 {
  font-size: 34px;
}
.ProseMirror h2 {
  font-size: 28px;
}
.ProseMirror h3 {
  font-size: 23px;
}
.ProseMirror h4 {
  font-size: 20px;
}
.ProseMirror h5,
.ProseMirror h6 {
  font-size: 15px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}
.ProseMirror blockquote {
  margin: 0 0 14px;
  padding: 4px 0 4px 16px;
  border-left: 3px solid var(--accent-bg);
  color: var(--ink-soft);
  font-style: italic;
}
.ProseMirror hr {
  border: 0;
  border-top: 1px dashed var(--line-www);
  margin: 22px 0;
}
.ProseMirror code {
  font-family: var(--font-mono-www);
  font-size: 0.75em;
  padding: 1px 5px;
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  border: 1px solid var(--line-www);
}
.ProseMirror pre {
  font-family: var(--font-mono-www);
  font-size: 14px;
  line-height: 1.55;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-www);
  overflow-x: auto;
  margin: 0 0 14px;
}
.ProseMirror pre code {
  background: transparent;
  border: 0;
  padding: 0;
}
.ProseMirror a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ProseMirror ul,
.ProseMirror ol {
  padding-left: 26px;
  margin: 0 0 14px;
}
.ProseMirror li {
  margin: 4px 0;
}
.ProseMirror ul[data-type="taskList"] {
  list-style: none;
  padding-left: 4px;
}
.ProseMirror ul[data-type="taskList"] li {
  display: flex;
  gap: 8px;
}
.ProseMirror ul[data-type="taskList"] li > label {
  user-select: none;
  margin-top: 4px;
}
.ProseMirror img {
  /* Centered + bounded by default so inserted images read as deliberate,
     centred figures (matches the published page) rather than a raw
     full-bleed block. data-align overrides below opt into left/right/full. */
  display: block;
  max-width: min(100%, 640px);
  height: auto;
  margin: 18px auto;
  border-radius: var(--radius-xs);
}
/* Image alignment — WYSIWYG mirror of the published `.post-body
   figure.img-align-*` styles so what's set here matches the live page.
   No `data-align` attr (every existing image) keeps the default above. */
.ProseMirror img[data-align="center"] {
  margin-inline: auto;
  max-width: min(100%, 600px);
}
.ProseMirror img[data-align="full"] {
  width: 100%;
  max-width: 100%;
}
.ProseMirror img[data-align="left"] {
  float: left;
  max-width: min(48%, 360px);
  margin: 6px 20px 10px 0;
}
.ProseMirror img[data-align="right"] {
  float: right;
  max-width: min(48%, 360px);
  margin: 6px 0 10px 20px;
}
@media (max-width: 700px) {
  /* No float on narrow surfaces — wrapping reads badly under ~700px. */
  .ProseMirror img[data-align="left"],
  .ProseMirror img[data-align="right"] {
    float: none;
    max-width: 100%;
    margin-inline: auto;
  }
}
/* Inline media nodes — library attachments (img.te-attachment) and the
   self-hosted video node (video.te-video). Keep them bounded to the writing
   column so backfilled media / inserted video never blow out the layout. */
.ProseMirror img.te-attachment,
.ProseMirror video.te-video {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  margin: 14px auto;
}
.ProseMirror video.te-video {
  background: #000;
}
.ProseMirror video,
.ProseMirror iframe {
  max-width: 100%;
}
/* Selected media node (ProseMirror adds .ProseMirror-selectednode) + hover. */
.ProseMirror .te-attachment.ProseMirror-selectednode,
.ProseMirror .te-video.ProseMirror-selectednode {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ProseMirror video.te-video:hover {
  box-shadow: 0 0 0 2px var(--line-www);
}
.ProseMirror p.is-editor-empty:first-child::before {
  content: attr(data-placeholder);
  color: var(--ink-faint);
  pointer-events: none;
  height: 0;
  float: left;
}

/* ─── CodeMirror 6 (source view) ─────────────────────────────── */
.cm-editor {
  flex: 1;
  height: 100%;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-www);
}
.cm-editor.cm-focused {
  outline: none;
  border-color: var(--accent);
}
/* Source mode is part of the writing surface — same long-form serif
   as the WYSIWYG view (Markdown syntax stays legible; code spans in
   the document render via their own marks). */
.cm-editor .cm-scroller {
  font-family: var(--font-read);
  font-size: 20px;
  line-height: 1.7;
  padding: 12px 14px;
}
.cm-editor .cm-content {
  caret-color: var(--accent);
  color: var(--ink);
}
.cm-editor .cm-cursor {
  border-left-color: var(--accent);
}
.cm-editor .cm-selectionBackground,
.cm-editor.cm-focused .cm-selectionBackground {
  background: var(--accent-soft) !important;
}
/* Light-theme tweak: CM6's default selection is hard to see on light. */
[data-theme="light"] .cm-editor .cm-selectionBackground,
[data-theme="light"] .cm-editor.cm-focused .cm-selectionBackground {
  background: color-mix(in srgb, var(--accent) 20%, transparent) !important;
}

/* `.editor-foot` styles live in the Phase 3d block at the end of this
   file; this comment is a breadcrumb for grep-ers who land here first. */

/* Right-side panels (frontmatter / SEO / media / publish) */
.ed-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  min-width: 0;
}
.ed-panel {
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.ed-panel summary {
  list-style: none;
  cursor: pointer;
  padding: 12px 16px;
  border-bottom: 1px solid transparent;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-mute);
  user-select: none;
}
.ed-panel summary::-webkit-details-marker {
  display: none;
}
.ed-panel summary .chev {
  color: var(--ink-faint);
  transition: transform 120ms;
}
.ed-panel[open] summary {
  border-bottom-color: var(--line-www);
}
.ed-panel[open] summary .chev {
  transform: rotate(90deg);
}
.ed-panel .body {
  padding: 14px 16px;
}

/* v2 field treatment inside the side panels — VT323 micro-labels,
   16px Hanken inputs, accent focus ring. Scoped so the base .field
   rules in admin.css keep covering the rest of the admin. */
.ed-side .field label {
  font-family: var(--font-pixel);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.ed-side .field input,
.ed-side .field textarea,
.ed-side .field select {
  font-family: var(--font-ui);
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
}
.ed-side .field input:focus,
.ed-side .field textarea:focus,
.ed-side .field select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* The custom CSS / JS panels hold code, not prose — keep them mono. */
#post-custom-css,
#post-custom-js {
  font-family: var(--font-mono-www);
  font-size: 13px;
  line-height: 1.55;
}

/* Social preview card inside SEO panel */
.social-preview {
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: var(--surface-2);
  font-family: var(--font-ui);
}
.social-preview .domain {
  padding: 10px 12px 4px;
  font-size: 10.5px;
  color: var(--ink-mute);
  font-family: var(--font-mono-www);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.social-preview .title {
  padding: 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.social-preview .desc {
  padding: 4px 12px 12px;
  font-size: 12.5px;
  color: var(--ink-soft);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Media drop zone within editor sidebar */
.ed-dropzone {
  border: 1px dashed var(--line-strong-www);
  border-radius: var(--radius-sm);
  padding: 16px;
  text-align: center;
  cursor: pointer;
  transition: 120ms;
  color: var(--ink-soft);
  font-family: var(--font-mono-www);
  font-size: 11px;
  background: var(--surface-2);
}
.ed-dropzone:hover,
.ed-dropzone.drag {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}
.ed-dropzone .ico {
  font-family: var(--font-read);
  font-size: 22px;
  color: var(--accent);
  margin-bottom: 2px;
  display: block;
}

.recent-media {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: 10px;
}
.recent-media .thumb {
  position: relative;
  aspect-ratio: 1;
  background: var(--surface-3);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
  background-size: cover;
  background-position: center;
  cursor: pointer;
  overflow: hidden;
}
.recent-media .thumb:hover {
  border-color: var(--accent);
}
.recent-media .thumb .badge {
  position: absolute;
  bottom: 2px;
  right: 2px;
  font-family: var(--font-mono-www);
  font-size: 8px;
  background: rgb(0, 0, 0, 0.5);
  color: var(--accent);
  padding: 1px 4px;
  border-radius: 2px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Phase 5 will add real status badges; mark slot for now */
.recent-media .thumb .badge.processing {
  color: var(--warn);
}
.recent-media .thumb .badge.error {
  color: var(--danger);
}

/* Word count / metrics in topbar */
.editor-metrics {
  font-family: var(--font-mono-www);
  font-size: 11px;
  color: var(--ink-mute);
  letter-spacing: 0.04em;
}
.editor-metrics b {
  color: var(--ink-soft);
  font-weight: 500;
}

@media (max-width: 1100px) {
  .editor-layout {
    grid-template-columns: 1fr;
  }
  .ed-side {
    order: 2;
  }
}
@media (max-width: 800px) {
  .ed-title-wrap {
    padding: 18px 18px 12px;
  }
  .ed-body {
    padding: 14px 18px 20px;
  }
  .ed-title {
    font-size: 30px;
  }
}

/* ============================================================
   Phase 3b: rich toolbar, slash menu, link dialog
   ============================================================ */

/* Rich toolbar — sits between the mode toggle group and the
   flex spacer, so it stays left-aligned while the mode toggle
   floats right. Buttons are grouped with thin dividers. */
.te-editor-toolbar-rich {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 3px 4px;
  min-width: 0;
  padding: 4px 6px;
  background: var(--surface-2);
  border: 1px solid var(--line-www);
  /* A rounded RECT (not a 999px pill) so wrapped rows read as one tidy
     toolbar instead of a lumpy multi-row capsule. */
  border-radius: var(--radius);
}
.te-editor-toolbar-rich.is-disabled {
  opacity: 0.45;
  pointer-events: none;
}
.te-tb-group {
  display: inline-flex;
  align-items: center;
  gap: 0;
}
.te-tb-divider {
  width: 1px;
  height: 24px;
  background: var(--line-www);
  margin: 0 6px;
  display: inline-block;
}

/* Toolbar buttons themselves. Quiet pixel-type chips, glyph-only at
   typical sizes; the visible glyph is decorative and aria-hidden so
   only the aria-label is announced. */
.te-tb-btn {
  appearance: none;
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-mute);
  font-family: var(--font-pixel);
  font-size: 16px;
  text-transform: uppercase;
  line-height: 1;
  min-width: 34px;
  height: 36px;
  padding: 0 8px;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    background-color 120ms,
    color 120ms,
    border-color 120ms;
}
.te-tb-btn:hover {
  /* --ink (AA on --accent-soft) rather than --accent so the hovered
     control keeps a high-contrast glyph even before it's active. */
  background: var(--accent-soft);
  color: var(--ink);
}
.te-tb-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  color: var(--ink);
}
.te-tb-btn.is-active,
.te-tb-btn[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
}
.te-tb-btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
}
/* B/I/U/S keep their letterform styling in the UI sans so the
   bold/italic/underline glyphs read as type, not pixels. */
.te-tb-btn.te-tb-bold .te-tb-glyph {
  font-weight: 700;
  font-family: var(--font-ui);
}
.te-tb-btn.te-tb-italic .te-tb-glyph {
  font-style: italic;
  font-family: var(--font-ui);
}
.te-tb-btn.te-tb-underline .te-tb-glyph {
  text-decoration: underline;
  text-underline-offset: 2px;
  font-family: var(--font-ui);
}
.te-tb-btn.te-tb-strike .te-tb-glyph {
  text-decoration: line-through;
  font-family: var(--font-ui);
}
.te-tb-btn.is-placeholder {
  opacity: 0.7;
}
.te-tb-glyph {
  pointer-events: none;
  user-select: none;
  letter-spacing: 0;
  font-size: 17px;
}
/* Inline-SVG icons fill a fixed 18px box, centred. They inherit
   `stroke: currentColor`, so hover/active/focus recolour them with the
   surrounding button text. */
.te-tb-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0;
}
.te-tb-icon svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* Underline mark inside the WYSIWYG body. */
.ProseMirror u {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ─── Slash menu ──────────────────────────────────────────────
   Floating absolutely-positioned listbox. Sized so 6-7 rows fit
   comfortably; longer menus scroll. */
.te-slash-menu {
  /* token ladder: popovers sit at the dropdown level */
  position: absolute;
  z-index: var(--z-dropdown);
  min-width: 240px;
  max-width: 320px;
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-pop);
  padding: 4px;
  font-family: var(--font-ui);
  max-height: 320px;
  overflow: auto;
}
.te-slash-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.te-slash-group {
  font-family: var(--font-pixel);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 8px 8px 4px;
  user-select: none;
}
.te-slash-item {
  appearance: none;
  display: flex;
  width: 100%;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  align-items: baseline;
  gap: 10px;
  padding: 7px 8px;
  border-radius: var(--radius-xs);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 13.5px;
}
.te-slash-item .te-slash-label {
  flex: 0 0 auto;
  font-weight: 500;
}
.te-slash-item .te-slash-hint {
  flex: 1 1 auto;
  font-size: 11.5px;
  color: var(--ink-mute);
  text-align: right;
}
.te-slash-item.is-active,
.te-slash-item:hover {
  background: var(--accent-soft);
  color: var(--accent);
}
.te-slash-item.is-active .te-slash-hint,
.te-slash-item:hover .te-slash-hint {
  color: color-mix(in srgb, var(--accent) 70%, var(--ink-mute));
}
.te-slash-item.is-placeholder {
  opacity: 0.55;
  font-style: italic;
}
.te-slash-empty {
  padding: 12px 10px;
  font-family: var(--font-mono-www);
  font-size: 11.5px;
  color: var(--ink-mute);
}

/* ─── Link dialog ─────────────────────────────────────────────
   Centered modal with a focus trap. The trap, Esc-close, and
   restored-focus are wired in editor.entry.js — the CSS here is
   purely presentational. */
.te-link-dialog {
  position: fixed;
  inset: 0;
  background: rgb(14, 41, 96, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-modal);
  padding: 20px;
}
.te-link-dialog[hidden] {
  display: none;
}
.te-link-card {
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius);
  box-shadow: var(--shadow-pop);
  padding: 18px 18px 14px;
  width: min(420px, 100%);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.te-link-card h3 {
  margin: 0 0 4px;
  font-family: var(--font-read);
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
}
.te-link-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.te-link-field label {
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.te-link-field input {
  appearance: none;
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  padding: 7px 9px;
  outline: none;
}
.te-link-field input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.te-link-error {
  margin: 0;
  font-family: var(--font-mono-www);
  font-size: 11.5px;
  color: var(--danger);
}
.te-link-foot {
  display: flex;
  gap: 8px;
  margin-top: 4px;
  justify-content: flex-end;
  align-items: center;
}
.te-link-foot button {
  appearance: none;
  border: 1px solid var(--line-www);
  background: transparent;
  color: var(--ink);
  font-family: var(--font-pixel);
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.te-link-foot button:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.te-link-foot button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.te-link-foot .te-link-ok {
  /* AA: white text needs the dark accent tier. */
  background: var(--accent);
  color: var(--accent-on);
  border-color: var(--accent-fill-hover);
}
.te-link-foot .te-link-ok:hover {
  background: var(--accent-fill-hover);
  color: var(--accent-on);
}
.te-link-foot .te-link-remove[hidden] {
  display: none;
}

/* ============================================================
   Phase 3c: tables, math, callouts, footnotes, code-highlight
   ============================================================ */

/* ─── Tables ───────────────────────────────────────────────── */
.ProseMirror table,
.ProseMirror .te-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 18px;
  font-family: var(--font-ui);
  font-size: 15px;
  table-layout: fixed;
  overflow: hidden;
  border-radius: var(--radius-xs);
}
.ProseMirror table th,
.ProseMirror table td {
  border: 1px solid var(--line-www);
  padding: 8px 10px;
  vertical-align: top;
  text-align: left;
  min-width: 60px;
  position: relative;
}
.ProseMirror table th {
  background: var(--surface-2);
  font-weight: 600;
  font-family: var(--font-mono-www);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.ProseMirror table tr:nth-child(2n) td {
  background: color-mix(in srgb, var(--surface-2) 50%, transparent);
}
.ProseMirror table .selectedCell {
  background: var(--accent-soft) !important;
}
/* The table/code/image/video toolbar groups only render in their context. */
.te-tb-table-group.is-hidden,
.te-tb-code-group.is-hidden,
.te-tb-image-group.is-hidden,
.te-tb-video-group.is-hidden {
  display: none;
}
.te-tb-table-group.is-visible,
.te-tb-code-group.is-visible,
.te-tb-image-group.is-visible,
.te-tb-video-group.is-visible {
  display: inline-flex;
}

/* ─── Image NodeView: resize handle + caption ─────────────────── */
.ProseMirror .te-image-outer {
  display: block;
  margin: 14px 0;
  text-align: center; /* centers the inline-block inner */
  line-height: 0;
}
.ProseMirror .te-image-outer[data-align="left"] {
  text-align: left;
}
.ProseMirror .te-image-outer[data-align="right"] {
  text-align: right;
}
/* inner: inline-block sized to image — the resize handle anchors here */
.ProseMirror .te-image-inner {
  display: inline-block;
  position: relative;
  max-width: 100%;
  line-height: 0;
  vertical-align: bottom;
}
.ProseMirror .te-image-outer[data-align="full"] .te-image-inner {
  display: block;
  width: 100%;
}
.ProseMirror .te-image-img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0; /* override the base .ProseMirror img { margin: 18px auto } */
  border-radius: var(--radius-xs);
}
/* Selected / hovered ring on the inner (image-sized) wrapper */
.ProseMirror .te-image-outer.ProseMirror-selectednode .te-image-inner,
.ProseMirror .te-image-inner:hover {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Resize handle — right-edge drag bar anchored to .te-image-inner */
.te-resize-handle {
  position: absolute;
  right: -4px;
  top: 20%;
  bottom: 20%;
  width: 8px;
  background: var(--accent);
  cursor: col-resize;
  border-radius: 4px;
  z-index: 5;
  opacity: 0;
  pointer-events: none; /* invisible — don't eat clicks near the image edge */
  transition: opacity 0.1s;
}
.ProseMirror .te-image-outer.ProseMirror-selectednode .te-resize-handle,
.ProseMirror .te-image-inner:hover .te-resize-handle {
  opacity: 0.85;
  pointer-events: auto;
}
/* Caption slot — read-only span shown when caption attr is non-null */
.te-image-caption {
  display: block;
  padding: 5px 8px 3px;
  font-size: 14px;
  font-style: italic;
  color: var(--ink-soft);
  text-align: center;
  border-top: 1px dashed var(--line-www);
  margin-top: 4px;
  line-height: 1.4;
  white-space: pre-wrap;
}
/* Contextual toolbar dividers hide with their group */
.te-tb-divider.is-hidden {
  display: none;
}
@media (max-width: 700px) {
  .ProseMirror .te-image-outer[data-align="left"],
  .ProseMirror .te-image-outer[data-align="right"] {
    text-align: center;
  }
}

/* ─── Code blocks (lowlight syntax-highlight) ──────────────── */
.ProseMirror pre.te-code-block,
.ProseMirror pre code.hljs {
  position: relative;
}
.ProseMirror pre.te-code-block::before {
  content: attr(data-language);
  position: absolute;
  top: 6px;
  right: 8px;
  font-family: var(--font-mono-www);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  pointer-events: none;
}
/* Highlight.js token colours — neutral palette that works in both
   themes. Phase 11 may tune these against a proper Chroma palette. */
.ProseMirror pre .hljs-keyword,
.ProseMirror pre .hljs-selector-tag,
.ProseMirror pre .hljs-built_in,
.ProseMirror pre .hljs-name,
.ProseMirror pre .hljs-tag {
  color: var(--accent);
}
.ProseMirror pre .hljs-string,
.ProseMirror pre .hljs-title,
.ProseMirror pre .hljs-section,
.ProseMirror pre .hljs-attribute,
.ProseMirror pre .hljs-literal,
.ProseMirror pre .hljs-template-tag,
.ProseMirror pre .hljs-template-variable,
.ProseMirror pre .hljs-type,
.ProseMirror pre .hljs-addition {
  color: color-mix(in srgb, var(--accent) 70%, var(--ink));
}
.ProseMirror pre .hljs-comment,
.ProseMirror pre .hljs-quote,
.ProseMirror pre .hljs-deletion,
.ProseMirror pre .hljs-meta {
  color: var(--ink-mute);
  font-style: italic;
}
.ProseMirror pre .hljs-number,
.ProseMirror pre .hljs-regexp,
.ProseMirror pre .hljs-symbol,
.ProseMirror pre .hljs-variable,
.ProseMirror pre .hljs-link {
  color: var(--warn);
}
.ProseMirror pre .hljs-doctag,
.ProseMirror pre .hljs-strong {
  font-weight: 700;
}
.ProseMirror pre .hljs-emphasis {
  font-style: italic;
}
/* Language select inside the toolbar. */
.te-tb-lang-label {
  display: inline-flex;
  align-items: center;
}
.te-tb-lang {
  appearance: none;
  background: var(--surface);
  border: 1px solid var(--line-www);
  color: var(--ink);
  font-family: var(--font-mono-www);
  font-size: 11px;
  padding: 3px 24px 3px 8px;
  border-radius: 999px;
  cursor: pointer;
}
.te-tb-lang:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ─── Math ─────────────────────────────────────────────────── */
.ProseMirror .te-math {
  cursor: pointer;
  border-radius: 3px;
  padding: 0 2px;
  transition:
    background-color 120ms,
    color 120ms;
}
.ProseMirror .te-math-inline {
  display: inline-block;
  vertical-align: baseline;
  font-family: var(--font-mono-www);
}
.ProseMirror .te-math-block {
  display: block;
  text-align: center;
  margin: 14px 0;
  padding: 12px;
  font-family: var(--font-mono-www);
}
.ProseMirror .te-math:hover {
  background: var(--accent-soft);
}
.ProseMirror .te-math.is-editing {
  background: var(--surface-2);
  outline: 1px dashed var(--accent);
  cursor: text;
  padding: 4px 6px;
}
.ProseMirror .te-math-selected {
  background: var(--accent-soft);
  outline: 1px solid var(--accent);
}
.te-math-input {
  width: 100%;
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--ink);
  font-family: var(--font-mono-www);
  font-size: 14px;
  resize: vertical;
  padding: 0;
  min-height: 1em;
}

/* ─── Callouts (admonitions) ───────────────────────────────── */
.ProseMirror aside.callout {
  border-left: 3px solid var(--accent-bg);
  background: var(--accent-soft);
  border-radius: var(--radius-xs);
  padding: 12px 14px 4px 14px;
  margin: 14px 0;
  font-family: var(--font-ui);
  font-size: 15px;
  color: var(--ink);
  position: relative;
}
.ProseMirror aside.callout .callout-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 6px;
  font-weight: 400;
}
.ProseMirror aside.callout .callout-label::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-bg);
  display: inline-block;
}
.ProseMirror aside.callout.callout-tip {
  border-left-color: var(--ok);
  background: var(--ok-soft);
}
.ProseMirror aside.callout.callout-tip .callout-label,
.ProseMirror aside.callout.callout-tip .callout-label::before {
  color: var(--ok);
  background: var(--ok);
}
.ProseMirror aside.callout.callout-tip .callout-label {
  background: transparent;
}
.ProseMirror aside.callout.callout-warn {
  border-left-color: var(--warn-bright);
  background: var(--warn-soft);
}
.ProseMirror aside.callout.callout-warn .callout-label {
  color: var(--warn);
}
.ProseMirror aside.callout.callout-warn .callout-label::before {
  background: var(--warn-bright);
}
.ProseMirror aside.callout.callout-danger {
  border-left-color: var(--danger-bright);
  background: var(--danger-soft);
}
.ProseMirror aside.callout.callout-danger .callout-label {
  color: var(--danger);
}
.ProseMirror aside.callout.callout-danger .callout-label::before {
  background: var(--danger-bright);
}
.ProseMirror aside.callout .callout-body > p:last-child {
  margin-bottom: 8px;
}

/* ─── Footnotes ────────────────────────────────────────────── */
.ProseMirror sup.footnote-ref {
  font-family: var(--font-mono-www);
  font-size: 0.72em;
  line-height: 0;
  position: relative;
  top: -0.5em;
  color: var(--accent);
}
.ProseMirror sup.footnote-ref a {
  color: inherit;
  text-decoration: none;
}
.ProseMirror sup.footnote-ref a::before {
  content: "[";
  letter-spacing: 0;
}
.ProseMirror ol.footnote-list {
  margin-top: 28px;
  padding-top: 14px;
  border-top: 1px solid var(--line-www);
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--ink-soft);
  counter-reset: footnote;
  list-style: none;
  padding-left: 22px;
}
.ProseMirror ol.footnote-list li[data-footnote-item] {
  position: relative;
  margin-bottom: 6px;
}
.ProseMirror ol.footnote-list li[data-footnote-item]::before {
  content: "[" attr(data-label) "]";
  font-family: var(--font-mono-www);
  color: var(--accent);
  font-size: 11px;
  position: absolute;
  left: -24px;
  top: 1px;
}

/* ============================================================
   Phase 3d: productivity layer
   Find/replace, TOC sidebar, status bar, autosave pip,
   SEO preview, drag-handle.
   ============================================================ */

/* ─── Layout: TOC + SEO aux column ──────────────────────────── */
/*
   Phase 3d adds a thin aux column between the editor pane and the
   frontmatter sidebar. The aux column hosts the TOC sidebar and the
   SEO preview snippet, each in its own collapsible panel. Both
   panels persist their open/closed state to localStorage; the column
   is fully removed from the grid track when both are closed.

   The 3-column track is set on `.editor-layout` near the top of this
   file; the override below collapses to 2 columns when both panels
   are closed.
*/
.editor-layout[data-toc-open="false"][data-seo-open="false"] {
  grid-template-columns: minmax(0, 1fr) 340px;
}
.editor-layout[data-toc-open="false"][data-seo-open="false"] .ed-aux {
  display: none;
}

/* Base .ed-aux must precede the @media hides below — media queries add no
   specificity, so source order is what lets the responsive display:none win. */
.ed-aux {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
.ed-aux[hidden] {
  display: none;
}

/* Mid-band: below 1280px the 260px aux + 340px sidebar crowd the writing
   column, so drop the aux track first (TOC/SEO stay reachable via their
   toggles). The full single-column collapse still kicks in at 1180px. */
@media (max-width: 1280px) {
  .editor-layout,
  .editor-layout[data-toc-open="false"][data-seo-open="false"] {
    grid-template-columns: minmax(0, 1fr) 340px;
  }
  .ed-aux {
    display: none;
  }
}
@media (max-width: 1180px) {
  .editor-layout,
  .editor-layout[data-toc-open="false"][data-seo-open="false"] {
    grid-template-columns: minmax(0, 1fr);
  }
  .ed-aux {
    display: none;
  }
  /* Keep frontmatter reachable on tablets/phones — stack it full-width
     below the writing pane (it used to be display:none, stranding status,
     date, cover, SEO and revision history). It flows in the page scroll. */
  .ed-side {
    order: 2;
    overflow: visible;
  }
}

.ed-aux-panel {
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.ed-aux-panel[hidden] {
  display: none;
}
.ed-aux-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  font-family: var(--font-pixel);
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
  border-bottom: 1px solid var(--line-www);
}
.ed-aux-head > span:first-child {
  flex: 1;
}
.ed-aux-close {
  background: transparent;
  border: 0;
  color: var(--ink-mute);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 4px;
}
.ed-aux-close:hover,
.ed-aux-close:focus-visible {
  color: var(--ink);
  background: var(--surface-2);
  outline: 0;
}
.ed-aux-empty {
  margin: 14px;
  color: var(--ink-mute);
  font-size: 12px;
  line-height: 1.5;
}

/* ─── TOC sidebar ──────────────────────────────────────────── */
.ed-toc-body {
  padding: 6px 6px 12px;
  overflow-y: auto;
  max-height: calc(100vh - 240px);
}
.ed-toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.ed-toc-item {
  margin: 0;
}
.ed-toc-link {
  display: block;
  padding: 4px 10px;
  border-radius: var(--radius-xs);
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 13px;
  line-height: 1.35;
  overflow-wrap: anywhere;
  border-left: 2px solid transparent;
}
.ed-toc-link:hover,
.ed-toc-link:focus-visible {
  background: var(--surface-2);
  color: var(--ink);
  outline: 0;
}
.ed-toc-link.is-current {
  background: var(--accent-soft);
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: 600;
}
.ed-toc-item.ed-toc-level-1 .ed-toc-link {
  padding-left: 10px;
  font-weight: 600;
  color: var(--ink);
  font-size: 13.5px;
}
.ed-toc-item.ed-toc-level-2 .ed-toc-link {
  padding-left: 22px;
}
.ed-toc-item.ed-toc-level-3 .ed-toc-link {
  padding-left: 34px;
}
.ed-toc-item.ed-toc-level-4 .ed-toc-link {
  padding-left: 46px;
}
.ed-toc-item.ed-toc-level-5 .ed-toc-link {
  padding-left: 58px;
  font-size: 12px;
}
.ed-toc-item.ed-toc-level-6 .ed-toc-link {
  padding-left: 70px;
  font-size: 12px;
}

/* ─── SEO preview ───────────────────────────────────────────── */
.ed-seo-body {
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* The SERP preview keeps its Google-ish type/colors, but sits on the
   v2 card vocabulary (radius + hairline). */
.serp-card {
  background: #fff;
  color: #202124;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  font-family: arial, sans-serif;
  box-shadow: var(--shadow-card-xs);
  border: 1px solid var(--line-www);
}
:root[data-theme="dark"] .serp-card {
  background: #2c2c2c;
  color: #dadce0;
  border-color: rgb(255, 255, 255, 0.08);
  box-shadow: none;
}
.serp-url {
  display: flex;
  gap: 6px;
  align-items: center;
  font-size: 12px;
  color: #5f6368;
  margin-bottom: 4px;
  flex-wrap: wrap;
}
:root[data-theme="dark"] .serp-url {
  color: #9aa0a6;
}
.serp-url-sep {
  opacity: 0.6;
}
.serp-title {
  color: #1a0dab;
  font-size: 18px;
  line-height: 1.3;
  margin-bottom: 3px;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  overflow-wrap: anywhere;
}
:root[data-theme="dark"] .serp-title {
  color: #8ab4f8;
}
.serp-desc {
  font-size: 13px;
  line-height: 1.45;
  color: #4d5156;
  overflow-wrap: anywhere;
}
:root[data-theme="dark"] .serp-desc {
  color: #bdc1c6;
}
.ed-seo-meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ed-seo-meta li {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 6px 10px;
  font-family: var(--font-mono-www);
  font-size: 10.5px;
  color: var(--ink-mute);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.ed-seo-bar {
  grid-column: 1 / -1;
  display: block;
  height: 4px;
  background: var(--surface-3);
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}
.ed-seo-bar-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent-bg);
  transition: width 120ms ease-out;
}
.ed-seo-bar.is-over .ed-seo-bar-fill {
  background: var(--warn-bright);
}
.ed-seo-count {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.ed-seo-hint {
  margin: 0;
  font-size: 11px;
  color: var(--ink-mute);
  line-height: 1.5;
}

/* ─── Editor status bar (foot) refresh ──────────────────────── */
.editor-foot {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 20px;
  border-top: 1px solid var(--line-www);
  font-family: var(--font-mono-www);
  font-size: 11px;
  color: var(--ink-mute);
  letter-spacing: 0.04em;
}
.editor-foot-stats {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-variant-numeric: tabular-nums;
}
.editor-foot-sep {
  opacity: 0.5;
}
.editor-foot-r {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 14px;
}

/* ─── Autosave pip ─────────────────────────────────────────── */
.autosave-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 11px;
  letter-spacing: 0.04em;
  background: transparent;
  border: 1px solid transparent;
  transition:
    background-color 180ms ease,
    color 180ms ease,
    border-color 180ms ease;
}
.autosave-pip {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-faint);
  display: inline-block;
}
.autosave-indicator[data-state="idle"] {
  color: var(--ink-mute);
}
.autosave-indicator[data-state="dirty"] {
  color: var(--warn);
}
.autosave-indicator[data-state="dirty"] .autosave-pip {
  background: var(--warn-bright);
}
.autosave-indicator[data-state="saving"] {
  color: var(--ink-soft);
}
.autosave-indicator[data-state="saving"] .autosave-pip {
  background: var(--accent-bg);
  animation: te-autosave-spin 900ms linear infinite;
}
.autosave-indicator[data-state="saved"] {
  color: var(--ok);
  border-color: color-mix(in srgb, var(--ok) 40%, transparent);
  background: var(--ok-soft);
}
.autosave-indicator[data-state="saved"] .autosave-pip {
  background: var(--ok);
}
.autosave-indicator[data-state="error"] {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 40%, transparent);
  background: var(--danger-soft);
  cursor: pointer;
}
.autosave-indicator[data-state="error"] .autosave-pip {
  background: var(--danger-bright);
}
@keyframes te-autosave-spin {
  0% {
    opacity: 0.3;
    transform: scale(0.7);
  }
  50% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0.3;
    transform: scale(0.7);
  }
}

/* ─── Find & Replace modal ──────────────────────────────────── */
.te-find-modal {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: var(--z-dropdown);
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-pop);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 320px;
  max-width: calc(100% - 28px);
  box-sizing: border-box;
  font-family: var(--font-mono-www);
  font-size: 12px;
}
.te-find-modal[hidden] {
  display: none;
}
/* On a narrow editor pane the 320px min-width would push the modal past the
   right edge — pin it to both sides and let it shrink instead. */
@media (max-width: 560px) {
  .te-find-modal {
    left: 14px;
    right: 14px;
    min-width: 0;
  }
}
.te-find-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.te-find-input {
  flex: 1;
  min-width: 0;
  background: var(--surface-2);
  color: var(--ink);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
  padding: 5px 8px;
  font-family: var(--font-mono-www);
  font-size: 12px;
}
.te-find-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.te-find-input[aria-invalid="true"] {
  border-color: var(--danger);
}
.te-find-btn {
  background: transparent;
  border: 1px solid var(--line-www);
  color: var(--ink-soft);
  border-radius: var(--radius-xs);
  padding: 4px 8px;
  cursor: pointer;
  font-family: var(--font-mono-www);
  font-size: 11px;
  line-height: 1.2;
}
.te-find-btn:hover,
.te-find-btn:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
  outline: 0;
}
.te-find-close {
  margin-left: 4px;
}
.te-find-count {
  color: var(--ink-mute);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  padding: 0 4px;
  white-space: nowrap;
}
.te-find-row-opts {
  gap: 8px;
}
.te-find-opt {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--ink-mute);
  cursor: pointer;
}
.te-find-opt input {
  margin: 0;
  cursor: pointer;
}
.te-find-err {
  color: var(--danger);
  font-size: 11px;
  margin-left: auto;
}

/* ProseMirror find-match decoration */
.ProseMirror .te-find-match {
  background: color-mix(in srgb, var(--accent) 32%, transparent);
  border-radius: 2px;
  padding: 0 1px;
}
.ProseMirror .te-find-match-active {
  background: color-mix(in srgb, var(--warn-bright) 56%, transparent);
  outline: 1px solid var(--warn-bright);
}

/* ─── Drag handle (Phase 3d) ────────────────────────────────── */
/*
   tiptap-extension-global-drag-handle injects a single absolutely
   positioned <div class="drag-handle"> that follows the hovered
   block. We style it as a slim grab handle in the left margin of the
   editor; it disappears unless the cursor is over a block.
*/
.drag-handle {
  position: fixed;
  opacity: 0;
  width: 22px;
  height: 22px;
  /* Above the sticky editor toolbar (--z-sticky) so the grab handle stays
     clickable for a block whose top has scrolled under the toolbar band; still
     below popovers (--z-dropdown). */
  z-index: calc(var(--z-sticky) + 1);
  cursor: grab;
  border-radius: 4px;
  background-color: transparent;
  background-image: radial-gradient(circle, var(--ink-faint) 1.2px, transparent 1.4px);
  background-size: 6px 6px;
  background-position: center;
  background-repeat: repeat;
  transition:
    opacity 120ms ease,
    background-color 120ms ease;
}
.drag-handle:hover {
  opacity: 1;
  background-color: var(--surface-2);
}
.ProseMirror:hover ~ .drag-handle,
.ProseMirror:focus ~ .drag-handle,
.drag-handle.show {
  opacity: 0.55;
}
.drag-handle:active {
  cursor: grabbing;
  opacity: 1;
}
.ProseMirror.dragging {
  cursor: grabbing;
}
.ProseMirror .ProseMirror-selectednode.is-dragging,
.ProseMirror [data-dragging="true"] {
  opacity: 0.45;
}
/* Drop-cursor line shown while dragging */
.prosemirror-dropcursor-block,
.ProseMirror-dropcursor {
  background: var(--accent-bg) !important;
  height: 2px !important;
  border-radius: 1px;
}

/* ============================================================
   Phase 5e — Mobile authoring
   Below 768 px we collapse the rich toolbar to a sticky bottom
   action bar so writers on a phone still have one-tap access to
   the heavy-rotation block actions (bold, italic, link, list, H2).
   Tap targets are bumped to 44 × 44 per WCAG.
   ============================================================ */
@media (max-width: 768px) {
  .te-editor-toolbar {
    flex-wrap: wrap;
    gap: 8px;
    /* The rich controls become a fixed bottom bar on mobile (below), so the
       outer strip needn't stick — revert it to normal flow here. */
    position: static;
    background: transparent;
    border-bottom: 0;
    padding: 0 0 4px;
  }
  .te-editor-toolbar-rich {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 80;
    width: auto;
    background: var(--surface);
    border: 0;
    border-top: 1px solid var(--line-www);
    border-radius: 0;
    padding: 6px 10px;
    overflow-x: auto;
    flex-wrap: nowrap;
    box-shadow: var(--shadow-pop);
  }
  .te-editor-toolbar-rich .te-tb-divider {
    margin: 0 4px;
  }
  .te-tb-btn {
    min-width: 44px;
    min-height: 44px;
    font-size: 14px;
  }
  .ed-body,
  .ed-side {
    /* Leave room for the fixed bottom toolbar. The spacer must be on BOTH the
       editor body AND the settings sidebar: at this width the grid is single
       column with .ed-side ordered last, so .ed-side is the bottom of the
       scroll — without this its final controls hide behind the bar. */
    padding-bottom: 80px;
  }
  /* The fixed bottom toolbar would otherwise cover the status foot; its
     stats (words/chars/read + autosave) are mirrored in the topbar. */
  .editor-foot {
    display: none;
  }
}

/* Phase 5e — editor sidebar additions */
.ed-publish-badge {
  display: inline-block;
  margin-top: 6px;
  padding: 3px 8px;
  border-radius: var(--radius-xs);
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-mono-www);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.ed-publish-badge[hidden] {
  display: none;
}

#preview-link-out {
  margin-top: 8px;
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-xs);
  color: var(--ink);
  padding: 6px 8px;
  font-family: var(--font-mono-www);
  font-size: 11px;
}

/* ── Phase 7: paste-to-embed picker ─────────────────────────── */
/* Floats above the WYSIWYG view when a single bare URL is pasted.
   Three buttons: Insert embed (primary), Insert link, Cancel. */
.te-embed-paste {
  display: none;
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  padding: 6px;
  box-shadow: var(--shadow-pop);
  font-family: var(--font-mono-www);
  font-size: 12px;
  max-width: 520px;
}
.te-embed-paste-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.te-embed-paste-msg {
  color: var(--ink-soft);
  padding: 0 6px;
}
.te-embed-paste-btn {
  font-family: var(--font-mono-www);
  font-size: 12px;
  padding: 5px 10px;
  border: 1px solid var(--line-www);
  background: transparent;
  color: var(--ink);
  border-radius: var(--radius-xs);
  cursor: pointer;
}
.te-embed-paste-btn:hover,
.te-embed-paste-btn:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
  outline: none;
}
.te-embed-paste-btn.primary {
  /* AA: white text needs the dark accent tier. */
  background: var(--accent);
  color: var(--accent-on);
  border-color: var(--accent-fill-hover);
}
.te-embed-paste-btn.primary:hover,
.te-embed-paste-btn.primary:focus-visible {
  background: var(--accent-fill-hover);
  color: var(--accent-on);
}
.te-embed-paste-btn.ghost {
  padding: 5px 8px;
  border-color: transparent;
  color: var(--ink-mute);
}
.te-embed-paste-btn:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* ── Revision history modal ─────────────────────────────────────────
   Two-pane: a scrollable version list (left) + a read-only preview of the
   selected version (right). Reuses the base .modal/.modal-* from admin.css. */
.te-history-card {
  max-width: 760px;
}
.te-history-body {
  display: flex;
  gap: 0;
  padding: 0;
  max-height: min(60dvh, 540px);
}
.te-history-list {
  list-style: none;
  margin: 0;
  padding: 6px;
  width: 42%;
  min-width: 220px;
  overflow-y: auto;
  border-right: 1px solid var(--glass-border);
}
.te-history-empty,
.te-history-hint {
  color: var(--fg-mute);
  font-size: 12px;
  padding: 12px;
  margin: 0;
}
.te-history-row {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "kind label" "kind when";
  column-gap: 8px;
  align-items: center;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
}
.te-history-row:hover {
  background: var(--bg-elev-2, rgb(127 127 127 / 8%));
}
.te-history-row.active {
  background: var(--accent-soft, rgb(176 71 8 / 12%));
  outline: 1px solid var(--accent);
}
.te-history-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.te-history-kind {
  grid-area: kind;
  align-self: start;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 3px 6px;
  border-radius: 999px;
  white-space: nowrap;
}
.te-history-kind.k-git {
  background: var(--accent);
  color: var(--paper, #fff);
}
.te-history-kind.k-snapshot {
  background: rgb(127 127 127 / 18%);
  color: var(--fg-dim);
}
.te-history-label {
  grid-area: label;
  font-size: 12.5px;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.te-history-when {
  grid-area: when;
  font-size: 10.5px;
  color: var(--fg-mute);
}
.te-history-preview {
  flex: 1;
  overflow-y: auto;
  padding: 14px 16px;
  min-width: 0;
}
.te-history-ptitle {
  margin: 0 0 10px;
  font-size: 15px;
  color: var(--fg);
}
.te-history-pbody {
  margin: 0;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--fg-dim);
  white-space: pre-wrap;
  overflow-wrap: break-word;
}
.te-history-card .modal-foot {
  justify-content: space-between;
  align-items: center;
}
.te-history-foot-note {
  font-size: 11px;
  color: var(--fg-mute);
}
@media (max-width: 640px) {
  .te-history-body {
    flex-direction: column;
    max-height: min(70dvh, 600px);
  }
  .te-history-list {
    width: auto;
    border-right: none;
    border-bottom: 1px solid var(--glass-border);
    max-height: 40%;
  }
}

/* Live slug validation hint under the slug field. */
.ed-slug-msg {
  font-family: var(--font-mono-www);
  font-size: 11px;
  letter-spacing: 0.02em;
  margin-top: 4px;
  min-height: 14px;
  color: var(--ink-mute);
}
.ed-slug-msg.ok {
  color: var(--ok, #2c7a4b);
}
.ed-slug-msg.warn {
  color: var(--warn-strong, var(--warn));
}
.ed-slug-msg.err {
  color: var(--danger);
}

/* ── Visual image picker modal ──────────────────────────────────────── */
.te-imgpick-card {
  max-width: 720px;
}
.te-imgpick-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: min(66dvh, 560px);
}
.te-imgpick-search {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--line-www, var(--glass-border));
  border-radius: 7px;
  background: var(--surface, var(--bg-elev));
  color: var(--ink, var(--fg));
  font-size: 13px;
}
.te-imgpick-search:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.te-imgpick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px;
  overflow-y: auto;
  padding: 2px;
}
.te-imgpick-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0;
  border: 1px solid var(--line-www, var(--glass-border));
  border-radius: 8px;
  background: var(--surface, var(--bg-elev));
  cursor: pointer;
  overflow: hidden;
  text-align: left;
  transition:
    border-color 120ms,
    transform 120ms;
}
.te-imgpick-item:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}
.te-imgpick-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.te-imgpick-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  background: var(--surface-2, rgb(127 127 127 / 8%));
}
.te-imgpick-name {
  font-size: 10.5px;
  color: var(--ink-mute, var(--fg-mute));
  padding: 4px 6px 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Focus mode (distraction-free) ──────────────────────────────────
   Hide the chrome and center a comfortable writing column. Toggle via the
   topbar button or Esc. */
body.distraction-free .sidebar,
body.distraction-free .ed-aux,
body.distraction-free .ed-side,
body.distraction-free .editor-metrics {
  display: none !important;
}
body.distraction-free .editor-layout {
  grid-template-columns: minmax(0, 1fr);
}
body.distraction-free .editor-pane {
  max-width: 820px;
  margin: 0 auto;
  width: 100%;
}
body.distraction-free .shell {
  /* Reclaim the 232px sidebar track once it's hidden. */
  grid-template-columns: 1fr;
}
body.distraction-free #btn-zen {
  background: var(--accent-soft);
  color: var(--accent);
}

/* ── Spell + grammar proofreading ──────────────────────────────────── */
/* Squiggly underlines, coloured by issue kind (spelling/grammar/style). */
.ProseMirror .te-pr {
  text-decoration-line: underline;
  text-decoration-style: wavy;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  cursor: pointer;
}
.ProseMirror .te-pr-spelling {
  text-decoration-color: var(--danger);
}
.ProseMirror .te-pr-grammar {
  text-decoration-color: var(--info, #2f6bff);
}
.ProseMirror .te-pr-style {
  text-decoration-color: var(--warn-strong, var(--warn));
}

/* Suggestion card shown on clicking a squiggle. */
.te-pr-pop {
  position: absolute;
  z-index: var(--z-dropdown);
  background: var(--surface);
  border: 1px solid var(--line-www);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-pop);
  padding: 10px;
  width: 280px;
  max-width: calc(100% - 16px);
  box-sizing: border-box;
  font-family: var(--font-mono-www);
  font-size: 12px;
  color: var(--ink);
}
.te-pr-pop[hidden] {
  display: none;
}
.te-pr-kind {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 600;
  margin-bottom: 4px;
}
.te-pr-kind-spelling {
  color: var(--danger);
}
.te-pr-kind-grammar {
  color: var(--info, #2f6bff);
}
.te-pr-kind-style {
  color: var(--warn-strong, var(--warn));
}
.te-pr-msg {
  color: var(--ink);
  margin-bottom: 8px;
  line-height: 1.4;
}
.te-pr-reps {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.te-pr-rep {
  border: 1px solid var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: 3px 10px;
  font: inherit;
  cursor: pointer;
}
.te-pr-rep:hover {
  background: var(--accent);
  color: var(--surface);
}
.te-pr-actions {
  display: flex;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding-top: 8px;
}
.te-pr-action {
  background: none;
  border: none;
  padding: 0;
  color: var(--ink-mute);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
}
.te-pr-action:hover {
  color: var(--ink);
}

/* Issue-count badge on the toolbar toggle. */
.te-tb-proof {
  position: relative;
}
.te-tb-proof[data-count]:not([data-count=""])::after {
  content: attr(data-count);
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 14px;
  height: 14px;
  padding: 0 3px;
  box-sizing: border-box;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 9px;
  line-height: 14px;
  text-align: center;
  font-family: var(--font-mono-www);
}

/* New-post crash-recovery banner — shown on a blank editor when localStorage
   holds an unsaved draft from a previous session. */
.ed-restore-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 14px;
  padding: 10px 14px;
  border: 1px solid var(--accent, #5b8def);
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent, #5b8def) 12%, var(--surface, #fff));
  color: var(--ink, #1a1a1a);
  font-size: 14px;
}
.ed-restore-banner .ed-restore-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
