/* ==========================================================================
   Luogu Markdown + KaTeX Editor - Windows & Web Stylesheet
   ========================================================================== */

:root {
  /* Luogu Light Theme Colors */
  --bg-primary: #ffffff;
  --bg-secondary: #f8f9fa;
  --bg-tertiary: #f1f3f5;
  --bg-editor: #ffffff;
  --bg-preview: #ffffff;
  --text-primary: #2c3e50;
  --text-secondary: #6c757d;
  --text-muted: #adb5bd;
  --border-color: #e9ecef;
  --border-focus: #3498db;
  
  /* Brand & Accent Colors */
  --luogu-blue: #3498db;
  --luogu-blue-dark: #2980b9;
  --luogu-blue-light: #ebf5fb;
  --luogu-green: #2ecc71;
  --luogu-green-dark: #27ae60;
  --luogu-green-light: #eafaf1;
  --luogu-orange: #e67e22;
  --luogu-orange-light: #fef5e7;
  --luogu-red: #e74c3c;
  --luogu-red-light: #fdedec;
  --luogu-purple: #9b59b6;
  
  /* UI Dimensions & Shadows */
  --header-height: 48px;
  --toolbar-height: 44px;
  --statusbar-height: 28px;
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15), 0 4px 10px rgba(0, 0, 0, 0.08);
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  
  /* Fonts */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
  --font-mono: "Cascadia Code", "Fira Code", "Consolas", "Courier New", monospace;
  --font-math: "KaTeX_Main", "Times New Roman", serif;
}

/* Dark Theme */
[data-theme="dark"] {
  --bg-primary: #1e1e1e;
  --bg-secondary: #252526;
  --bg-tertiary: #2d2d30;
  --bg-editor: #1e1e1e;
  --bg-preview: #1e1e1e;
  --text-primary: #d4d4d4;
  --text-secondary: #9da5b4;
  --text-muted: #5c6370;
  --border-color: #333333;
  --border-focus: #007acc;
  
  --luogu-blue: #007acc;
  --luogu-blue-dark: #005999;
  --luogu-blue-light: #1a2f42;
  --luogu-green: #388e3c;
  --luogu-green-light: #1e3323;
  --luogu-orange: #d97706;
  --luogu-orange-light: #3d2b14;
  --luogu-red: #d32f2f;
  --luogu-red-light: #3b1b1b;
}

/* Academic White Theme */
[data-theme="academic"] {
  --bg-primary: #fafafa;
  --bg-secondary: #f4f4f5;
  --bg-tertiary: #e4e4e7;
  --bg-editor: #ffffff;
  --bg-preview: #ffffff;
  --text-primary: #18181b;
  --text-secondary: #52525b;
  --text-muted: #a1a1aa;
  --border-color: #e4e4e7;
  --border-focus: #18181b;
  --luogu-blue: #2563eb;
  --luogu-blue-light: #eff6ff;
}

/* Reset & Base */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-primary);
  background-color: var(--bg-primary);
  -webkit-font-smoothing: antialiased;
}

/* App Container Layout */
#app {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

/* Header & Titlebar */
.app-header {
  height: var(--header-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  user-select: none;
  z-index: 100;
  position: relative;
}

.brand-section {
  display: flex;
  align-items: center;
  gap: 8px;
}

.app-title-group {
  display: flex;
  flex-direction: column;
}

.app-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: 8px;
}

.app-badge {
  font-size: 10px;
  padding: 2px 7px;
  background: var(--luogu-blue-light);
  color: var(--luogu-blue);
  border-radius: 10px;
  font-weight: 500;
  letter-spacing: 0.3px;
}

.header-center {
  display: flex;
  align-items: center;
  gap: 8px;
}

.doc-name-input {
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  text-align: center;
  transition: all 0.2s;
  min-width: 180px;
}

.doc-name-input:hover {
  background: var(--bg-tertiary);
}

.doc-name-input:focus {
  background: var(--bg-primary);
  border-color: var(--border-focus);
  outline: none;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
}

/* Button Styles */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 12px;
  font-size: 12px;
  font-weight: 500;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
  background: var(--bg-primary);
  color: var(--text-primary);
  cursor: pointer;
  transition: all 0.15s ease;
  user-select: none;
  white-space: nowrap;
}

.btn:hover {
  background: var(--bg-tertiary);
  border-color: var(--text-muted);
}

.btn-primary {
  background: var(--luogu-blue);
  color: #ffffff;
  border-color: var(--luogu-blue);
}

.btn-primary:hover {
  background: var(--luogu-blue-dark);
  border-color: var(--luogu-blue-dark);
}

.btn-success {
  background: var(--luogu-green);
  color: #ffffff;
  border-color: var(--luogu-green);
}

.btn-success:hover {
  background: var(--luogu-green-dark);
  border-color: var(--luogu-green-dark);
}

.btn-icon-only {
  padding: 5px 8px;
}

.btn svg {
  width: 14px;
  height: 14px;
}

/* Toolbar */
.toolbar-container {
  height: var(--toolbar-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  padding: 0 12px;
  gap: 4px;
  overflow: visible;
  user-select: none;
  z-index: 50;
  position: relative;
}

.toolbar-group {
  display: flex;
  align-items: center;
  gap: 2px;
  position: relative;
}

.toolbar-divider {
  width: 1px;
  height: 20px;
  background: var(--border-color);
  margin: 0 6px;
  flex-shrink: 0;
}

.tool-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  min-width: 30px;
  padding: 0 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  cursor: pointer;
  white-space: nowrap;
  font-size: 12px;
  transition: background-color 0.1s, border-color 0.1s;
}

.tool-btn:hover {
  background: var(--bg-tertiary);
  border-color: var(--border-color);
}

.tool-btn.active {
  background: var(--luogu-blue-light);
  color: var(--luogu-blue);
  border-color: var(--luogu-blue);
}

.tool-btn svg {
  width: 16px;
  height: 16px;
}

/* Dropdown Tool */
.tool-dropdown {
  position: relative;
  display: inline-flex;
}

.dropdown-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0;
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.18), 0 3px 8px rgba(0, 0, 0, 0.08);
  min-width: 190px;
  max-width: 340px;
  z-index: 9999;
  padding: 6px;
}

/* Invisible hover bridge */
.dropdown-menu::before {
  content: "";
  position: absolute;
  top: -12px;
  left: 0;
  right: 0;
  height: 12px;
  background: transparent;
}

/* Right-side dropdown alignment */
.header-actions .dropdown-menu,
.dropdown-menu-right,
.toolbar-container > div:last-child .dropdown-menu {
  left: auto !important;
  right: 0 !important;
}

.tool-dropdown:hover .dropdown-menu,
.tool-dropdown.open .dropdown-menu {
  display: block;
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  font-size: 12px;
  color: var(--text-primary);
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

.dropdown-item:hover {
  background: var(--bg-tertiary);
  color: var(--luogu-blue);
}

.dropdown-item svg {
  width: 14px;
  height: 14px;
}

/* Main Workspace Split View */
.main-workspace {
  flex: 1;
  display: flex;
  width: 100%;
  height: calc(100vh - var(--header-height) - var(--toolbar-height) - var(--statusbar-height));
  overflow: hidden;
  position: relative;
  z-index: 1;
}

/* Editor Pane */
.editor-pane {
  flex: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--bg-editor);
  border-right: 1px solid var(--border-color);
  position: relative;
  min-width: 250px;
}

.pane-header {
  height: 28px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  user-select: none;
}

.editor-wrapper {
  flex: 1;
  display: flex;
  position: relative;
  overflow: hidden;
}

.line-numbers-gutter {
  position: relative;
  width: 52px;
  padding: 12px 10px 12px 8px;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-muted);
  background: transparent;
  user-select: none;
  overflow: visible;
  will-change: transform;
  /* Numbers are absolutely positioned at measured offsets because soft-wrapped
     lines have varying heights. */
  white-space: nowrap;
}

.gutter-num-abs {
  position: absolute;
  right: 10px;
}

/* Each gutter row must occupy exactly one text line so the numbers stay aligned
   with the textarea (which uses white-space: pre, i.e. one row per logical line). */
/* Stacking context for the line-number column. */
.gutter-stack {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  overflow: hidden;
  /* The number layer is translated to follow the textarea's scroll, so this
     container clips it. */
  background: var(--bg-secondary);
  border-right: 1px solid var(--border-color);
}



.editor-textarea {
  flex: 1;
  height: 100%;
  padding: 12px 16px;
  border: none;
  outline: none;
  resize: none;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-primary);
  background: var(--bg-editor);
  tab-size: 4;
  /* Soft-wrap long lines so nothing hides off-screen horizontally. A logical line may
     now span several visual rows, so the gutter can no longer assume one row per line;
     it measures each line's real height instead (see measureLineTops). */
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: break-word;
  overflow-x: hidden;
  overflow-y: auto;
}

/* Resizer Splitter */
.split-resizer {
  width: 6px;
  height: 100%;
  background: var(--border-color);
  cursor: col-resize;
  transition: background 0.15s;
  z-index: 5;
}

.split-resizer:hover, .split-resizer.resizing {
  background: var(--luogu-blue);
}

/* Preview Pane */
.preview-pane {
  flex: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--bg-preview);
  min-width: 250px;
  overflow: hidden;
}

.preview-content {
  flex: 1;
  padding: 24px 32px;
  overflow-y: auto;
  /* Positioning context for Typora's overlay editors, which are placed in the
     scroll container's own coordinate space. */
  position: relative;
  line-height: 1.75;
  color: var(--text-primary);
  word-break: break-word;
}

/* View Mode States */
.mode-editor-only .preview-pane,
.mode-editor-only .split-resizer {
  display: none !important;
}

.mode-preview-only .editor-pane,
.mode-preview-only .split-resizer {
  display: none !important;
}

/* Typora mode: the preview pane becomes the whole workspace and doubles as the
   editor. The source textarea stays in the DOM (it remains the canonical document
   and every other feature reads from it) but is hidden along with the resizer. */
.mode-typora .editor-pane,
.mode-typora .split-resizer {
  display: none !important;
}

.mode-typora .preview-pane {
  /* Centre the column the way a document editor does, rather than letting text run
     the full width of a maximised window. Tables and code blocks in solutions are
     wide, so this is deliberately roomier than a prose-only measure. */
  --typora-measure: 1000px;
}

.mode-typora .preview-content {
  max-width: var(--typora-measure);
  margin: 0 auto;
  padding: 24px 32px 45vh;
  /* Generous bottom padding keeps the last block reachable above the fold once it
     expands into a textarea. It doubles as the click target for "start a new
     paragraph at the end", so it must stay tall even for an empty document. */
  min-height: 100%;
  box-sizing: border-box;
  cursor: text;
}

/* Hint that blocks are clickable, without the noise of a permanent outline. */
.preview-content.typora-mode > * {
  border-radius: 4px;
  transition: background-color 0.12s ease;
}

.preview-content.typora-mode > *:hover {
  cursor: text;
}

/* Only tint blocks that have no surface of their own. A code block / table / bilibili
   card / callout paints its own background, and washing --bg-secondary over it made
   the light theme show pale syntax colours on white. */
.preview-content.typora-mode > *:hover:not(.luogu-code-block-wrapper):not(.luogu-code-block-wrap):not(.luogu-table-wrapper):not(.luogu-bilibili-container):not(details.luogu-callout):not(ul):not(ol) {
  background-color: var(--bg-secondary);
}

/* A list is edited one item at a time, so the hover affordance must point at the
   item under the pointer rather than washing over the whole list. Innermost wins:
   on a nested list only the deepest <li> containing the pointer lights up. */
.preview-content.typora-mode li:hover {
  cursor: text;
}
.preview-content.typora-mode li:hover > :not(ul):not(ol),
.preview-content.typora-mode li:hover {
  background-color: var(--bg-secondary);
  border-radius: 4px;
}
.preview-content.typora-mode li:hover ul,
.preview-content.typora-mode li:hover ol,
.preview-content.typora-mode li:has(li:hover) {
  background-color: transparent;
}

/* Blocks that paint their own background must not be tinted by the generic hover
   above: a code block has a dark surface of its own, and washing --bg-secondary over
   it (or over a table's zebra striping) produced visibly wrong colours. Highlight
   them with a ring instead, which reads on both light and dark themes. */
.preview-content.typora-mode > .luogu-code-block-wrapper:hover,
.preview-content.typora-mode > .luogu-code-block-wrap:hover,
.preview-content.typora-mode > .luogu-table-wrapper:hover,
.preview-content.typora-mode > .luogu-bilibili-container:hover,
.preview-content.typora-mode > details.luogu-callout:hover {
  /* Deliberately does NOT touch background-color. These blocks paint their own
     surface (a code block stays dark even under the light theme); an earlier version
     forced `transparent` here, which dropped that background and left pale syntax
     colours on white. The ring alone is enough of a hover affordance. */
  box-shadow: 0 0 0 2px var(--luogu-blue-light, rgba(52, 152, 219, 0.35));
}

/* Inside those blocks, highlight the actual sub-target instead. */
.preview-content.typora-mode .luogu-table td:hover,
.preview-content.typora-mode .luogu-table th:hover {
  box-shadow: inset 0 0 0 2px var(--luogu-blue);
  cursor: text;
}

/* Only the title text is editable, so it is the only part of the header that gets a
   text cursor and an edit affordance; the rest of the summary still toggles. */
.preview-content.typora-mode .luogu-callout-title:hover {
  cursor: text;
  text-decoration: underline dashed;
  text-underline-offset: 3px;
  background: rgba(52, 152, 219, 0.12);
  border-radius: 3px;
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.12);
}

.preview-content.typora-mode .luogu-callout-summary {
  cursor: pointer;
}

.preview-content.typora-mode .luogu-callout-icon:hover {
  cursor: pointer;
  filter: brightness(1.25);
}

.preview-content.typora-mode pre[data-code-body]:hover {
  cursor: text;
}

/* Sub-block editors sit inside an existing block, so they must not inherit the
   full-width block spacing the top-level editor uses. */
.typora-partial {
  margin: 0;
}


.typora-code-input {
  border-radius: 0;
  border-color: var(--luogu-blue);
  background: var(--code-bg, #2d2d2d);
  color: var(--code-fg, #ccc);
  tab-size: 4;
}

/* A cell / title editor should read as inline text, not as a block form field. */
.typora-inline-input {
  min-height: 0;
  padding: 2px 6px;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

.preview-content.typora-mode:focus {
  outline: none;
}

/* The in-place source editor swapped in for the block being edited. */
.typora-editing {
  margin: 4px 0;
}

.typora-block-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 2.4em;
  padding: 10px 12px;
  border: 1px solid var(--luogu-blue);
  border-radius: 4px;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: 'JetBrains Mono', 'Fira Code', Consolas, 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.7;
  resize: none;
  overflow: hidden;
  outline: none;
  white-space: pre-wrap;
  word-break: break-word;
  tab-size: 4;
}

.typora-block-input:focus {
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.18);
}

.typora-block-input::placeholder {
  color: var(--text-secondary);
  opacity: 0.6;
}

/* A brand-new paragraph is dashed until it has content, so it reads as a draft
   rather than as a block that already exists in the document. */
.typora-inserting .typora-block-input {
  border-style: dashed;
}

/* Status Bar */
.app-statusbar {
  height: var(--statusbar-height);
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  font-size: 11px;
  color: var(--text-secondary);
  user-select: none;
  z-index: 10;
  position: relative;
}

.status-left, .status-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.status-item {
  display: flex;
  align-items: center;
  gap: 4px;
}

.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--luogu-green);
}

.status-score-badge {
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 10px;
}

.status-score-good {
  background: var(--luogu-green-light);
  color: var(--luogu-green-dark);
}

.status-score-warn {
  background: var(--luogu-orange-light);
  color: var(--luogu-orange);
}

/* ==========================================================================
   Luogu Markdown Rendered Content Styles (预览与排版样式)
   ========================================================================== */

.preview-content h1,
.preview-content h2,
.preview-content h3,
.preview-content h4,
.preview-content h5,
.preview-content h6 {
  margin-top: 1.5em;
  margin-bottom: 0.6em;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.35;
}

.preview-content h1 { font-size: 1.85em; border-bottom: 1px solid var(--border-color); padding-bottom: 0.3em; }
.preview-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--border-color); padding-bottom: 0.25em; }
.preview-content h3 { font-size: 1.25em; }
.preview-content h4 { font-size: 1.1em; }
.preview-content h5 { font-size: 1em; }
.preview-content h6 { font-size: 0.9em; color: var(--text-secondary); }

.preview-content p {
  margin-bottom: 1em;
}

/* Emphasis & Inline Elements */
.preview-content strong {
  font-weight: 600;
  color: var(--text-primary);
}

.preview-content em {
  font-style: italic;
}

.preview-content del {
  text-decoration: line-through;
  color: var(--text-muted);
}

/* GFM footnotes. Rendered as a trailing <section> separated from the body, with
   small superscript references in the text. Mirrors remark-gfm's structure so the
   result matches what Luogu produces. */
.luogu-footnote-ref a {
  text-decoration: none;
  padding: 0 1px;
}

.luogu-footnotes {
  margin-top: 32px;
  padding-top: 12px;
  border-top: 1px solid var(--border-color, #d0d7de);
  font-size: 0.9em;
}

.luogu-footnotes-title {
  font-size: 1em;
  font-weight: 600;
  margin: 0 0 8px;
  color: var(--text-secondary, #57606a);
}

.luogu-footnotes-list {
  margin: 0;
  padding-left: 24px;
}

.luogu-footnote-item {
  margin: 4px 0;
}

.luogu-footnote-item p {
  margin: 0;
}

.luogu-footnote-back {
  text-decoration: none;
  margin-left: 4px;
}

.luogu-inline-code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 2px 6px;
  background: var(--bg-tertiary);
  color: #e06c75;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
}

.preview-content hr.luogu-hr {
  height: 2px;
  border: none;
  background: var(--border-color);
  margin: 1.5em 0;
}

.preview-content blockquote.luogu-blockquote {
  margin: 1em 0;
  padding: 8px 16px;
  border-left: 4px solid var(--luogu-blue);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.preview-content blockquote blockquote {
  margin: 0.5em 0;
  border-left-color: var(--luogu-purple);
}

/* Links & Images */
.preview-content a.luogu-link {
  color: var(--luogu-blue);
  text-decoration: none;
  transition: color 0.15s;
}

.preview-content a.luogu-link:hover {
  text-decoration: underline;
  color: var(--luogu-blue-dark);
}

.luogu-img-wrapper {
  display: inline-block;
  max-width: 100%;
  margin: 0.5em 0;
}

.luogu-img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.luogu-img-error {
  border: 1px dashed var(--luogu-red);
  padding: 10px;
  color: var(--luogu-red);
  background: var(--luogu-red-light);
}

/* Lists & Tasks */
.preview-content ul.luogu-list,
.preview-content ol.luogu-list {
  padding-left: 24px;
  margin-bottom: 1em;
}

.preview-content li {
  margin-bottom: 0.35em;
}

.preview-content ul.luogu-task-list {
  list-style-type: none;
  padding-left: 4px;
}

.luogu-task-item {
  display: block;
  margin-bottom: 6px;
}
.luogu-task-item > .luogu-checkbox-label {
  display: flex;
  align-items: center;
}

.luogu-checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.luogu-task-checkbox {
  width: 15px;
  height: 15px;
  accent-color: var(--luogu-blue);
  cursor: pointer;
  flex: none;
}

/* The checkbox is the only place that toggles; everything else on the row edits the
   item. Make that split visible: a pointer cursor on the box, a text caret on the
   label text (which would otherwise inherit the label's pointer). */
.preview-content.typora-mode .luogu-checkbox-label { cursor: text; }
.preview-content.typora-mode .luogu-task-checkbox { cursor: pointer; }
.preview-content.typora-mode .luogu-task-checkbox:hover {
  outline: 2px solid var(--luogu-blue-light, rgba(52, 152, 219, 0.45));
  outline-offset: 1px;
}

/* Luogu Code Blocks - with Auto-Wrapping in Preview */
.luogu-code-block-wrapper {
  margin: 1.2em 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  background: #282c34;
  color: #abb2bf;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  width: 100%;
  box-sizing: border-box;
}

.luogu-code-pre,
.luogu-code-pre code,
.luogu-code-pre code[class*="language-"],
.luogu-code-pre pre[class*="language-"],
pre[class*="language-"],
code[class*="language-"] {
  white-space: pre-wrap !important;
  word-break: break-all !important;
  word-wrap: break-word !important;
  overflow-wrap: anywhere !important;
}

.luogu-code-pre code,
.luogu-code-pre code[class*="language-"] {
  display: block !important;
  /* Grow to the widest line rather than to the visible width, so that when the
     block is scrolled right the highlight backgrounds keep covering the row
     instead of ending at the original fold. min-width keeps short blocks full
     width so a highlight still spans the pane. */
  width: max-content !important;
  min-width: 100% !important;
  box-sizing: border-box !important;
}

.luogu-code-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 14px;
  background: #21252b;
  border-bottom: 1px solid #181a1f;
  font-size: 11px;
  font-weight: 600;
  user-select: none;
  gap: 8px;
}

.luogu-code-lang {
  color: #61afef;
  letter-spacing: 0.5px;
  flex-shrink: 0;
}

.luogu-code-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap !important;
}

.luogu-code-copy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 3px 10px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius-sm);
  color: #abb2bf;
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap !important;
  flex-shrink: 0 !important;
  min-width: 64px;
  height: 24px;
  line-height: 1;
}

.luogu-code-copy-btn:hover {
  background: rgba(255, 255, 255, 0.15);
  color: #ffffff;
}

.luogu-code-copy-btn .copy-text {
  white-space: nowrap !important;
  display: inline-block;
}

.luogu-code-copy-btn .copy-icon {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
  display: inline-block;
}

.luogu-code-pre {
  margin: 0;
  padding: 12px 0;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  /* The whole block scrolls horizontally, so a single scrollbar sits at the very
     bottom of the code block. Scrolling per line instead gave every overflowing
     line its own scrollbar, wedged between that line and the next — it ate into
     the line's height and covered the line below it. The gutter numbers stay put
     because they are position:sticky against this scroll container. */
  overflow-x: auto !important;
  width: 100%;
  box-sizing: border-box;
  display: block !important;
}

.code-line {
  /* Lines do not scroll individually — see .luogu-code-pre. Each row must be at
     least as wide as the widest line so that highlight backgrounds and the gutter
     tint extend across the full scrolled width instead of stopping at the fold;
     `width: max-content` with `min-width: 100%` achieves both. */
  display: block !important;
  white-space: pre !important;
  padding: 0 16px;
  /* Inherit the <code> width (widest line) so every row — highlighted or not —
     paints across the whole scrollable width. */
  min-width: 100%;
  box-sizing: border-box;
}

.code-line-number {
  display: inline-block !important;
  position: sticky;
  left: 0;
  width: 36px;
  min-width: 36px;
  padding-right: 14px;
  margin-right: 10px;
  text-align: right;
  color: #5c6370;
  background: #282c34;
  border-right: 1px solid #3e4451;
  user-select: none;
  vertical-align: top;
  z-index: 2;
}

.code-line-text {
  /* Code text beside the gutter, kept on a single row (no wrapping) so it aligns
     to its own line number; long lines scroll horizontally within the line. */
  display: inline !important;
  vertical-align: top;
  white-space: pre !important;
  word-break: normal !important;
  word-wrap: normal !important;
  overflow-wrap: normal !important;
}

.code-line-highlighted {
  background: rgba(229, 192, 123, 0.15);
  border-left: 3px solid #e5c07b;
  padding-left: 13px;
}

/* When a line is highlighted, the sticky gutter cell must composite the same
   translucent highlight over the code background — otherwise the gutter shows a
   plain dark block that sits "one layer above" the highlight. (The linear-gradient
   layer + opaque base keeps it opaque so it still masks horizontally-scrolled code.) */
.code-line-highlighted .code-line-number {
  background: linear-gradient(rgba(229, 192, 123, 0.15), rgba(229, 192, 123, 0.15)), #282c34;
}

/* Tables & Merged Cells */
.luogu-table-wrapper {
  width: 100%;
  overflow-x: auto;
  margin: 1.2em 0;
}

.luogu-table-center-wrapper {
  display: flex;
  justify-content: center;
  margin: 1.4em auto;
}

.luogu-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  border: 1px solid var(--border-color);
  background: var(--bg-primary);
}

.luogu-table-center-wrapper .luogu-table {
  width: auto;
  max-width: 100%;
}

.luogu-table th,
.luogu-table td {
  padding: 8px 14px;
  border: 1px solid var(--border-color);
}

.luogu-table th {
  background: var(--bg-secondary);
  font-weight: 600;
  color: var(--text-primary);
}

.luogu-table tr:nth-child(even) td {
  background: var(--bg-secondary);
}

/* Tuack / Cute-Table Style (洛谷 Tuack 竞赛风格表格) */
.luogu-tuack-table {
  border: 2px solid #3498db;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.luogu-tuack-table th {
  background: #3498db;
  color: #ffffff;
  border: 1px solid #2980b9;
  font-weight: 600;
  text-align: center;
}

.luogu-tuack-table td {
  border: 1px solid #d4e6f1;
}

.luogu-tuack-table tr:nth-child(even) td {
  background: #f4f9fd;
}

.luogu-tuack-table tr:hover td {
  background: #eaf2f8;
}

/* Dark mode: make the Tuack (contest) table use a dark-appropriate palette
   instead of the hardcoded light blue. */
[data-theme="dark"] .luogu-tuack-table {
  border-color: #1f6feb;
}
[data-theme="dark"] .luogu-tuack-table th {
  background: #1f6feb;
  border-color: #1759c4;
}
[data-theme="dark"] .luogu-tuack-table td {
  border-color: #2d3a4a;
}
[data-theme="dark"] .luogu-tuack-table tr:nth-child(even) td {
  background: #1c2530;
}
[data-theme="dark"] .luogu-tuack-table tr:hover td {
  background: #24303e;
}

.luogu-cute-centered-table {
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
}

.luogu-cute-centered-table th {
  background: var(--luogu-blue-light);
  color: #1f618d;
  font-weight: 600;
  text-align: center;
}

/* Align Blocks (居中 & 居右排版) */
.luogu-align-center {
  text-align: center;
  margin: 1em 0;
}

.luogu-align-right {
  text-align: right;
  margin: 1em 0;
}

/* Typora mode: alignment containers are otherwise invisible — centred text looks
   the same whether it came from `:::align{center}` or a lone short line — so the
   editor marks their extent with a dashed rule and a corner label, the same idea as
   a callout's coloured edge. Screen/print/export are untouched. */
.preview-content.typora-mode [class*="luogu-align-"] {
  position: relative;
  border: 1px dashed var(--border-color);
  border-radius: 4px;
  padding: 10px 12px;
  margin-top: 1.5em;
}

.preview-content.typora-mode [class*="luogu-align-"]::before {
  position: absolute;
  top: -0.75em;
  left: 10px;
  padding: 0 6px;
  border-radius: 3px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: 0.02em;
  pointer-events: none;
}

.preview-content.typora-mode .luogu-align-left::before { content: "居左"; }
.preview-content.typora-mode .luogu-align-center::before { content: "居中"; }
.preview-content.typora-mode .luogu-align-right::before { content: "居右"; }

/* The badge is the control that switches left/center/right, so make it read as
   clickable rather than as a passive label. */
.preview-content.typora-mode [class*="luogu-align-"]::before { cursor: pointer; }
.preview-content.typora-mode [class*="luogu-align-"]:hover::before {
  background: var(--luogu-blue, #3498db);
  color: #fff;
}

.preview-content.typora-mode [class*="luogu-align-"]:hover {
  border-color: var(--luogu-blue);
}

.preview-content.typora-mode .luogu-epigraph {
  border: 1px dashed var(--border-color);
  border-radius: 4px;
  margin-top: 1.6em;
}

.preview-content.typora-mode .luogu-epigraph::after {
  content: "引言";
  position: absolute;
  top: -0.75em;
  left: 10px;
  padding: 0 6px;
  border-radius: 3px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  pointer-events: none;
}

/* Epigraph (引言) */
.luogu-epigraph {
  position: relative;
  margin: 1.5em 0;
  padding: 16px 20px 16px 48px;
  background: var(--bg-secondary);
  border-left: 4px solid var(--luogu-blue);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.luogu-epigraph-quote-mark {
  position: absolute;
  top: 6px;
  left: 14px;
  font-size: 38px;
  line-height: 1;
  font-family: Georgia, serif;
  color: var(--luogu-blue);
  opacity: 0.5;
  user-select: none;
}

.luogu-epigraph-body {
  font-style: italic;
  font-size: 14px;
  color: var(--text-primary);
  margin-bottom: 6px;
}

.luogu-epigraph-author {
  text-align: right;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
}

/* Foldable Callouts (折叠框: info, success, warning, error) */
.luogu-callout {
  margin: 1.2em 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  background: var(--bg-primary);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: all 0.2s ease;
}

.luogu-callout-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  user-select: none;
  list-style: none;
  transition: background 0.15s;
}

.luogu-callout-summary::-webkit-details-marker {
  display: none;
}

.luogu-callout-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.callout-icon-svg {
  width: 18px;
  height: 18px;
}

.luogu-callout-title {
  /* Only as wide as the text, with `margin-right:auto` keeping the arrow pinned
     right. It used to be `flex:1`, which stretched the span across the whole
     summary — so in Typora mode a click anywhere on the header row landed on the
     title and opened the rename editor instead of expanding the box. */
  flex: 0 1 auto;
  margin-right: auto;
  min-width: 0;
}

.luogu-callout-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  transition: transform 0.2s ease;
}

.arrow-svg {
  width: 14px;
  height: 14px;
}

.luogu-callout[open] > .luogu-callout-summary .luogu-callout-arrow {
  transform: rotate(180deg);
}

.luogu-callout-content {
  padding: 12px 16px;
  border-top: 1px solid var(--border-color);
  background: var(--bg-primary);
  font-size: 13px;
}

/* Callout Color Schemes */
.luogu-callout-info {
  border-left: 4px solid var(--luogu-blue);
}
.luogu-callout-info > .luogu-callout-summary {
  background: var(--luogu-blue-light);
  color: #1f618d;
}

.luogu-callout-success {
  border-left: 4px solid var(--luogu-green);
}
.luogu-callout-success > .luogu-callout-summary {
  background: var(--luogu-green-light);
  color: #196f3d;
}

.luogu-callout-warning {
  border-left: 4px solid var(--luogu-orange);
}
.luogu-callout-warning > .luogu-callout-summary {
  background: var(--luogu-orange-light);
  color: #b9770e;
}

.luogu-callout-error {
  border-left: 4px solid var(--luogu-red);
}
.luogu-callout-error > .luogu-callout-summary {
  background: var(--luogu-red-light);
  color: #943126;
}

/* Bilibili Video Container */
.luogu-bilibili-container {
  margin: 1.5em 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  overflow: hidden;
  background: #000000;
  box-shadow: var(--shadow-md);
}

.luogu-bilibili-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 12px;
  background: #232323;
  color: #ffffff;
  font-size: 11px;
}

.luogu-bilibili-badge {
  background: #fb7299;
  color: #ffffff;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  font-weight: bold;
}

.luogu-bilibili-link {
  display: flex;
  align-items: center;
  gap: 4px;
  color: #00a1d6;
  text-decoration: none;
}

.luogu-bilibili-link:hover {
  text-decoration: underline;
}

.ext-icon {
  width: 12px;
  height: 12px;
}

.luogu-bilibili-player-wrapper {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* 16:9 ratio */
}

.luogu-bilibili-player-wrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
}

/* Click-to-load placeholder shown in place of the Bilibili iframe. Keeps the app
   fully offline (and free of third-party trackers) until the user opts in. */
.luogu-bilibili-facade {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  cursor: pointer;
  background: #111827;
  color: #e5e7eb;
  font-size: 13px;
  font-family: inherit;
  transition: background 0.15s;
}

.luogu-bilibili-facade:hover {
  background: #1f2937;
}

.luogu-bilibili-facade:focus-visible {
  outline: 2px solid #38bdf8;
  outline-offset: -2px;
}

.luogu-bilibili-play-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #fb7299;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.luogu-bilibili-play-icon svg {
  width: 28px;
  height: 28px;
  margin-left: 3px;
}

/* KaTeX Formulas */
.luogu-math-display {
  margin: 1.2em 0;
  overflow-x: auto;
  overflow-y: hidden;
  text-align: center;
  padding: 6px 0;
}

.luogu-math-inline {
  display: inline-block;
  padding: 0 2px;
}

.katex-error {
  color: var(--luogu-red);
  background: var(--luogu-red-light);
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* ==========================================================================
   Modals & Drawers (模态框、公式抽屉、表格生成器)
   ========================================================================== */

.modal-overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  /* Solid dim only — backdrop-filter:blur forces a full-viewport backdrop
     repaint on every hover style change inside the dialog (esp. KaTeX cards). */
  background: rgba(0, 0, 0, 0.48);
  z-index: 10000;
  align-items: center;
  justify-content: center;
}

.modal-overlay.active {
  display: flex;
}

.modal-dialog {
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 90%;
  max-width: 580px;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: modalFadeIn 0.2s ease;
}

.modal-dialog-large {
  max-width: 960px;
  width: 94%;
}

@keyframes modalFadeIn {
  from { opacity: 0; transform: translateY(-10px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.modal-header {
  height: 48px;
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border-color);
  background: var(--bg-secondary);
  flex-shrink: 0;
}

.modal-title {
  font-size: 15px;
  font-weight: 600;
}

.modal-close-btn {
  background: transparent;
  border: none;
  font-size: 20px;
  cursor: pointer;
  color: var(--text-secondary);
  padding: 4px;
  line-height: 1;
}

.modal-close-btn:hover {
  color: var(--text-primary);
}

.modal-body {
  padding: 20px;
  overflow-y: auto;
  flex: 1;
}

.modal-footer {
  padding: 12px 20px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  border-top: 1px solid var(--border-color);
  background: var(--bg-secondary);
  flex-shrink: 0;
}

/* Form Controls in Modal */
.form-group {
  margin-bottom: 16px;
}

.form-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--text-primary);
}

.form-input, .form-select {
  width: 100%;
  padding: 8px 12px;
  font-size: 13px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  color: var(--text-primary);
  outline: none;
  transition: border-color 0.15s;
}

.form-input:focus, .form-select:focus {
  border-color: var(--border-focus);
}

.form-hint {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
}

/* Formula Drawer Grid
   Hover must stay GPU-cheap: KaTeX trees are deep, so never change the card's
   own background/border on :hover (that invalidates paint for every nested
   span). Instead, fade a single ::before overlay via opacity only. */
.math-tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 16px;
  overflow-x: auto;
  padding-bottom: 6px;
  /* Isolate tab strip repaints from the formula grid below. */
  contain: layout style;
}

.math-tab-btn {
  padding: 6px 12px;
  border: none;
  background: transparent;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: none;
}

.math-tab-btn.active {
  background: var(--luogu-blue-light);
  color: var(--luogu-blue);
  font-weight: 600;
}

/* Panels stay mounted; only [hidden] toggles. Avoids re-parsing KaTeX HTML. */
.math-tab-panel {
  display: block;
}

.math-tab-panel[hidden] {
  display: none !important;
}

.math-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 8px;
  padding: 2px;
}

.math-grid-wide {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.math-item-card {
  /* <button> reset — cards are real buttons for a11y + no inline onclick */
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  color: inherit;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 8px 6px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  cursor: pointer;
  min-height: 66px;
  max-width: 100%;
  overflow: hidden;
  box-sizing: border-box;
  position: relative;
  /* Isolate each card so hover compositing never dirties siblings. */
  contain: layout style paint;
  transition: none !important;
}

/* Hover highlight is a separate overlay layer — only its opacity changes. */
.math-item-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  /* 1px inset ring + fill without touching the card's own border/background */
  box-shadow: inset 0 0 0 1px var(--luogu-blue);
  background: var(--luogu-blue-light);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  /* opacity-only = compositor-friendly, no layout/paint of KaTeX children */
  transition: opacity 0.06s linear;
}

.math-item-card:hover::before,
.math-item-card:focus-visible::before {
  opacity: 0.92;
}

.math-item-card:focus {
  outline: none;
}

.math-item-card:focus-visible {
  outline: 2px solid var(--luogu-blue);
  outline-offset: 1px;
}

.math-item-card.card-wide {
  grid-column: span 2;
}

/* IMPORTANT: do NOT change background/border on the card itself on :hover.
   That path is what made KaTeX hover feel sticky. */

.math-item-preview {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 100%;
  /* overflow:auto creates a scrollable layer that reflows on every hover paint;
     clip keeps glyphs inside without a scrollport. */
  overflow: hidden;
  font-size: 13px;
  margin-bottom: 4px;
  padding: 2px 0;
  pointer-events: none !important;
  /* Keep KaTeX subtree from participating in hit-testing / hover invalidation. */
  contain: layout style paint;
}

.math-item-preview * {
  pointer-events: none !important;
}

.math-item-preview .katex {
  /* Prevent KaTeX from expanding the card and causing sibling reflow */
  max-width: 100%;
  font-size: 1.05em;
}

.math-item-preview .katex-display {
  margin: 0 !important;
  font-size: 0.9em;
}

.math-item-label {
  position: relative;
  z-index: 1;
  font-size: 11px;
  color: var(--text-secondary);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
  pointer-events: none !important;
}

/* Table Generator Grid */
.table-builder-grid-preview {
  margin: 14px 0;
  overflow-x: auto;
}

.grid-table-editor {
  border-collapse: collapse;
  width: 100%;
}

.grid-table-editor td, .grid-table-editor th {
  border: 1px solid var(--border-color);
  padding: 6px 8px;
  position: relative;
}

.grid-cell-input {
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  font-size: 12px;
  text-align: center;
}

.grid-cell-tools {
  display: flex;
  gap: 2px;
  justify-content: center;
  margin-top: 4px;
}

.btn-mini {
  padding: 1px 4px;
  font-size: 10px;
  border-radius: 2px;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  cursor: pointer;
}

/* Toast Notifications */
.toast-container {
  position: fixed;
  bottom: 38px;
  right: 20px;
  z-index: 20000;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.toast {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: #2c3e50;
  color: #ffffff;
  border-radius: var(--radius-md);
  font-size: 12px;
  box-shadow: var(--shadow-lg);
  animation: toastSlideIn 0.2s ease;
}

.toast-success { background: #27ae60; }
.toast-error { background: #e74c3c; }
.toast-info { background: #2980b9; }

@keyframes toastSlideIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   Print & PDF Stylesheet (100% 解决所有 PDF 导出与打印 Bug)
   ========================================================================== */
@media print {
  /* Force a light (white) palette for the printed PDF, regardless of the editor's
     current theme. Without this, dark-mode variables leak into content elements
     (inline code, tables, callouts, blockquotes, epigraph) and print as dark
     blocks on a white page. Sources are the LIGHT palette values. */
  .print-light:root,
  .print-light[data-theme="light"],
  .print-light[data-theme="dark"],
  .print-light[data-theme="academic"] {
    --bg-primary: #ffffff;
    --bg-secondary: #f6f8fa;
    --bg-tertiary: #eef1f4;
    --bg-editor: #ffffff;
    --bg-preview: #ffffff;
    --text-primary: #24292e;
    --text-secondary: #57606a;
    --text-muted: #6e7781;
    --border-color: #d0d7de;
    --luogu-blue: #3498db;
    --luogu-blue-light: #eff6fb;
    --luogu-green: #2eaf5e;
    --luogu-green-light: #eafaf1;
    --luogu-orange: #e67e22;
    --luogu-orange-light: #fef5e7;
    --luogu-red: #e74c3c;
    --luogu-red-light: #fdecea;
  }

  /* Tuack table: its palette is hardcoded (light) so ensure dark-mode overrides
     don't leak into the printed PDF. */
  .luogu-tuack-table {
    border-color: #3498db !important;
  }
  .luogu-tuack-table th {
    background: #3498db !important;
    border-color: #2980b9 !important;
  }
  .luogu-tuack-table td {
    border-color: #d4e6f1 !important;
  }
  .luogu-tuack-table tr:nth-child(even) td {
    background: #f4f9fd !important;
  }
  .luogu-tuack-table tr:hover td {
    background: #eaf2f8 !important;
  }

  @page {
    size: A4 portrait;
    margin: 15mm 15mm 15mm 15mm;
  }
  
  *, *::before, *::after {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
    color-adjust: exact !important;
  }
  
  html, body {
    width: 100% !important;
    height: auto !important;
    overflow: visible !important;
    font-size: 11pt !important;
    line-height: 1.6 !important;
  }

  /* Page colours follow the chosen print mode instead of being hard-forced to white,
     which previously left dark-mode PDFs with near-black headings on a dark page. */
  .print-light, .print-light body {
    background: #ffffff !important;
    color: #24292e !important;
  }
  .print-dark, .print-dark body {
    background: #1e1e1e !important;
    color: #e6e6e6 !important;
  }
  
  #app, .main-workspace, .preview-pane, .preview-content {
    display: block !important;
    width: 100% !important;
    height: auto !important;
    overflow: visible !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    box-shadow: none !important;
  }
  .print-light #app, .print-light .main-workspace,
  .print-light .preview-pane, .print-light .preview-content {
    background: #ffffff !important;
  }
  .print-dark #app, .print-dark .main-workspace,
  .print-dark .preview-pane, .print-dark .preview-content {
    background: #1e1e1e !important;
    color: #e6e6e6 !important;
  }
  
  /* Hide interactive UI elements */
  .app-header,
  .toolbar-container,
  .editor-pane,
  .split-resizer,
  .app-statusbar,
  .modal-overlay,
  .toast-container,
  .pane-header,
  .luogu-code-actions,
  .luogu-code-copy-btn,
  button.luogu-code-copy-btn,
  .copy-icon,
  .copy-text {
    display: none !important;
    visibility: hidden !important;
    opacity: 0 !important;
  }
  
  /* Prevent awkward page breaks */
  h1, h2, h3, h4, h5, h6 {
    page-break-after: avoid !important;
    break-after: avoid !important;
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
  .print-light h1, .print-light h2, .print-light h3,
  .print-light h4, .print-light h5, .print-light h6 {
    color: #1a1a1a !important;
  }
  .print-dark h1, .print-dark h2, .print-dark h3,
  .print-dark h4, .print-dark h5, .print-dark h6 {
    color: #f0f0f0 !important;
  }
  
  p, blockquote, .luogu-p {
    orphans: 3;
    widows: 3;
  }
  
  pre, code, .luogu-code-block-wrapper, .luogu-callout, .luogu-epigraph, .luogu-table-wrapper, table {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
  
  tr {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
  
  /* Prism ships a DARK theme (Tomorrow Night): #999 comments, #ccc punctuation,
     #7ec699 strings — all chosen to sit on a near-black background. Printing forces
     the code block to a light background, but nothing was re-colouring the tokens,
     so every one of them landed under 3:1 contrast on white (punctuation was 1.51).
     That is the "code colours are wrong in the PDF" report: pale text on pale paper.

     Re-map the whole palette to light-background equivalents, keeping the hue so the
     printed code still reads like the on-screen code. Values are the GitHub light
     syntax palette, all >= 4.5:1 against #f6f8fa. */
  .print-light .luogu-code-block-wrapper .token.comment,
  .print-light .luogu-code-block-wrapper .token.block-comment,
  .print-light .luogu-code-block-wrapper .token.prolog,
  .print-light .luogu-code-block-wrapper .token.doctype,
  .print-light .luogu-code-block-wrapper .token.cdata {
    color: #6a737d !important;
  }
  .print-light .luogu-code-block-wrapper .token.punctuation,
  .print-light .luogu-code-block-wrapper .token.double-colon {
    color: #24292e !important;
  }
  .print-light .luogu-code-block-wrapper .token.tag,
  .print-light .luogu-code-block-wrapper .token.attr-name,
  .print-light .luogu-code-block-wrapper .token.namespace,
  .print-light .luogu-code-block-wrapper .token.deleted {
    color: #b31d28 !important;
  }
  .print-light .luogu-code-block-wrapper .token.function-name,
  .print-light .luogu-code-block-wrapper .token.function {
    color: #6f42c1 !important;
  }
  .print-light .luogu-code-block-wrapper .token.boolean,
  .print-light .luogu-code-block-wrapper .token.number,
  .print-light .luogu-code-block-wrapper .token.constant,
  .print-light .luogu-code-block-wrapper .token.symbol {
    color: #005cc5 !important;
  }
  .print-light .luogu-code-block-wrapper .token.class-name,
  .print-light .luogu-code-block-wrapper .token.property,
  .print-light .luogu-code-block-wrapper .token.macro,
  .print-light .luogu-code-block-wrapper .token.directive-hash {
    color: #a04100 !important;
  }
  .print-light .luogu-code-block-wrapper .token.atrule,
  .print-light .luogu-code-block-wrapper .token.builtin,
  .print-light .luogu-code-block-wrapper .token.keyword,
  .print-light .luogu-code-block-wrapper .token.directive,
  .print-light .luogu-code-block-wrapper .token.selector,
  .print-light .luogu-code-block-wrapper .token.important {
    /* #d73a49 is 4.30:1; nudged darker for AA. */
    color: #b31d28 !important;
  }
  .print-light .luogu-code-block-wrapper .token.string,
  .print-light .luogu-code-block-wrapper .token.attr-value,
  .print-light .luogu-code-block-wrapper .token.char,
  .print-light .luogu-code-block-wrapper .token.regex,
  .print-light .luogu-code-block-wrapper .token.variable {
    color: #032f62 !important;
  }
  .print-light .luogu-code-block-wrapper .token.operator,
  .print-light .luogu-code-block-wrapper .token.entity,
  .print-light .luogu-code-block-wrapper .token.url {
    color: #b31d28 !important;
  }
  .print-light .luogu-code-block-wrapper .token.inserted {
    color: #22863a !important;
  }

  /* Printing in dark mode. The default is print-light (see printDocument): a reader
     usually wants ink-on-paper. But when the user explicitly keeps the dark theme we
     honour it, and then the PAGE itself must be dark as well — otherwise dark code
     blocks and callouts float on white paper, which looks broken and wastes toner.
     Prism's own dark palette is already correct here, so tokens are left alone. */
  /* Tables in dark PDF. The generic .luogu-table rules are themed for the screen,
     so a tuack/three table kept its light-theme rules (#d4e6f1 borders, white cell
     backgrounds) on the dark page and came out nearly invisible. */
  .print-dark .luogu-table,
  .print-dark .luogu-tuack-table,
  .print-dark .luogu-three-table {
    background: transparent !important;
    color: #d4d4d4 !important;
  }

  .print-dark .luogu-table th,
  .print-dark .luogu-table td {
    border-color: #4b5563 !important;
    color: #d4d4d4 !important;
  }

  .print-dark .luogu-table tr:nth-child(even) td {
    background: rgba(255, 255, 255, 0.04) !important;
  }

  .print-dark .luogu-tuack-table th,
  .print-dark .luogu-three-table thead th {
    background: transparent !important;
    color: #f3f4f6 !important;
  }

  /* The rules that define these two styles must stay visible: tuack's row lines and
     column divider, and the three-line table's three horizontal rules. */
  .print-dark .luogu-tuack-table th,
  .print-dark .luogu-tuack-table td {
    border-top-color: #9ca3af !important;
    border-bottom-color: #9ca3af !important;
  }

  .print-dark table.luogu-tuack-table[data-tuack-col] th,
  .print-dark table.luogu-tuack-table[data-tuack-col] td {
    border-left-color: #d4d4d4 !important;
  }

  .print-dark table.luogu-three-table th,
  .print-dark table.luogu-three-table td {
    border-color: #d4d4d4 !important;
  }

  .print-dark .luogu-code-block-wrapper {
    color: #abb2bf !important;
  }

  .print-dark body,
  .print-dark #app,
  .print-dark .main-workspace,
  .print-dark .preview-pane,
  .print-dark .preview-content {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
  }

  /* Code blocks in print: force 100% clean multi-line wrapping */
  .print-light .luogu-code-block-wrapper {
    background: #f6f8fa !important;
    color: #24292e !important;
    border: 1px solid #d1d5da !important;
    border-radius: 6px !important;
    box-shadow: none !important;
    margin: 14px 0 !important;
    page-break-inside: avoid !important;
    break-inside: avoid !important;
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
  }
  
  .print-light .luogu-code-header {
    background: #eaecef !important;
    color: #444d56 !important;
    border-bottom: 1px solid #d1d5da !important;
    padding: 6px 12px !important;
    font-size: 9pt !important;
    display: flex !important;
    justify-content: space-between !important;
  }
  
  .luogu-code-pre,
  .luogu-code-pre code,
  .code-line,
  .code-line-text,
  pre, code {
    white-space: pre-wrap !important;
    word-break: break-all !important;
    overflow-wrap: anywhere !important;
  }

  .luogu-code-pre {
    background: transparent !important;
    color: #24292e !important;
    padding: 8px 0 !important;
    margin: 0 !important;
    font-family: Consolas, "Courier New", monospace !important;
    font-size: 9pt !important;
    line-height: 1.45 !important;
    overflow: visible !important;
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
  }
  
  .luogu-code-pre code {
    display: block !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }

  .code-line {
    display: flex !important;
    flex-direction: row !important;
    align-items: flex-start !important;
    width: 100% !important;
    max-width: 100% !important;
    min-height: 14pt !important;
    padding: 1px 6px !important;
    box-sizing: border-box !important;
  }
  
  .code-line-number {
    display: inline-block !important;
    width: 30px !important;
    min-width: 30px !important;
    max-width: 30px !important;
    flex: 0 0 30px !important;
    padding-right: 6px !important;
    margin-right: 6px !important;
    text-align: right !important;
    user-select: none !important;
    font-size: 8.5pt !important;
    line-height: 1.45 !important;
  }

  /* The gutter must take its colours from the print mode. The screen rules paint it
     #282c34 with a #5c6370 number, and the print block only overrode the text colour
     — so a light PDF got a black gutter stripe running down the side of an otherwise
     white code block. `position: sticky` is a screen-scrolling affordance and is
     equally wrong on paper. */
  .code-line-number {
    position: static !important;
  }
  .print-light .code-line-number {
    background: #f6f8fa !important;
    /* #8c959f is 2.85:1 on this background; darkened to clear WCAG AA while staying
       visibly subordinate to the code itself. */
    color: #6e7781 !important;
    border-right: 1px solid #d0d7de !important;
  }
  .print-dark .code-line-number {
    background: #282c34 !important;
    color: #7f8896 !important;
    border-right: 1px solid #3e4451 !important;
  }
  /* Highlighted rows tint their own gutter cell to match the row. */
  .print-light .code-line-highlighted .code-line-number {
    background: #fff8c5 !important;
    color: #6a5b16 !important;
  }
  .print-dark .code-line-highlighted .code-line-number {
    background: linear-gradient(rgba(229, 192, 123, 0.15), rgba(229, 192, 123, 0.15)), #282c34 !important;
  }
  
  .code-line-text {
    display: block !important;
    flex: 1 1 0% !important;
    min-width: 0 !important;
    width: 100% !important;
    max-width: calc(100% - 36px) !important;
    box-sizing: border-box !important;
    font-size: 9pt !important;
    line-height: 1.45 !important;
  }

  /* Unhighlighted code text. Split by print mode: the flat #24292e used to apply in
     both, so a dark-mode PDF printed near-black text onto a near-black code block. */
  .print-light .code-line-text { color: #24292e !important; }
  .print-dark .code-line-text { color: #abb2bf !important; }
  
  /* A highlighted row gains a 3px left border, so its left padding must drop by
     exactly 3px to keep the code text on the same x as every other row. The base row
     uses 6px, so this must be 3px — it said 5px, which pushed highlighted lines 2px
     right, and the dark mode had no rule at all (a full 3px shift). */
  .print-light .code-line-highlighted,
  .print-dark .code-line-highlighted {
    border-left: 3px solid #d4a72c !important;
    padding-left: 3px !important;
  }
  .print-light .code-line-highlighted {
    background: #fff8c5 !important;
  }
  .print-dark .code-line-highlighted {
    background: linear-gradient(rgba(229, 192, 123, 0.15), rgba(229, 192, 123, 0.15)), #282c34 !important;
  }
  
  /* Callouts in print: always forced fully open */
  .luogu-callout {
    display: block !important;
    box-shadow: none !important;
    page-break-inside: avoid !important;
    break-inside: avoid !important;
    margin: 12px 0 !important;
    border: 1px solid #d0d7de !important;
  }
  
  .luogu-callout > summary {
    pointer-events: none !important;
    list-style: none !important;
    padding: 8px 12px !important;
  }

  .luogu-callout > summary::-webkit-details-marker {
    display: none !important;
  }
  
  .luogu-callout-content {
    display: block !important;
    visibility: visible !important;
    opacity: 1 !important;
    height: auto !important;
    max-height: none !important;
    padding: 10px 14px !important;
    border-top: 1px solid #d0d7de !important;
  }
  
  .luogu-callout-arrow {
    display: none !important;
  }

  /* Bilibili Video in Print / PDF - Clean printable link banner */
  .luogu-bilibili-container {
    display: block !important;
    background: #f6f8fa !important;
    border: 1px solid #d0d7de !important;
    border-radius: 6px !important;
    box-shadow: none !important;
    margin: 12px 0 !important;
    page-break-inside: avoid !important;
  }

  .luogu-bilibili-header {
    background: #f6f8fa !important;
    color: #24292e !important;
    padding: 8px 12px !important;
    display: flex !important;
    justify-content: space-between !important;
    align-items: center !important;
    border: none !important;
  }

  .luogu-bilibili-badge {
    background: #fb7299 !important;
    color: #ffffff !important;
    padding: 2px 6px !important;
    border-radius: 4px !important;
    font-size: 8.5pt !important;
  }

  .luogu-bilibili-link {
    display: inline-flex !important;
    align-items: center !important;
    gap: 4px !important;
    color: #0969da !important;
    font-size: 9pt !important;
    text-decoration: underline !important;
  }

  .luogu-bilibili-player-wrapper {
    display: none !important;
  }

  /* Math display */
  .luogu-math-display {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
}

/* ==========================================================================
   Auto-save failure indicator
   ========================================================================== */
.save-failed {
  color: #dc2626 !important;
  font-weight: 600;
}

/* ==========================================================================
   Responsive / mobile layout
   --------------------------------------------------------------------------
   The stylesheet previously contained no width breakpoints at all, so the
   fixed two-column workspace and the 6px drag handle were unusable on a phone
   — a real scenario for reading problems and touching up solutions on the go.
   On narrow screens the panes stack and the existing view-mode classes
   (.mode-editor-only / .mode-preview-only) become the primary way to switch.
   ========================================================================== */
@media (max-width: 900px) {
  .main-workspace {
    flex-direction: column;
    height: auto;
    min-height: calc(100vh - var(--header-height) - var(--toolbar-height) - var(--statusbar-height));
  }

  /* Inline flex percentages are set by the splitter drag; neutralise them. */
  .editor-pane,
  .preview-pane {
    flex: 1 1 auto !important;
    width: 100% !important;
    min-width: 0 !important;
    height: 50vh;
  }

  /* Dragging a vertical divider makes no sense in a stacked layout. */
  .split-resizer {
    display: none !important;
  }

  /* When a single pane is selected, let it use the full viewport. */
  .mode-editor-only .editor-pane,
  .mode-preview-only .preview-pane {
    height: calc(100vh - var(--header-height) - var(--toolbar-height) - var(--statusbar-height));
  }

  .toolbar-container {
    flex-wrap: wrap;
    height: auto;
    row-gap: 4px;
    padding-top: 6px;
    padding-bottom: 6px;
  }

  .app-header {
    height: auto;
    flex-wrap: wrap;
    row-gap: 4px;
  }
}

@media (max-width: 600px) {
  /* Reclaim vertical space: on a phone the header + toolbar otherwise consumed
     over a third of the viewport before any content was visible. */
  .app-header {
    padding: 4px 8px;
  }

  .toolbar-container {
    padding: 2px 6px;
    row-gap: 2px;
    column-gap: 2px;
  }

  .toolbar-group {
    gap: 2px;
  }

  .editor-pane,
  .preview-pane {
    height: 50vh;
  }

  /* Comfortable touch targets while staying compact. */
  .toolbar-container button,
  .pane-header button {
    min-width: 36px;
    min-height: 36px;
    padding: 4px 6px;
  }

  /* The editor is the primary surface on a phone; keep the app header from
     wrapping into several tall rows. */
  .app-header .header-title-group {
    flex: 1 1 100%;
  }

  /* Secondary chrome costs too much room on a phone. */
  .toolbar-divider {
    display: none;
  }

  .luogu-table-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* Respect users who ask for reduced motion. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* A container name the renderer does not know (e.g. a typo like ":::s"). Shown as
   literal text rather than being coerced into an info box, with a hint that it is
   probably a mistake. */
.luogu-unknown-container {
  font-family: var(--font-mono);
  color: var(--text-muted);
  background: var(--bg-secondary);
  border-left: 3px solid var(--border-color);
  padding: 4px 10px;
  border-radius: 4px;
}

.luogu-unclosed-warning {
  color: #b26a00;
  background: rgba(255, 170, 0, 0.1);
  border-left: 3px solid #ffaa00;
  padding: 6px 10px;
  border-radius: 4px;
  font-size: 0.92em;
}

.luogu-unclosed-warning code {
  background: rgba(0, 0, 0, 0.08);
  padding: 1px 4px;
  border-radius: 3px;
}

/* Typora mode: hide the element that has been swapped out for an editor.
   This must come last in the stylesheet — `.luogu-code-pre code` is also
   `display:block !important`, and between two !important declarations of equal
   specificity the later one wins. */
/* ::cute-table{three} — booktabs 三线表: only three horizontal rules (top, under the
   header, bottom) and no vertical rules at all. Selectors are qualified with the
   table class so they outrank the generic `.luogu-table th/td` borders. */
table.luogu-three-table {
  border-collapse: collapse;
  border: 0 !important;
  background: transparent;
  box-shadow: none;
}

table.luogu-three-table th,
table.luogu-three-table td {
  border: 0 !important;
  background: transparent !important;
  padding: 8px 18px;
  text-align: center;
}

table.luogu-three-table thead th {
  border-top: 2px solid var(--text-primary) !important;
  border-bottom: 1px solid var(--text-primary) !important;
  font-weight: 600;
}

table.luogu-three-table tbody tr:last-child td {
  border-bottom: 2px solid var(--text-primary) !important;
}

/* ::cute-table{tuack=N} — thicker divider on the left edge of column N, marking the
   boundary between two logical halves of the table. */
table.luogu-tuack-table[data-tuack-col="2"] th:nth-child(2),
table.luogu-tuack-table[data-tuack-col="2"] td:nth-child(2),
table.luogu-tuack-table[data-tuack-col="3"] th:nth-child(3),
table.luogu-tuack-table[data-tuack-col="3"] td:nth-child(3),
table.luogu-tuack-table[data-tuack-col="4"] th:nth-child(4),
table.luogu-tuack-table[data-tuack-col="4"] td:nth-child(4),
table.luogu-tuack-table[data-tuack-col="5"] th:nth-child(5),
table.luogu-tuack-table[data-tuack-col="5"] td:nth-child(5),
table.luogu-tuack-table[data-tuack-col="6"] th:nth-child(6),
table.luogu-tuack-table[data-tuack-col="6"] td:nth-child(6),
table.luogu-tuack-table[data-tuack-col="7"] th:nth-child(7),
table.luogu-tuack-table[data-tuack-col="7"] td:nth-child(7),
table.luogu-tuack-table[data-tuack-col="8"] th:nth-child(8),
table.luogu-tuack-table[data-tuack-col="8"] td:nth-child(8) {
  border-left: 2.5px solid var(--text-primary) !important;
}

/* Merged-cell hover: the cell is temporarily un-merged, and the positions it had
   swallowed come back as real cells showing their own source text. Dashed borders
   and a tinted background mark them as a transient preview rather than content. */
.preview-content.typora-mode td.typora-unmerged-origin,
.preview-content.typora-mode th.typora-unmerged-origin {
  outline: 2px solid var(--luogu-blue);
  outline-offset: -2px;
}

.preview-content.typora-mode td.typora-unmerged-cell,
.preview-content.typora-mode th.typora-unmerged-cell {
  border: 1px dashed var(--luogu-blue) !important;
  background: rgba(52, 152, 219, 0.08) !important;
  color: var(--text-secondary);
  font-family: var(--font-mono, monospace);
  text-align: center;
  /* The revealed markers are metadata, not prose: keep them from being selected or
     dragged while the pointer is just passing over the table. */
  user-select: none;
}

/* An editor pinned over the element it edits, leaving the document's own layout
   untouched. A merged table cell cannot host an inline editor without the table
   reflowing around it, so the cell editor floats instead. */
.preview-content.typora-mode .typora-editing/* Cell-local editing: the marker text is replaced by the input inside the same
   <td>, so the un-merged skeleton around it keeps its own markers on screen. */
.preview-content.typora-mode td.typora-host-editing,
.preview-content.typora-mode th.typora-host-editing {
  padding: 0 !important;
  /* Collapse the cell's own text nodes: the editor replaces the marker, so the
     original glyph must not linger above the input. */
  font-size: 0;
  line-height: 0;
}
.preview-content.typora-mode .typora-host-editing .typora-editing {
  display: block;
  font-size: 13px;
}
.preview-content.typora-mode .typora-host-editing .typora-block-input {
  width: 100%;
  /* Ignore the textarea's `cols` intrinsic width so it cannot widen the column. */
  min-inline-size: 0;
  field-sizing: content;
  /* No min-width in em: a wide editor forces the whole column wider and squeezes
     the neighbouring marker cell down to nothing. The cell already reserves the
     space it had before the edit. */
  min-width: 0;
  box-sizing: border-box;
  border: 2px solid var(--luogu-blue, #3498db);
  border-radius: 3px;
  padding: 2px 4px;
  text-align: center;
  background: #fff;
}

.typora-overlay {
  position: absolute;
  z-index: 40;
  margin: 0;
  padding: 0;
}

.preview-content.typora-mode .typora-editing.typora-overlay .typora-block-input {
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  padding: 2px 6px;
  border: 2px solid var(--luogu-blue);
  border-radius: 3px;
  background: var(--bg-primary);
  text-align: center;
  resize: none;
}

.preview-content .typora-hidden,
.preview-content .typora-hidden code,
.preview-content .typora-hidden pre {
  display: none !important;
}

/* Callout type picker (Typora mode). Appended to <body> so it is never clipped by
   the preview pane's overflow. */
.typora-type-menu {
  position: fixed;
  z-index: 9999;
  min-width: 128px;
  padding: 4px;
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}

.typora-type-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--text-primary);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.typora-type-item:hover {
  background: var(--bg-secondary);
}

.typora-type-item.is-current {
  font-weight: 600;
}

.typora-type-item.is-current::after {
  content: "✓";
  margin-left: auto;
  color: var(--luogu-blue);
}

.typora-type-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: none;
}

/* Scroll-sync toggle: dim + strike through when off, so the state is readable at a
   glance rather than only from the tooltip. */
.tool-btn.scroll-sync-btn { position: relative; }
.tool-btn.scroll-sync-btn:not(.active) { opacity: .45; }
.tool-btn.scroll-sync-btn:not(.active)::after {
  content: '';
  position: absolute;
  left: 15%;
  right: 15%;
  top: 50%;
  height: 2px;
  background: currentColor;
  transform: rotate(-45deg);
  border-radius: 2px;
}
