openwriter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ :root{--bg-primary: #fff;--bg-sidebar: #fafafa;--bg-titlebar: #fafafa;--bg-surface: #fff;--bg-hover: #f0f0f0;--border: #f0f0f0;--border-light: #f0f0f0;--ink-dark: #111;--ink-light: #777;--font-body: Inter, -apple-system, BlinkMacSystemFont, sans-serif;--font-sidebar: Inter, -apple-system, sans-serif;--accent: #2563eb;--editor-font: Charter, "Bitstream Charter", "Sitka Text", Cambria, serif;--editor-font-size: 18px;--editor-line-height: 1.75;--editor-letter-spacing: -.003em;--editor-max-width: 680px;--editor-color: #242424;--font-heading: Inter, -apple-system, sans-serif;--h1-size: 32px;--h1-weight: 700;--h1-spacing: -.8px;--h1-line-height: 1.15;--h1-color: #111;--h1-style: normal;--h2-size: 24px;--h2-weight: 700;--h2-spacing: -.5px;--h2-line-height: 1.2;--h2-color: #111;--font-heading-h3: Inter, -apple-system, sans-serif;--h3-size: 18px;--h3-weight: 600;--h3-spacing: -.3px;--h3-line-height: 1.4;--h3-color: #333;--h3-transform: none;--h3-border: none;--h3-pb: 0;--h3-display: block;--strong-color: #111;--blockquote-border: #d0d0d0;--blockquote-opacity: .8;--blockquote-font-size: inherit;--blockquote-border-width: 3px;--shimmer-highlight: rgba(255, 255, 255, .7);--color-pending-insert: #16a34a;--color-pending-insert-bg: rgba(22, 163, 74, .1);--color-pending-insert-border: #16a34a;--color-pending-rewrite: #2563eb;--color-pending-rewrite-bg: rgba(37, 99, 235, .1);--color-pending-rewrite-border: #2563eb;--color-pending-delete: #e74c3c;--color-pending-delete-bg: rgba(231, 76, 60, .1);--color-pending-delete-border: #e74c3c;--color-pending-focus: #2563eb}[data-theme=ink][data-mode=dark]{--bg-primary: #1a1a1a;--bg-sidebar: #1c1c1c;--bg-titlebar: #1f1f1f;--bg-surface: #1f1f1f;--bg-hover: #262626;--border: #2a2a2a;--border-light: #262626;--ink-dark: #e0e0e0;--ink-light: #666;--editor-color: #d4d4d4;--h1-color: #f0f0f0;--h2-color: #f0f0f0;--h3-color: #ccc;--strong-color: #fff;--blockquote-border: #444;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=novel][data-mode=light]{--bg-primary: #faf8f3;--bg-sidebar: #f5f2ea;--bg-titlebar: #f3f0e8;--bg-surface: #faf8f3;--bg-hover: #ece8df;--border: #eae6dc;--border-light: #ece8df;--ink-dark: #4a3f30;--ink-light: #998e7e;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "Source Serif 4", "Iowan Old Style", "Palatino Linotype", Palatino, serif;--editor-font-size: 18px;--editor-line-height: 1.85;--editor-letter-spacing: .003em;--editor-max-width: 640px;--editor-color: #2c2519;--font-heading: "Newsreader", "Iowan Old Style", Georgia, serif;--h1-size: 34px;--h1-weight: 400;--h1-spacing: -.3px;--h1-line-height: 1.2;--h1-color: #2c2519;--h1-style: italic;--h2-size: 26px;--h2-weight: 400;--h2-spacing: -.2px;--h2-line-height: 1.25;--h2-color: #3d3122;--font-heading-h3: "Newsreader", Georgia, serif;--h3-size: 13px;--h3-weight: 600;--h3-spacing: 2px;--h3-color: #5c4b32;--h3-transform: uppercase;--strong-color: #5c4b32;--blockquote-border: #d4c4a0;--color-pending-insert: #6b9e4f;--color-pending-insert-bg: rgba(107, 158, 79, .1);--color-pending-insert-border: #6b9e4f;--color-pending-rewrite: #8b7b4a;--color-pending-rewrite-bg: rgba(139, 123, 74, .1);--color-pending-rewrite-border: #8b7b4a;--color-pending-delete: #c9785d;--color-pending-delete-bg: rgba(201, 120, 93, .1);--color-pending-delete-border: #c9785d;--color-pending-focus: #8b7b4a}[data-theme=novel][data-mode=dark]{--bg-primary: #1c1914;--bg-sidebar: #1e1b15;--bg-titlebar: #211e17;--bg-surface: #211e17;--bg-hover: #29261f;--border: #2e2a21;--border-light: #29261f;--ink-dark: #d4c4a0;--ink-light: #5c5548;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "Source Serif 4", "Iowan Old Style", "Palatino Linotype", Palatino, serif;--editor-font-size: 18px;--editor-line-height: 1.85;--editor-letter-spacing: .003em;--editor-max-width: 640px;--editor-color: #c8bba0;--font-heading: "Newsreader", "Iowan Old Style", Georgia, serif;--h1-size: 34px;--h1-weight: 400;--h1-spacing: -.3px;--h1-line-height: 1.2;--h1-color: #e8d8b8;--h1-style: italic;--h2-size: 26px;--h2-weight: 400;--h2-spacing: -.2px;--h2-line-height: 1.25;--h2-color: #ddd0b5;--font-heading-h3: "Newsreader", Georgia, serif;--h3-size: 13px;--h3-weight: 600;--h3-spacing: 2px;--h3-color: #a09070;--h3-transform: uppercase;--strong-color: #e8d8b4;--blockquote-border: #4a4030;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #7daa68;--color-pending-insert-bg: rgba(125, 170, 104, .1);--color-pending-insert-border: #7daa68;--color-pending-rewrite: #d4a953;--color-pending-rewrite-bg: rgba(212, 169, 83, .1);--color-pending-rewrite-border: #d4a953;--color-pending-delete: #c9785d;--color-pending-delete-bg: rgba(201, 120, 93, .1);--color-pending-delete-border: #c9785d;--color-pending-focus: #d4a953}[data-theme=mono][data-mode=light]{--bg-primary: #fff;--bg-sidebar: #fafafa;--bg-titlebar: #f8f8f8;--bg-surface: #fff;--bg-hover: #f0f0f0;--border: #eee;--border-light: #f0f0f0;--ink-dark: #333;--ink-light: #aaa;--font-sidebar: "IBM Plex Sans", Inter, sans-serif;--editor-font: "IBM Plex Mono", "Fira Code", "Cascadia Code", monospace;--editor-font-size: 14.5px;--editor-line-height: 1.85;--editor-letter-spacing: 0;--editor-max-width: 620px;--editor-color: #333;--font-heading: "IBM Plex Sans", Inter, sans-serif;--h1-size: 28px;--h1-weight: 600;--h1-spacing: -.6px;--h1-line-height: 1.2;--h1-color: #111;--h2-size: 21px;--h2-weight: 600;--h2-spacing: -.4px;--h2-line-height: 1.25;--h2-color: #111;--font-heading-h3: "IBM Plex Sans", Inter, sans-serif;--h3-size: 15px;--h3-weight: 600;--h3-spacing: 0;--h3-color: #555;--strong-color: #111;--blockquote-border: #d0d0d0}[data-theme=mono][data-mode=dark]{--bg-primary: #151515;--bg-sidebar: #171717;--bg-titlebar: #181818;--bg-surface: #181818;--bg-hover: #222;--border: #222;--border-light: #202020;--ink-dark: #ccc;--ink-light: #555;--font-sidebar: "IBM Plex Sans", Inter, sans-serif;--editor-font: "IBM Plex Mono", "Fira Code", "Cascadia Code", monospace;--editor-font-size: 14.5px;--editor-line-height: 1.85;--editor-letter-spacing: 0;--editor-max-width: 620px;--editor-color: #b0b0b0;--font-heading: "IBM Plex Sans", Inter, sans-serif;--h1-size: 28px;--h1-weight: 600;--h1-spacing: -.6px;--h1-line-height: 1.2;--h1-color: #e8e8e8;--h2-size: 21px;--h2-weight: 600;--h2-spacing: -.4px;--h2-line-height: 1.25;--h2-color: #e8e8e8;--font-heading-h3: "IBM Plex Sans", Inter, sans-serif;--h3-size: 15px;--h3-weight: 600;--h3-spacing: 0;--h3-color: #888;--strong-color: #e0e0e0;--blockquote-border: #333;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=editorial][data-mode=light]{--bg-titlebar: #f9f9f9;--bg-sidebar: #f9f9f9;--bg-hover: #eee;--border: #eee;--border-light: #eee;--ink-dark: #111;--ink-light: #888;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "Crimson Pro", "Libre Baskerville", Georgia, serif;--editor-font-size: 20px;--editor-line-height: 1.7;--editor-letter-spacing: .005em;--editor-max-width: 660px;--editor-color: #1a1a1a;--font-heading: "Playfair Display", Georgia, serif;--h1-size: 38px;--h1-weight: 700;--h1-spacing: -.8px;--h1-line-height: 1.1;--h1-color: #0a0a0a;--h2-size: 28px;--h2-weight: 700;--h2-spacing: -.5px;--h2-line-height: 1.2;--h2-color: #111;--font-heading-h3: "DM Sans", Inter, sans-serif;--h3-size: 12px;--h3-weight: 700;--h3-spacing: 2.5px;--h3-color: #999;--h3-transform: uppercase;--h3-border: 2px solid #dc2626;--h3-pb: 8px;--h3-display: inline-block;--strong-color: #111;--blockquote-border: #dc2626;--blockquote-opacity: 1;--blockquote-font-size: 22px;--blockquote-border-width: 3px}[data-theme=editorial][data-mode=dark]{--bg-primary: #161616;--bg-sidebar: #181818;--bg-titlebar: #1b1b1b;--bg-surface: #1b1b1b;--bg-hover: #232323;--border: #262626;--border-light: #232323;--ink-dark: #e0e0e0;--ink-light: #666;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "Crimson Pro", "Libre Baskerville", Georgia, serif;--editor-font-size: 20px;--editor-line-height: 1.7;--editor-letter-spacing: .005em;--editor-max-width: 660px;--editor-color: #ccc;--font-heading: "Playfair Display", Georgia, serif;--h1-size: 38px;--h1-weight: 700;--h1-spacing: -.8px;--h1-line-height: 1.1;--h1-color: #f0f0f0;--h2-size: 28px;--h2-weight: 700;--h2-spacing: -.5px;--h2-line-height: 1.2;--h2-color: #eee;--font-heading-h3: "DM Sans", Inter, sans-serif;--h3-size: 12px;--h3-weight: 700;--h3-spacing: 2.5px;--h3-color: #777;--h3-transform: uppercase;--h3-border: 2px solid #ef4444;--h3-pb: 8px;--h3-display: inline-block;--strong-color: #fff;--blockquote-border: #ef4444;--blockquote-opacity: 1;--blockquote-font-size: 22px;--blockquote-border-width: 3px;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=studio][data-mode=light]{--bg-titlebar: #f7f7f8;--bg-sidebar: #f7f7f8;--bg-hover: #ececee;--border: #ececee;--border-light: #ececee;--ink-dark: #111;--ink-light: #888;--editor-font: Inter, -apple-system, BlinkMacSystemFont, sans-serif;--editor-font-size: 16px;--editor-line-height: 1.7;--editor-letter-spacing: -.011em;--editor-max-width: 660px;--editor-color: #2a2a2a;--h1-size: 30px;--h1-spacing: -.8px;--h2-size: 22px;--h2-spacing: -.5px;--h3-size: 16px;--h3-spacing: -.2px;--h3-color: #555;--strong-color: #111}[data-theme=studio][data-mode=dark]{--bg-primary: #18181b;--bg-sidebar: #1a1a1d;--bg-titlebar: #1e1e21;--bg-surface: #1e1e21;--bg-hover: #27272a;--border: #27272a;--border-light: #27272a;--ink-dark: #e4e4e7;--ink-light: #666;--editor-font: Inter, -apple-system, BlinkMacSystemFont, sans-serif;--editor-font-size: 16px;--editor-line-height: 1.7;--editor-letter-spacing: -.011em;--editor-max-width: 660px;--editor-color: #d4d4d8;--h1-size: 30px;--h1-spacing: -.8px;--h1-color: #f4f4f5;--h2-size: 22px;--h2-spacing: -.5px;--h2-color: #f4f4f5;--h3-size: 16px;--h3-spacing: -.2px;--h3-color: #a1a1aa;--strong-color: #fff;--blockquote-border: #3f3f46;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=calm][data-mode=light]{--bg-primary: #faf9f7;--bg-sidebar: #f5f3f0;--bg-titlebar: #f4f2ef;--bg-surface: #faf9f7;--bg-hover: #eae7e2;--border: #eae7e2;--border-light: #eae7e2;--ink-dark: #292524;--ink-light: #a8a29e;--editor-font: Inter, -apple-system, BlinkMacSystemFont, sans-serif;--editor-font-size: 16px;--editor-line-height: 1.75;--editor-letter-spacing: -.011em;--editor-max-width: 680px;--editor-color: #44403c;--h1-size: 30px;--h1-spacing: -.8px;--h1-color: #1c1917;--h2-size: 22px;--h2-weight: 600;--h2-spacing: -.5px;--h2-line-height: 1.25;--h2-color: #1c1917;--h3-size: 15px;--h3-spacing: -.2px;--h3-color: #78716c;--strong-color: #1c1917;--blockquote-border: #d6d3d1;--color-pending-insert-bg: rgba(22, 163, 74, .08);--color-pending-rewrite-bg: rgba(37, 99, 235, .08);--color-pending-delete-bg: rgba(231, 76, 60, .08)}[data-theme=calm][data-mode=dark]{--bg-primary: #1c1b19;--bg-sidebar: #1e1d1b;--bg-titlebar: #211f1d;--bg-surface: #211f1d;--bg-hover: #2c2a27;--border: #2c2a27;--border-light: #2c2a27;--ink-dark: #e7e5e4;--ink-light: #78716c;--editor-font: Inter, -apple-system, BlinkMacSystemFont, sans-serif;--editor-font-size: 16px;--editor-line-height: 1.75;--editor-letter-spacing: -.011em;--editor-max-width: 680px;--editor-color: #d6d3d1;--h1-size: 30px;--h1-spacing: -.8px;--h1-color: #fafaf9;--h2-size: 22px;--h2-weight: 600;--h2-spacing: -.5px;--h2-line-height: 1.25;--h2-color: #fafaf9;--h3-size: 15px;--h3-spacing: -.2px;--h3-color: #a8a29e;--strong-color: #fafaf9;--blockquote-border: #44403c;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=prose][data-mode=light]{--bg-titlebar: #f9f9f9;--bg-sidebar: #f9f9f9;--bg-hover: #efefef;--border: #efefef;--border-light: #efefef;--ink-dark: #222;--ink-light: #999;--editor-font: "Libre Baskerville", "Hoefler Text", Garamond, serif;--editor-font-size: 17px;--editor-line-height: 1.8;--editor-letter-spacing: .01em;--editor-max-width: 660px;--editor-color: #222;--h1-size: 32px;--h1-spacing: -.8px;--h2-size: 24px;--h2-spacing: -.5px;--h3-size: 17px;--h3-spacing: -.2px;--h3-color: #555;--blockquote-border: #ddd;--blockquote-font-size: 18px}[data-theme=prose][data-mode=dark]{--bg-primary: #181818;--bg-sidebar: #1a1a1a;--bg-titlebar: #1d1d1d;--bg-surface: #1d1d1d;--bg-hover: #252525;--border: #282828;--border-light: #252525;--ink-dark: #e0e0e0;--ink-light: #666;--editor-font: "Libre Baskerville", "Hoefler Text", Garamond, serif;--editor-font-size: 17px;--editor-line-height: 1.8;--editor-letter-spacing: .01em;--editor-max-width: 660px;--editor-color: #ccc;--h1-color: #f0f0f0;--h2-color: #f0f0f0;--h3-size: 17px;--h3-spacing: -.2px;--h3-color: #999;--strong-color: #f0f0f0;--blockquote-border: #444;--blockquote-font-size: 18px;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=craft][data-mode=light]{--bg-sidebar: #f7f7f7;--bg-titlebar: #f5f5f5;--bg-hover: #ebebeb;--border: #e8e8e8;--border-light: #ebebeb;--ink-dark: #111;--ink-light: #999;--font-sidebar: "Space Grotesk", Inter, sans-serif;--editor-font: "Space Grotesk", Inter, -apple-system, sans-serif;--editor-font-size: 16.5px;--editor-line-height: 1.75;--editor-letter-spacing: -.01em;--editor-max-width: 660px;--editor-color: #1a1a1a;--font-heading: "Space Grotesk", Inter, sans-serif;--h1-size: 32px;--h1-spacing: -1px;--h1-line-height: 1.1;--h1-color: #0a0a0a;--h2-size: 24px;--h2-weight: 600;--h2-spacing: -.5px;--h2-color: #111;--font-heading-h3: "Space Mono", "IBM Plex Mono", monospace;--h3-size: 13px;--h3-weight: 400;--h3-spacing: 2px;--h3-color: #8b5cf6;--h3-transform: uppercase;--strong-color: #0a0a0a;--blockquote-border: #8b5cf6;--blockquote-opacity: 1;--blockquote-border-width: 2px;--color-pending-insert: #10b981;--color-pending-insert-bg: rgba(16, 185, 129, .1);--color-pending-insert-border: #10b981;--color-pending-rewrite: #8b5cf6;--color-pending-rewrite-bg: rgba(139, 92, 246, .1);--color-pending-rewrite-border: #8b5cf6;--color-pending-delete: #f43f5e;--color-pending-delete-bg: rgba(244, 63, 94, .1);--color-pending-delete-border: #f43f5e;--color-pending-focus: #8b5cf6}[data-theme=craft][data-mode=dark]{--bg-primary: #121218;--bg-sidebar: #141420;--bg-titlebar: #17171e;--bg-surface: #17171e;--bg-hover: #1e1e2c;--border: #222230;--border-light: #1e1e2c;--ink-dark: #e0e0f0;--ink-light: #666;--font-sidebar: "Space Grotesk", Inter, sans-serif;--editor-font: "Space Grotesk", Inter, -apple-system, sans-serif;--editor-font-size: 16.5px;--editor-line-height: 1.75;--editor-letter-spacing: -.01em;--editor-max-width: 660px;--editor-color: #c8c8d8;--font-heading: "Space Grotesk", Inter, sans-serif;--h1-size: 32px;--h1-spacing: -1px;--h1-line-height: 1.1;--h1-color: #f0f0f8;--h2-size: 24px;--h2-weight: 600;--h2-spacing: -.5px;--h2-color: #e8e8f0;--font-heading-h3: "Space Mono", "IBM Plex Mono", monospace;--h3-size: 13px;--h3-weight: 400;--h3-spacing: 2px;--h3-color: #a78bfa;--h3-transform: uppercase;--strong-color: #f0f0f8;--blockquote-border: #a78bfa;--blockquote-opacity: 1;--blockquote-border-width: 2px;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #34d399;--color-pending-insert-bg: rgba(52, 211, 153, .1);--color-pending-insert-border: #34d399;--color-pending-rewrite: #a78bfa;--color-pending-rewrite-bg: rgba(167, 139, 250, .1);--color-pending-rewrite-border: #a78bfa;--color-pending-delete: #fb7185;--color-pending-delete-bg: rgba(251, 113, 133, .1);--color-pending-delete-border: #fb7185;--color-pending-focus: #a78bfa}[data-theme=literata][data-mode=light]{--bg-primary: #fcfcfa;--bg-sidebar: #f7f6f3;--bg-titlebar: #f5f5f2;--bg-surface: #fcfcfa;--bg-hover: #eceae6;--border: #eceae6;--border-light: #eceae6;--ink-dark: #222;--ink-light: #999;--editor-font: "Literata", Georgia, "Times New Roman", serif;--editor-font-size: 18px;--editor-line-height: 1.8;--editor-letter-spacing: .005em;--editor-max-width: 660px;--editor-color: #2a2a2a;--h1-size: 30px;--h1-spacing: -.8px;--h2-size: 22px;--h2-spacing: -.5px;--h3-size: 16px;--h3-spacing: -.2px;--h3-color: #666;--blockquote-border: #d0d0cc}[data-theme=literata][data-mode=dark]{--bg-primary: #19191a;--bg-sidebar: #1b1b1c;--bg-titlebar: #1e1e1f;--bg-surface: #1e1e1f;--bg-hover: #272728;--border: #2a2a2b;--border-light: #272728;--ink-dark: #e0e0de;--ink-light: #666;--editor-font: "Literata", Georgia, "Times New Roman", serif;--editor-font-size: 18px;--editor-line-height: 1.8;--editor-letter-spacing: .005em;--editor-max-width: 660px;--editor-color: #c8c8c4;--h1-size: 30px;--h1-spacing: -.8px;--h1-color: #f0f0ee;--h2-size: 22px;--h2-spacing: -.5px;--h2-color: #f0f0ee;--h3-size: 16px;--h3-spacing: -.2px;--h3-color: #999;--strong-color: #f0f0ee;--blockquote-border: #444;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-theme=swiss][data-mode=light]{--bg-sidebar: #f8f8f8;--bg-titlebar: #f6f6f6;--bg-hover: #ebebeb;--border: #e8e8e8;--border-light: #ebebeb;--ink-dark: #111;--ink-light: #999;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "DM Sans", Inter, -apple-system, sans-serif;--editor-font-size: 16.5px;--editor-line-height: 1.7;--editor-letter-spacing: -.01em;--editor-max-width: 680px;--editor-color: #1a1a1a;--font-heading: "DM Serif Display", Georgia, serif;--h1-size: 36px;--h1-weight: 400;--h1-spacing: -.5px;--h1-line-height: 1.1;--h1-color: #0a0a0a;--h2-size: 26px;--h2-weight: 400;--h2-spacing: -.3px;--h2-color: #111;--font-heading-h3: "DM Sans", Inter, sans-serif;--h3-size: 14px;--h3-weight: 600;--h3-spacing: .5px;--h3-color: #666;--h3-transform: uppercase;--strong-color: #0a0a0a;--blockquote-border: #ddd}[data-theme=swiss][data-mode=dark]{--bg-primary: #151515;--bg-sidebar: #171717;--bg-titlebar: #1a1a1a;--bg-surface: #1a1a1a;--bg-hover: #222;--border: #252525;--border-light: #222;--ink-dark: #e0e0e0;--ink-light: #666;--font-sidebar: "DM Sans", Inter, sans-serif;--editor-font: "DM Sans", Inter, -apple-system, sans-serif;--editor-font-size: 16.5px;--editor-line-height: 1.7;--editor-letter-spacing: -.01em;--editor-max-width: 680px;--editor-color: #ccc;--font-heading: "DM Serif Display", Georgia, serif;--h1-size: 36px;--h1-weight: 400;--h1-spacing: -.5px;--h1-line-height: 1.1;--h1-color: #f0f0f0;--h2-size: 26px;--h2-weight: 400;--h2-spacing: -.3px;--h2-color: #eee;--font-heading-h3: "DM Sans", Inter, sans-serif;--h3-size: 14px;--h3-weight: 600;--h3-spacing: .5px;--h3-color: #888;--h3-transform: uppercase;--strong-color: #f0f0f0;--blockquote-border: #3a3a3a;--shimmer-highlight: rgba(255, 255, 255, .08);--color-pending-insert: #22c55e;--color-pending-insert-bg: rgba(34, 197, 94, .1);--color-pending-insert-border: #22c55e;--color-pending-rewrite: #60a5fa;--color-pending-rewrite-bg: rgba(96, 165, 250, .1);--color-pending-rewrite-border: #60a5fa;--color-pending-delete: #f87171;--color-pending-delete-bg: rgba(248, 113, 113, .1);--color-pending-delete-border: #f87171;--color-pending-focus: #60a5fa}[data-typography=butterick][data-typography=butterick]{--editor-line-height: 1.4;--h1-size: calc(var(--editor-font-size) * 1.28);--h2-size: calc(var(--editor-font-size) * 1.11);--editor-max-width: 65ch;--blockquote-font-size: .9em}[data-typography=butterick] .tiptap{font-kerning:normal;font-feature-settings:"kern" 1,"liga" 1}[data-typography=butterick] .tiptap h1{margin-top:2em;margin-bottom:.4em}[data-typography=butterick] .tiptap h2{margin-top:1.6em;margin-bottom:.35em}[data-typography=butterick] .tiptap h3{margin-top:1.2em;margin-bottom:.25em}[data-typography=butterick] .tiptap h1:first-child{margin-top:0}[data-typography=butterick] .tiptap p{margin-bottom:.75em}[data-typography=butterick] .tiptap blockquote{margin-left:2em;padding-left:1em;line-height:1.3}[data-typography=butterick] .tiptap ul{list-style-type:circle}[data-typography=web][data-typography=web]{--editor-line-height: 1.75;--h1-size: calc(var(--editor-font-size) * 2.25);--h2-size: calc(var(--editor-font-size) * 1.5);--editor-max-width: 65ch}[data-typography=web] .tiptap{font-kerning:normal}[data-typography=web] .tiptap h1{margin-top:0;margin-bottom:.89em}[data-typography=web] .tiptap h2{margin-top:2em;margin-bottom:1em}[data-typography=web] .tiptap h3{margin-top:1.6em;margin-bottom:.6em}[data-typography=web] .tiptap p{margin-bottom:1.25em}[data-typography=blog][data-typography=blog]{--editor-line-height: 1.6;--h1-size: calc(var(--editor-font-size) * 2);--h2-size: calc(var(--editor-font-size) * 1.625);--editor-max-width: 728px}[data-typography=blog] .tiptap{font-kerning:normal}[data-typography=blog] .tiptap h1,[data-typography=blog] .tiptap h2,[data-typography=blog] .tiptap h3{margin-top:1em;margin-bottom:.625em}[data-typography=blog] .tiptap h1:first-child{margin-top:0}[data-typography=blog] .tiptap p{margin-bottom:1.05em}[data-sidebar-style=frost] .sidebar{background:#ffffffa6;backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);border-right-color:#ffffff4d}[data-sidebar-style=frost][data-mode=dark] .sidebar{background:#1e1e23b3;border-right-color:#ffffff14}[data-sidebar-style=frost] .sidebar-section-header{background:transparent}[data-sidebar-style=frost] .sidebar-item:hover,[data-sidebar-style=frost] .tl-item:hover,[data-sidebar-style=frost] .board-card:hover{background:#fff6}[data-sidebar-style=frost][data-mode=dark] .sidebar-item:hover,[data-sidebar-style=frost][data-mode=dark] .tl-item:hover,[data-sidebar-style=frost][data-mode=dark] .board-card:hover{background:#ffffff0f}[data-sidebar-style=frost] .sidebar-item.active,[data-sidebar-style=frost] .tl-item.active{background:#ffffff80}[data-sidebar-style=frost][data-mode=dark] .sidebar-item.active,[data-sidebar-style=frost][data-mode=dark] .tl-item.active{background:#ffffff14}[data-sidebar-style=minimal] .sidebar{background:var(--bg-primary);border-right:none;box-shadow:1px 0 0 var(--border-light, var(--border))}[data-sidebar-style=minimal] .sidebar-section-header{border-left:none;padding-left:14px}[data-sidebar-style=minimal] .sidebar-item{border-radius:0;margin:0}[data-sidebar-style=minimal] .sidebar-item:hover,[data-sidebar-style=minimal] .tl-item:hover{background:transparent}[data-sidebar-style=minimal] .sidebar-item:hover .sidebar-item-title-text,[data-sidebar-style=minimal] .tl-item:hover .tl-item-title{text-decoration:underline}[data-sidebar-style=minimal] .sidebar-item.active,[data-sidebar-style=minimal] .tl-item.active{background:transparent;border-left:2px solid var(--accent, #5b7a9d);padding-left:8px}[data-sidebar-style=minimal] .sidebar-container{border-left-width:1px}[data-sidebar-style=minimal] .sidebar-new-workspace button{border-style:solid;border-width:1px}[data-sidebar-style=terminal] .sidebar{background:#0d1117;border-right:1px solid #21262d;color:#c9d1d9;font-family:IBM Plex Mono,Courier New,monospace}[data-sidebar-style=terminal] .sidebar-section-header{border-left-color:#3fb950}[data-sidebar-style=terminal] .sidebar-label,[data-sidebar-style=terminal] .tl-title{color:#3fb950;font-family:inherit}[data-sidebar-style=terminal] .sidebar-item-title-text,[data-sidebar-style=terminal] .tl-item-title,[data-sidebar-style=terminal] .board-card-title,[data-sidebar-style=terminal] .shelf-detail-title{color:#c9d1d9;font-family:inherit}[data-sidebar-style=terminal] .sidebar-item-meta,[data-sidebar-style=terminal] .tl-item-meta,[data-sidebar-style=terminal] .board-card-meta,[data-sidebar-style=terminal] .shelf-detail-meta{color:#8b949e;font-family:inherit}[data-sidebar-style=terminal] .sidebar-item:hover,[data-sidebar-style=terminal] .tl-item:hover,[data-sidebar-style=terminal] .board-card:hover{background:#161b22}[data-sidebar-style=terminal] .sidebar-item.active,[data-sidebar-style=terminal] .tl-item.active{background:#161b22;border-left:2px solid #3fb950}[data-sidebar-style=terminal] .board-card.active{border-color:#3fb950}[data-sidebar-style=terminal] .board-lane{background:#161b22}[data-sidebar-style=terminal] .board-card{background:#0d1117;border-color:#21262d}[data-sidebar-style=terminal] .tl-dot{border-color:#3fb950;background:#0d1117}[data-sidebar-style=terminal] .tl-item.active .tl-dot{background:#3fb950}[data-sidebar-style=terminal] .tl-group:before{background:#21262d}[data-sidebar-style=terminal] .tl-date{color:#3fb950}[data-sidebar-style=terminal] .sidebar-workspace-label{color:#58a6ff}[data-sidebar-style=terminal] .sidebar-container-name{color:#d2a8ff}[data-sidebar-style=terminal] .sidebar-new-workspace button,[data-sidebar-style=terminal] .shelf-add{border-color:#21262d;color:#8b949e}[data-sidebar-style=terminal] .sidebar-new-workspace button:hover,[data-sidebar-style=terminal] .shelf-add:hover{border-color:#3fb950;color:#3fb950}[data-sidebar-style=terminal] .sidebar-tag{background:#161b22;border-color:#21262d;color:#8b949e}[data-sidebar-style=terminal] .shelf-spines{background:#0d1117;border-right-color:#21262d}[data-sidebar-style=terminal] .shelf-detail-open{border-color:#21262d;color:#c9d1d9;background:#161b22}[data-sidebar-style=terminal] .shelf-detail-open:hover{border-color:#3fb950;color:#3fb950}.floating-toolbar{display:flex;align-items:center;gap:2px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 12px #0000001f;padding:4px}.floating-toolbar__btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;cursor:pointer;color:var(--ink-dark);border-radius:6px;padding:0;transition:all .15s ease}.floating-toolbar__btn:hover:not(:disabled){background:var(--bg-hover)}.floating-toolbar__btn.active{background:#2563eb1a;color:var(--accent)}.floating-toolbar__btn.disabled,.floating-toolbar__btn:disabled{opacity:.3;cursor:default}.floating-toolbar__divider{width:1px;height:20px;background:var(--border);margin:0 2px;flex-shrink:0}.format-toolbar{display:flex;align-items:center;justify-content:center;gap:2px;padding:4px 16px;background:var(--bg-titlebar);border-bottom:1px solid var(--border);height:36px;flex-shrink:0;overflow-x:auto;scrollbar-width:none}.format-toolbar::-webkit-scrollbar{display:none}.format-toolbar__group{display:flex;align-items:center;gap:2px}.format-toolbar__btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:none;cursor:pointer;color:var(--ink-light);border-radius:5px;padding:0;transition:all .15s ease;flex-shrink:0}.format-toolbar__btn:hover:not(:disabled){background:var(--bg-hover);color:var(--ink-dark)}.format-toolbar__btn.active{background:#2563eb1a;color:var(--accent)}.format-toolbar__btn:disabled{opacity:.3;cursor:default}.format-toolbar__divider{width:1px;height:20px;background:var(--border);margin:0 4px;flex-shrink:0}.format-toolbar__file-input{display:none}.appearance-wrapper{position:relative;display:flex;align-items:center}.appearance-dropdown{position:absolute;top:calc(100% + 6px);right:0;width:300px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0000001f;z-index:100;overflow:hidden}.appearance-section{padding:10px 14px;border-bottom:1px solid var(--border)}.appearance-section:last-child{border-bottom:none}.appearance-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.appearance-section-title{font-size:11px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.5px}.appearance-mode-btn{display:flex;align-items:center;gap:4px;padding:3px 7px;border:1px solid var(--border);border-radius:5px;background:var(--bg-hover);cursor:pointer;color:var(--ink-light);font-size:11px;font-family:var(--font-body);transition:all .15s ease}.appearance-mode-btn:hover{background:var(--border);color:var(--ink-dark)}.appearance-theme-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:2px}.appearance-swatch{display:flex;flex-direction:column;align-items:center;gap:3px;padding:5px 2px;border:none;background:none;cursor:pointer;border-radius:6px;transition:background .1s ease}.appearance-swatch:hover{background:var(--bg-hover)}.appearance-swatch-color{width:26px;height:26px;border-radius:50%;border:2px solid var(--border);transition:border-color .15s ease}.appearance-swatch.active .appearance-swatch-color{border-color:var(--accent);box-shadow:0 0 0 2px #2563eb40}.appearance-swatch-label{font-size:9px;color:var(--ink-light);font-family:var(--font-body);white-space:nowrap}.appearance-swatch.active .appearance-swatch-label{color:var(--ink-dark);font-weight:600}.appearance-mode-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4px}.appearance-mode-option{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 4px;border:1px solid var(--border);border-radius:6px;background:none;cursor:pointer;color:var(--ink-light);font-size:10px;font-family:var(--font-body);transition:all .15s ease}.appearance-mode-option:hover{background:var(--bg-hover);color:var(--ink-dark)}.appearance-mode-option.active{border-color:var(--accent);background:#2563eb0f;color:var(--ink-dark);font-weight:600}.appearance-typography-grid,.appearance-style-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4px}.appearance-style-option{padding:6px 4px;border:1px solid var(--border);border-radius:6px;background:none;cursor:pointer;color:var(--ink-light);font-size:10px;font-family:var(--font-body);text-align:center;transition:all .15s ease}.appearance-style-option:hover{background:var(--bg-hover);color:var(--ink-dark)}.appearance-style-option.active{border-color:var(--accent);background:#2563eb0f;color:var(--ink-dark);font-weight:600}.version-wrapper{position:relative;display:flex;align-items:center}.version-dropdown{position:absolute;top:calc(100% + 6px);right:0;width:280px;max-height:400px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0000001f;z-index:100;overflow:hidden;display:flex;flex-direction:column}.version-dropdown__header{padding:10px 14px;font-size:11px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border);flex-shrink:0}.version-dropdown__list{flex:1;overflow-y:auto;max-height:300px}.version-dropdown__empty{padding:24px 14px;text-align:center;color:var(--ink-light);font-size:12px}.version-dropdown__item{display:flex;flex-direction:column;padding:8px 14px;cursor:pointer;border-left:3px solid transparent;transition:all .12s ease}.version-dropdown__item:hover{background:var(--bg-hover)}.version-dropdown__item--selected{background:#2563eb0f;border-left-color:var(--accent)}.version-dropdown__item-time{font-size:12px;font-weight:500;color:var(--ink-dark)}.version-dropdown__item-meta{font-size:10px;color:var(--ink-light);margin-top:1px}.version-dropdown__footer{display:flex;gap:6px;padding:10px 14px;border-top:1px solid var(--border);flex-shrink:0}.version-dropdown__footer button{flex:1;padding:6px 10px;border-radius:6px;font-size:12px;font-weight:500;cursor:pointer;font-family:var(--font-body);transition:all .15s ease}.version-dropdown__footer button:disabled{opacity:.5;cursor:default}.version-dropdown__review-btn{background:var(--bg-surface);color:var(--accent);border:1px solid var(--accent)}.version-dropdown__review-btn:hover:not(:disabled){background:#2563eb0f}.version-dropdown__restore-btn{background:var(--accent);color:#fff;border:1px solid var(--accent)}.version-dropdown__restore-btn:hover:not(:disabled){background:#1d4ed8}.export-wrapper{position:relative;display:flex;align-items:center}.export-dropdown{position:absolute;top:calc(100% + 6px);right:0;width:260px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0000001f;z-index:100;overflow:hidden;display:flex;flex-direction:column}.export-dropdown__header{padding:10px 14px;font-size:11px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border);flex-shrink:0}.export-dropdown__list{flex:1;overflow-y:auto}.export-dropdown__item{display:flex;align-items:flex-start;gap:10px;padding:10px 14px;cursor:pointer;transition:background .12s ease}.export-dropdown__item:hover{background:var(--bg-hover)}.export-dropdown__item-icon{flex-shrink:0;color:var(--ink-light);margin-top:1px}.export-dropdown__item-text{display:flex;flex-direction:column;min-width:0}.export-dropdown__item-label{font-size:13px;font-weight:500;color:var(--ink-dark)}.export-dropdown__item-desc{font-size:11px;color:var(--ink-light);margin-top:1px}.tl-scroll{padding:0}.tl-header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--border)}.tl-title{font-size:12px;font-weight:600;color:var(--ink-dark);text-transform:uppercase;letter-spacing:.5px}.tl-group{position:relative;padding-left:28px}.tl-group:before{content:"";position:absolute;left:17px;top:28px;bottom:0;width:1.5px;background:var(--border)}.tl-group:last-child:before{display:none}.tl-date{padding:12px 10px 4px 0;font-size:11px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.3px;position:relative}.tl-item{display:flex;align-items:flex-start;gap:8px;padding:6px 10px 6px 0;cursor:pointer;position:relative;transition:background .1s ease;border-radius:0 6px 6px 0}.tl-item:hover{background:var(--bg-hover)}.tl-item.active{background:#2563eb0f}.tl-dot{width:8px;height:8px;min-width:8px;border-radius:50%;border:2px solid var(--border);background:var(--bg-primary);margin-top:5px;margin-left:-15px;position:relative;z-index:1}.tl-item.active .tl-dot{border-color:var(--accent, #5b7a9d);background:var(--accent, #5b7a9d)}.tl-content{flex:1;min-width:0}.tl-item-title{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;color:var(--ink-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tl-item-context{font-size:10px;color:var(--ink-light);font-style:italic;margin-top:1px}.tl-item-meta{font-size:11px;color:var(--ink-light);margin-top:2px}.tl-badge{display:inline-block;max-width:100%;padding:1px 6px;border-radius:3px;background:var(--bg-hover);border:1px solid var(--border);font-size:9px;font-weight:500;color:var(--ink-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}.tl-item .sidebar-delete-btn{position:relative;top:auto;right:auto;opacity:0;flex-shrink:0;margin-top:2px}.tl-item:hover .sidebar-delete-btn{opacity:.5}.tl-item .sidebar-delete-btn:hover{opacity:1}.tl-item .sidebar-confirm-delete{position:relative;top:auto;right:auto}.sidebar.sidebar-board-mode{width:100%!important;min-width:100%!important;max-width:100%!important;height:auto;max-height:200px;min-height:0;border-right:none;border-bottom:1px solid var(--border);flex-direction:row;overflow:visible!important}.sidebar.sidebar-board-mode:not(.open){max-height:0;border-bottom:none}.board-scroll{display:flex;flex-direction:row;align-items:center;gap:4px;overflow-x:auto;overflow-y:visible;padding:6px 10px;height:40px;flex:1;min-width:0}.board-back{display:flex;align-items:center;gap:3px;padding:4px 10px;border:1px solid var(--border);border-radius:14px;background:none;cursor:pointer;color:var(--ink-light);font-size:11px;font-family:var(--font-body);white-space:nowrap;flex-shrink:0;transition:all .15s}.board-back:hover{color:var(--ink-dark);border-color:var(--ink-light)}.board-back--static{cursor:default;color:var(--ink-muted, var(--ink-light));opacity:.6}.board-back--static:hover{color:var(--ink-muted, var(--ink-light));border-color:var(--border)}.board-chip{display:flex;align-items:center;gap:5px;padding:4px 12px;border:1px solid var(--border);border-radius:14px;background:var(--bg-surface);cursor:pointer;color:var(--ink-dark);font-size:11px;font-weight:500;font-family:var(--font-body);white-space:nowrap;transition:all .15s}.board-chip:hover{background:var(--bg-hover);border-color:var(--ink-light)}.board-chip.open{background:var(--bg-hover);border-color:var(--ink-dark)}.board-chip-count{font-size:10px;color:var(--ink-light);font-weight:400}.board-chip-arrow{font-size:14px;line-height:1;color:var(--ink-light);margin-left:-2px}.board-chip-docs{border-style:dashed}.board-chip-add{border-style:dashed;color:var(--ink-light);font-size:14px;padding:4px 10px}.board-chip-add:hover{color:var(--ink-dark)}.board-dropdown{min-width:220px;max-width:300px;max-height:280px;overflow-y:auto;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px #0000001f;z-index:100;padding:4px}.board-dropdown-item{padding:6px 8px;border-radius:5px;cursor:pointer;transition:background .1s}.board-dropdown-item:hover{background:var(--bg-hover)}.board-dropdown-item.active{background:var(--bg-hover);border-left:2px solid var(--ink-dark)}.board-dropdown-title{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:500;color:var(--ink-dark)}.board-dropdown-meta{display:block;font-size:10px;color:var(--ink-light);margin-top:1px}.board-pending-dot{width:6px;height:6px;border-radius:50%;background:#22c55e;flex-shrink:0}.board-dropdown-empty{padding:12px 8px;text-align:center;font-size:11px;color:var(--ink-light)}.shelf-wrapper{display:flex;flex-direction:row;height:100%;overflow:hidden}.shelf-spines{width:72px;min-width:72px;display:flex;flex-direction:column;gap:2px;padding:8px 4px;overflow-y:auto;background:var(--bg-sidebar);border-right:1px solid var(--border)}.shelf-back{display:flex;align-items:center;gap:2px;width:100%;padding:6px 4px;border:none;border-bottom:1px solid var(--border);background:none;cursor:pointer;color:var(--ink-light);font-size:10px;font-family:var(--font-body);margin-bottom:4px;flex-shrink:0;transition:color .15s}.shelf-back:hover{color:var(--ink-dark)}.shelf-back-arrow{font-size:12px;line-height:1}.shelf-back-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shelf-section-spine{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;width:100%;min-height:52px;padding:8px 4px;border-radius:4px;background:var(--bg-hover);border-left:3px solid var(--ink-light);cursor:pointer;transition:background .15s,border-color .15s;flex-shrink:0}.shelf-section-spine:hover{background:var(--border);border-left-color:var(--ink-dark)}.shelf-section-container{border-left-color:var(--border);background:transparent;min-height:44px}.shelf-section-container:hover{background:var(--bg-hover);border-left-color:var(--ink-light)}.shelf-section-title{font-size:9px;font-weight:600;color:var(--ink-dark);text-align:center;line-height:1.2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;word-break:break-word}.shelf-section-count{font-size:9px;color:var(--ink-light);background:var(--bg-sidebar);border-radius:8px;padding:1px 5px;line-height:1}.shelf-docs{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}.shelf-docs-header{padding:8px 10px;font-size:11px;font-weight:600;color:var(--ink-dark);border-bottom:1px solid var(--border);flex-shrink:0}.shelf-docs-list{flex:1;overflow-y:auto;padding:4px 0}.shelf-doc-item{padding:8px 10px;cursor:pointer;transition:background .1s}.shelf-doc-item:hover{background:var(--bg-hover)}.shelf-doc-item.active{background:var(--bg-hover);border-left:2px solid var(--ink-dark)}.shelf-doc-title{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:500;color:var(--ink-dark);line-height:1.3}.shelf-doc-meta{font-size:10px;color:var(--ink-light);margin-top:2px}.shelf-pending-dot{width:6px;height:6px;border-radius:50%;background:#22c55e;flex-shrink:0}.shelf-docs-empty{padding:16px 10px;font-size:11px;color:var(--ink-light);text-align:center}.shelf-add{width:100%;min-height:36px;border:2px dashed var(--border);border-radius:4px;background:none;cursor:pointer;color:var(--ink-light);font-size:16px;transition:all .15s;flex-shrink:0}.shelf-add:hover{border-color:var(--ink-light);background:var(--bg-hover)}.sidebar{width:0;min-width:0;overflow:hidden;background:var(--bg-sidebar);border-right:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease,min-width .2s ease}.sidebar.open{width:260px;min-width:260px}.sidebar-topbar{height:48px;min-height:48px;display:flex;align-items:center;justify-content:space-between;padding:0 8px 0 12px;background:var(--bg-titlebar);border-bottom:1px solid var(--border);flex-shrink:0}.sidebar-logo{display:flex;align-items:center;gap:8px;color:var(--ink-dark)}.sidebar-logo svg{flex-shrink:0}.sidebar-logo-text{font-size:15px;font-weight:600;letter-spacing:.02em}.sidebar-collapse-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;cursor:pointer;color:var(--ink-light);border-radius:6px;padding:0;transition:all .15s ease}.sidebar-collapse-btn:hover{background:var(--bg-hover);color:var(--ink-dark)}.sidebar-scroll{flex:1;overflow-y:auto;display:flex;flex-direction:column}.sidebar-section{border-bottom:1px solid var(--border)}.sidebar-section-header{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px;border-left:3px solid transparent;padding:10px 12px 10px 9px;transition:border-color .15s ease}.sidebar-workspace-section{position:relative}.sidebar-workspace-section>.sidebar-section-header{border-left-color:var(--accent)}.sidebar-workspace-section.ws-collapsed>.sidebar-section-header{border-left-color:transparent}.sidebar-docs-section>.sidebar-section-header{border-left-color:#9b9690}.sidebar-docs-section.docs-collapsed>.sidebar-section-header{border-left-color:transparent}.sidebar-section-header:hover{background:var(--bg-hover)}.sidebar-chevron{font-size:10px;color:var(--ink-light);transition:transform .15s ease;flex-shrink:0;width:12px;text-align:center}.sidebar-chevron.collapsed{transform:rotate(-90deg)}.sidebar-label{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-light);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-workspace-label{text-transform:none;letter-spacing:normal}.sidebar-section-list{padding:0 8px 8px}.sidebar-new-btn{width:22px;height:22px;border:1px solid var(--border);border-radius:5px;background:var(--bg-surface);cursor:pointer;font-size:16px;line-height:1;color:var(--ink-light);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all .15s ease}.sidebar-new-btn:hover{background:var(--bg-hover);border-color:#cbd5e1;color:var(--ink-dark)}.sidebar-workspace-delete{font-size:14px}.sidebar-workspace-actions{display:flex;gap:4px;align-items:center;flex-shrink:0}.sidebar-item{position:relative;padding:8px 10px;border-radius:6px;cursor:pointer;transition:background .1s ease;display:flex;flex-direction:column}.sidebar-item:hover{background:var(--bg-hover)}.sidebar-item.active{background:#2563eb0f}.sidebar-item.sidebar-missing{opacity:.5}.sidebar-item.sidebar-unavailable{opacity:.5;font-style:italic;cursor:default}.sidebar-item-title{font-size:13px;font-weight:500;color:var(--ink-dark);display:flex;align-items:center;padding-right:20px;min-width:0}.sidebar-item-title-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}.sidebar-item-context{font-size:10px;color:var(--ink-light);opacity:.7;margin-top:1px;font-style:italic}.sidebar-item-meta{font-size:11px;color:var(--ink-light);margin-top:2px}.sidebar-container{position:relative;margin-left:12px;border-left:2px solid var(--border);margin-bottom:2px;transition:border-color .15s ease}.sidebar-container.collapsed{border-left-color:transparent}.sidebar-container.depth-0{margin-left:4px}.sidebar-container.depth-1,.sidebar-container.depth-2{margin-left:12px}.sidebar-container-header{display:flex;align-items:center;padding:6px 8px;cursor:pointer;-webkit-user-select:none;user-select:none;gap:4px;font-size:12px}.sidebar-container-header:hover{background:var(--bg-hover)}.sidebar-container-name{font-weight:600;color:var(--ink-dark);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-container-list{padding:0 4px 4px}.sidebar-container-list.drag-over{background:#2563eb0f;outline:2px dashed rgba(37,99,235,.3);border-radius:6px;min-height:24px}.sidebar-workspace-section.drop-before:before,.sidebar-workspace-section.drop-after:after{content:"";position:absolute;left:4px;right:4px;height:2px;background:#2563eb;border-radius:1px;z-index:1;pointer-events:none}.sidebar-workspace-section.drop-before:before{top:0}.sidebar-workspace-section.drop-after:after{bottom:0}.sidebar-workspace-section.dragging{opacity:.4}.sidebar-workspace-section>.sidebar-section-header{cursor:grab}.sidebar-item.drop-before:before,.sidebar-container.drop-before:before{content:"";position:absolute;top:0;left:4px;right:4px;height:2px;background:#2563eb;border-radius:1px;z-index:1;pointer-events:none}.sidebar-item.drop-after:after,.sidebar-container.drop-after:after{content:"";position:absolute;bottom:0;left:4px;right:4px;height:2px;background:#2563eb;border-radius:1px;z-index:1;pointer-events:none}.sidebar-container-header.drop-inside{background:#2563eb14}.sidebar-container.drop-inside{outline:2px dashed rgba(37,99,235,.4);border-radius:6px;background:#2563eb08}.sidebar-container-actions{display:flex;gap:2px;align-items:center;flex-shrink:0;opacity:0;transition:opacity .1s ease}.sidebar-container-header:hover .sidebar-container-actions{opacity:1}.sidebar-container-delete{font-size:12px}.sidebar-rename-input{width:100%;font-size:13px;font-weight:500;border:1px solid var(--accent);border-radius:4px;padding:2px 6px;outline:none;font-family:var(--font-body)}.sidebar-delete-btn{position:absolute;top:8px;right:6px;width:18px;height:18px;border:none;background:none;cursor:pointer;font-size:14px;color:var(--ink-light);border-radius:4px;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .1s ease}.sidebar-item:hover .sidebar-delete-btn{opacity:1}.sidebar-delete-btn:hover{background:#fee2e2;color:#dc2626}.sidebar-confirm-delete{display:flex;align-items:center;gap:6px;margin-top:4px;font-size:12px;color:#dc2626}.sidebar-confirm-delete button{padding:2px 8px;border:1px solid var(--border);border-radius:4px;background:var(--bg-surface);cursor:pointer;font-size:11px;font-family:var(--font-body)}.sidebar-confirm-delete button:first-of-type{border-color:#dc2626;color:#dc2626}.sidebar-confirm-delete button:first-of-type:hover{background:#dc2626;color:#fff}.sidebar-inline-confirm{display:inline-flex;gap:2px}.sidebar-inline-confirm button{padding:1px 6px;border:1px solid var(--border);border-radius:3px;background:var(--bg-surface);cursor:pointer;font-size:10px;font-family:var(--font-body)}.sidebar-inline-confirm button:first-of-type{border-color:#dc2626;color:#dc2626}.sidebar-item[data-drag-id],.sidebar-container-header[data-drag-id]{cursor:grab}.sidebar-item.dragging,.sidebar-container-header.dragging{cursor:grabbing}.sidebar-item.dragging,.sidebar-container.dragging{opacity:.4}.sidebar-section-list.drag-over{background:#2563eb0f;outline:2px dashed rgba(37,99,235,.3);border-radius:6px;min-height:32px}.sidebar-empty{font-size:12px;color:var(--ink-light);padding:8px 10px;font-style:italic}.sidebar-new-workspace{padding:12px;border-top:1px solid var(--border);flex-shrink:0}.sidebar-new-workspace button{width:100%;padding:6px 0;border:1px dashed var(--border);border-radius:6px;background:none;cursor:pointer;font-size:12px;color:var(--ink-light);font-family:var(--font-body);transition:all .15s ease}.sidebar-new-workspace button:hover{border-color:#cbd5e1;color:var(--ink-dark);background:var(--bg-hover)}.sidebar-tags{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px;align-items:center}.sidebar-tag{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;font-size:10px;border-radius:3px;background:var(--bg-hover);color:var(--ink-light);white-space:nowrap}.sidebar-tag-remove{cursor:pointer;opacity:0;transition:opacity .1s;margin-left:1px}.sidebar-tag:hover .sidebar-tag-remove{opacity:1}.sidebar-tag-remove:hover{color:#dc2626}.sidebar-tag-add{padding:1px 4px;font-size:10px;border-radius:3px;background:none;border:1px dashed var(--border);color:var(--ink-light);cursor:pointer}.sidebar-tag-add:hover{border-color:#cbd5e1;color:var(--ink-dark)}.sidebar-tag-input{font-size:10px;padding:1px 4px;border:1px solid #2563eb;border-radius:3px;outline:none;width:60px;font-family:var(--font-body)}.sidebar-pending-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#16a34a;margin-left:6px;flex-shrink:0;vertical-align:middle}.sync-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0006;display:flex;align-items:center;justify-content:center;z-index:1000}.sync-modal{background:var(--bg-surface);border-radius:12px;width:440px;max-width:90vw;box-shadow:0 8px 32px #0000002e;overflow:hidden}.sync-modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border)}.sync-modal-header h2{font-size:16px;font-weight:600}.sync-modal-close{background:none;border:none;font-size:20px;cursor:pointer;color:var(--ink-light);padding:0 4px}.sync-modal-body{padding:20px}.sync-tabs{display:flex;gap:4px;margin-bottom:16px;border-bottom:1px solid var(--border);padding-bottom:8px}.sync-tab{background:none;border:none;padding:6px 12px;font-size:13px;color:var(--ink-light);cursor:pointer;border-radius:6px;transition:all .15s}.sync-tab:hover{background:#0000000a}.sync-tab.active{background:var(--accent);color:#fff}.sync-form{display:flex;flex-direction:column;gap:12px}.sync-form label{display:flex;flex-direction:column;gap:4px;font-size:13px;color:var(--ink-light)}.sync-form input[type=text],.sync-form input[type=password]{padding:8px 10px;border:1px solid var(--border);border-radius:6px;font-size:14px;background:var(--bg-surface);color:var(--ink-dark)}.sync-form input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px #2563eb26}.sync-checkbox{flex-direction:row!important;align-items:center;gap:8px!important}.sync-checkbox input[type=checkbox]{width:16px;height:16px}.sync-hint{font-size:13px;color:var(--ink-light);margin-bottom:4px}.sync-hint a{color:var(--accent)}.sync-hint code{font-size:12px}.sync-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.sync-btn{padding:8px 16px;border:none;border-radius:6px;font-size:13px;cursor:pointer;transition:opacity .15s}.sync-btn:disabled{opacity:.5;cursor:not-allowed}.sync-btn.primary{background:var(--accent);color:#fff}.sync-btn.primary:hover:not(:disabled){opacity:.9}.sync-btn.secondary{background:#0000000f;color:var(--ink-dark)}.sync-btn.secondary:hover{background:#0000001a}.sync-spinner{width:24px;height:24px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:sync-spin .8s linear infinite;margin:0 auto 12px}@keyframes sync-spin{to{transform:rotate(360deg)}}.sync-success-icon{width:40px;height:40px;border-radius:50%;background:#22c55e;color:#fff;display:flex;align-items:center;justify-content:center;font-size:20px;margin:0 auto 12px}.sync-error-msg{background:#fef2f2;border:1px solid #fecaca;color:#dc2626;padding:10px 14px;border-radius:6px;font-size:13px;margin-bottom:8px}.sync-warning{background:#fffbeb;border:1px solid #fed7aa;color:#92400e;padding:10px 14px;border-radius:6px;font-size:13px}.sync-warning a{color:var(--accent)}.pending-insert{color:var(--color-pending-insert);background-color:var(--color-pending-insert-bg);border-left:3px solid var(--color-pending-insert-border);border-radius:3px;padding:4px 8px;transition:background-color .2s ease}.pending-rewrite{color:var(--color-pending-rewrite);background-color:var(--color-pending-rewrite-bg);border-left:3px solid var(--color-pending-rewrite-border);border-radius:3px;padding:4px 8px;transition:background-color .2s ease}.pending-delete{color:var(--color-pending-delete);background-color:var(--color-pending-delete-bg);border-left:3px solid var(--color-pending-delete-border);border-radius:3px;padding:4px 8px;text-decoration:line-through;text-decoration-color:var(--color-pending-delete);opacity:.8;transition:background-color .2s ease,opacity .2s ease}.pending-delete *{text-decoration:line-through;text-decoration-color:inherit}.pending-focused,.pending-insert.pending-focused,.pending-rewrite.pending-focused,.pending-delete.pending-focused{outline:2px solid var(--color-pending-focus);outline-offset:2px;box-shadow:0 0 0 4px #6366f133}.pending-insert:hover{background-color:#16a34a26}.pending-rewrite:hover{background-color:#2563eb26}.pending-delete:hover{background-color:#e74c3c26;opacity:.9}.review-panel{position:absolute;bottom:24px;left:50%;transform:translate(-50%);background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;box-shadow:0 4px 20px #00000026;padding:6px 14px;display:flex;gap:10px;align-items:center;z-index:1000;font-family:var(--font-body);font-size:14px}.review-panel__nav{display:flex;gap:3px;align-items:center}.review-panel__btn{width:30px;height:30px;border:1px solid var(--border);border-radius:6px;background:var(--bg-surface);cursor:pointer;font-family:inherit;color:var(--ink-light);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all .15s ease;line-height:1;padding:0}.review-panel__btn:hover{background:var(--bg-hover);color:var(--ink-dark)}.review-panel__btn:disabled{opacity:.35;cursor:default}.review-panel__divider{width:1px;height:24px;background:var(--border)}.review-panel__counter{font-size:13px;color:var(--ink-light);white-space:nowrap;display:flex;align-items:center;gap:4px;padding:0 4px}.review-panel__dot{width:7px;height:7px;border-radius:50%;display:inline-block}.review-panel__dot--insert{background:var(--color-pending-insert)}.review-panel__dot--rewrite{background:var(--color-pending-rewrite)}.review-panel__dot--delete{background:var(--color-pending-delete)}.review-panel__status{font-size:13px;color:var(--ink-light);white-space:nowrap;display:flex;align-items:center;gap:6px}.review-panel__actions{display:flex;gap:4px}.review-panel__accept{width:30px;height:30px;background:var(--color-pending-insert);color:#fff;border:none;border-radius:6px;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;transition:all .15s ease}.review-panel__accept:hover{filter:brightness(.85)}.review-panel__reject{width:30px;height:30px;background:var(--bg-surface);color:var(--color-pending-delete);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;transition:all .15s ease}.review-panel__reject:hover{background:var(--color-pending-delete-bg);border-color:var(--color-pending-delete-border);color:var(--color-pending-delete)}.review-panel__accept-all{height:30px;padding:0 10px;background:var(--color-pending-insert);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:13px;font-family:inherit;font-weight:500;white-space:nowrap;display:flex;align-items:center;gap:3px;flex-shrink:0;transition:all .15s ease}.review-panel__accept-all:hover{filter:brightness(.85)}.review-panel__reject-all{height:30px;padding:0 10px;background:var(--bg-surface);color:var(--color-pending-delete);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-size:13px;font-family:inherit;font-weight:500;white-space:nowrap;display:flex;align-items:center;gap:3px;flex-shrink:0;transition:all .15s ease}.review-panel__reject-all:hover{background:var(--color-pending-delete-bg);border-color:var(--color-pending-delete-border);color:var(--color-pending-delete)}[data-mode=dark] .review-panel{border-color:#ffffff14;box-shadow:0 4px 24px #0009,0 0 0 1px #ffffff0a}[data-mode=dark] .review-panel__btn{border-color:#ffffff14;background:transparent}[data-mode=dark] .review-panel__btn:hover{background:#ffffff0f;border-color:#ffffff26}[data-mode=dark] .review-panel__divider{background:#ffffff14}[data-mode=dark] .review-panel__reject,[data-mode=dark] .review-panel__reject-all{background:transparent;border-color:#ffffff14}[data-mode=dark] .review-panel__reject:hover,[data-mode=dark] .review-panel__reject-all:hover{background:var(--color-pending-delete-bg);border-color:var(--color-pending-delete-border)}[data-mode=dark] .review-panel__accept:hover,[data-mode=dark] .review-panel__accept-all:hover{filter:brightness(1.15)}@keyframes flash-accept{0%{background-color:#16a34a4d}to{background-color:transparent}}@keyframes flash-reject{0%{background-color:#dc26264d}to{background-color:transparent}}.titlebar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:8px 16px;border-bottom:1px solid var(--border);background:var(--bg-titlebar);height:48px;flex-shrink:0}.titlebar-left{display:flex;align-items:center;gap:8px;justify-self:start}.titlebar-center{justify-self:center;min-width:0;overflow:hidden}.titlebar-menu-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;cursor:pointer;color:var(--ink-light);border-radius:6px;transition:all .15s ease}.titlebar-menu-btn:hover{background:var(--bg-hover);color:var(--ink-dark)}.titlebar-nav-btn{display:flex;align-items:center;justify-content:center;width:26px;height:26px;border:none;background:none;cursor:pointer;color:var(--ink-light);border-radius:4px;transition:all .15s ease;padding:0}.titlebar-nav-btn:hover:not(:disabled){background:var(--bg-hover);color:var(--ink-dark)}.titlebar-nav-btn:disabled{color:var(--border);cursor:default}.titlebar-nav-btn--active{background:#2563eb1a;color:var(--accent)}.titlebar-divider{width:1px;height:18px;background:var(--border);margin:0 2px}.titlebar-title{font-size:15px;font-weight:500;color:var(--ink-dark);cursor:pointer}.titlebar-input{font-size:15px;font-weight:500;border:1px solid var(--accent);border-radius:4px;padding:2px 6px;outline:none;font-family:var(--font-body)}.titlebar-right{display:flex;align-items:center;gap:10px;justify-self:end}.titlebar-btn{padding:5px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg-surface);cursor:pointer;font-size:13px;color:var(--ink-dark);font-family:var(--font-body);transition:all .15s ease}.titlebar-btn:hover{background:var(--bg-hover);border-color:#cbd5e1}.titlebar-btn.submitted{background:var(--color-pending-insert);color:#fff;border-color:var(--color-pending-insert);cursor:default}.titlebar-btn.primary{background:var(--accent);color:#fff;border-color:var(--accent)}.titlebar-btn.primary:hover{background:#1d4ed8}.context-menu{position:fixed;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 20px #00000026;padding:4px;z-index:2000;min-width:180px}.context-menu-item{display:flex;justify-content:space-between;align-items:center;width:100%;padding:8px 12px;border:none;background:none;cursor:pointer;font-size:13px;color:var(--ink-dark);border-radius:4px;text-align:left;font-family:var(--font-body)}.context-menu-item:hover{background:var(--bg-hover)}.context-menu-shortcut{font-size:11px;color:var(--ink-light);margin-left:16px}.context-menu-loading{padding:12px;text-align:center;color:var(--ink-light);font-size:13px}.context-menu-custom{display:flex;gap:6px;padding:8px}.context-menu-custom input{flex:1;padding:6px 8px;border:1px solid var(--border);border-radius:4px;font-size:13px;outline:none;font-family:var(--font-body)}.context-menu-custom input:focus{border-color:var(--accent)}.context-menu-custom button{padding:6px 12px;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-family:var(--font-body)}.context-menu-link-picker{max-height:240px;display:flex;flex-direction:column}.context-menu-link-header{padding:6px 12px;font-size:11px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.5px}.context-menu-link-list{overflow-y:auto;max-height:240px}.context-menu-new-link{color:var(--accent)!important;font-weight:500;border-bottom:1px solid var(--border-light)}.context-menu-section-header{padding:6px 12px 4px;font-size:10px;font-weight:600;color:var(--ink-light);text-transform:uppercase;letter-spacing:.5px;border-top:1px solid var(--border-light);margin-top:2px}.pending-inline-rewrite{background:#2563eb26;border-bottom:2px solid var(--color-pending-rewrite);border-radius:2px;padding:0 1px}.pending-inline-insert{background:#16a34a26;border-bottom:2px solid var(--color-pending-insert);border-radius:2px;padding:0 1px}.pending-inline-parent{border-left:3px solid var(--color-pending-rewrite-border);border-radius:3px;padding-left:8px}.tiptap table{border-collapse:collapse;width:100%;margin:1em 0}.tiptap th,.tiptap td{border:1px solid var(--border);padding:8px 12px;text-align:left}.tiptap th{background:var(--bg-hover);font-weight:600}.tiptap .doc-link{color:var(--accent);border-bottom:1px solid transparent;transition:border-color .15s ease;cursor:pointer}.tiptap .doc-link:hover{border-bottom-color:var(--accent)}@media(max-width:640px){.review-panel{bottom:16px;padding:8px 12px;gap:8px}.review-panel__status{display:none}}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{height:100%}body{font-family:var(--font-body);background:var(--bg-primary);color:var(--ink-dark);-webkit-font-smoothing:antialiased}.app{display:flex;flex-direction:row;height:100vh;overflow:hidden}.app-main{display:flex;flex-direction:column;flex:1;min-width:0;overflow:hidden;position:relative}.editor-container{flex:1;overflow-y:auto;padding:2rem 1rem;min-width:0}.app:has(.review-panel) .editor-container{padding-bottom:5rem}.tiptap{max-width:var(--editor-max-width);margin:0 auto;padding:0 1rem;font-family:var(--editor-font);font-size:var(--editor-font-size);line-height:var(--editor-line-height);letter-spacing:var(--editor-letter-spacing);color:var(--editor-color);outline:none}.tiptap p{margin-bottom:1em}.tiptap h1{font-family:var(--font-heading-h1);font-size:var(--h1-size);font-weight:var(--h1-weight);letter-spacing:var(--h1-spacing);line-height:var(--h1-line-height);color:var(--h1-color);font-style:var(--h1-style);margin-bottom:.5em}.tiptap h2{font-family:var(--font-heading-h2);font-size:var(--h2-size);font-weight:var(--h2-weight);letter-spacing:var(--h2-spacing);line-height:var(--h2-line-height);color:var(--h2-color);margin-bottom:.5em}.tiptap h3{font-family:var(--font-heading-h3);font-size:var(--h3-size);font-weight:var(--h3-weight);letter-spacing:var(--h3-spacing);line-height:var(--h3-line-height);color:var(--h3-color);text-transform:var(--h3-transform);border-bottom:var(--h3-border);padding-bottom:var(--h3-pb);display:var(--h3-display);margin-bottom:.5em}.tiptap ul,.tiptap ol{padding-left:1.5em;margin-bottom:1em}.tiptap li{margin-bottom:.25em}.tiptap blockquote{border-left:var(--blockquote-border-width) solid var(--blockquote-border);padding-left:1em;margin-left:0;margin-bottom:1em;color:var(--ink-light);font-style:italic;opacity:var(--blockquote-opacity);font-size:var(--blockquote-font-size)}.tiptap code{background:#0000000d;padding:.15em .3em;border-radius:3px;font-size:.9em}.tiptap pre{background:#1e1e1e;color:#d4d4d4;padding:1em;border-radius:6px;margin-bottom:1em;overflow-x:auto}.tiptap pre code{background:none;padding:0;color:inherit}.tiptap hr{border:none;border-top:1px solid var(--border);margin:2em 0}.tiptap p.is-editor-empty:first-child:before{content:attr(data-placeholder);float:left;color:#adb5bd;pointer-events:none;height:0}.tiptap ::selection{background:#2563eb26}.sync-btn-state{display:inline-flex;align-items:center;gap:6px}.sync-btn-state svg{flex-shrink:0}.sync-unconfigured{background:var(--accent);color:#fff;border-color:var(--accent)}.sync-synced{background:#22c55e;color:#fff;border-color:#22c55e}.sync-pending{background:var(--accent);color:#fff;border-color:var(--accent)}.sync-syncing{background:var(--accent);color:#fff;border-color:var(--accent);opacity:.8}.sync-error{background:#dc2626;color:#fff;border-color:#dc2626}.sync-btn-state:hover{background:#1d4ed8!important;border-color:#1d4ed8!important}.sync-synced:hover{background:#16a34a!important;border-color:#16a34a!important}.sync-error:hover{background:#b91c1c!important;border-color:#b91c1c!important}.sync-btn-spinner{width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:sync-btn-spin .8s linear infinite}@keyframes sync-btn-spin{to{transform:rotate(360deg)}}.sync-btn-group{position:relative;display:flex;align-items:center;gap:0}.sync-details-btn{display:flex;align-items:center;justify-content:center;width:24px;height:28px;border:1px solid var(--accent);border-left:1px solid rgba(255,255,255,.3);border-radius:0 6px 6px 0;background:var(--accent);color:#fff;cursor:pointer;transition:background .15s ease;margin-left:-1px}.sync-details-btn:hover{background:#1d4ed8}.sync-btn-group .sync-btn-state:has(+.sync-details-btn){border-radius:6px 0 0 6px}.sync-pending-dropdown{position:absolute;top:calc(100% + 6px);right:0;width:320px;max-height:400px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0000001f;z-index:100;overflow:hidden}.sync-pending-header{padding:10px 14px;font-size:12px;font-weight:600;color:var(--ink-muted);text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border)}.sync-pending-loading{padding:20px 14px;text-align:center;color:var(--ink-muted);font-size:13px}.sync-pending-list{max-height:350px;overflow-y:auto}.sync-pending-item{display:flex;align-items:center;gap:8px;padding:7px 14px;font-size:13px;border-bottom:1px solid var(--border-light)}.sync-pending-item:last-child{border-bottom:none}.sync-file-badge{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:4px;font-size:11px;font-weight:600;flex-shrink:0}.sync-file-added .sync-file-badge{background:#dcfce7;color:#16a34a}.sync-file-modified .sync-file-badge{background:#dbeafe;color:#2563eb}.sync-file-deleted .sync-file-badge{background:#fee2e2;color:#dc2626}.sync-file-renamed .sync-file-badge{background:#fef3c7;color:#d97706}.sync-file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink-dark)}.node-blur-effect{filter:blur(1.5px);opacity:1;pointer-events:none;transition:filter .3s ease,opacity .3s ease;position:relative;overflow:hidden}.node-blur-effect:after{content:"";position:absolute;top:0;left:-100%;width:250%;height:100%;background:linear-gradient(90deg,transparent 0%,transparent 40%,var(--shimmer-highlight) 50%,transparent 60%,transparent 100%);animation:shimmer-paragraph-sweep 2.8s ease-in-out infinite;pointer-events:none}@keyframes shimmer-paragraph-sweep{0%{left:-150%}to{left:100%}}.node-blur-selection{filter:blur(1.5px);display:inline;background:linear-gradient(90deg,var(--ink-dark) 0%,var(--ink-dark) 45%,var(--shimmer-highlight) 50%,var(--ink-dark) 55%,var(--ink-dark) 100%);background-size:250% 100%;background-clip:text;-webkit-background-clip:text;color:transparent;animation:shimmer-text-flow 4.2s ease-in-out infinite;box-decoration-break:clone;-webkit-box-decoration-break:clone;background-attachment:fixed;pointer-events:none}@keyframes shimmer-text-flow{0%{background-position:110% 0}to{background-position:-60% 0}}.node-blur-effect::selection,.node-blur-effect *::selection,.node-blur-selection::selection,.node-blur-selection *::selection{background:transparent!important}.ProseMirror:has(.node-blur-effect) ::selection,.ProseMirror:has(.node-blur-selection) ::selection{background:#00000003!important}.tiptap ul[data-type=taskList]{list-style:none;padding-left:0;margin-bottom:1em}.tiptap ul[data-type=taskList] li{display:flex;align-items:flex-start;gap:.5em;margin-bottom:.25em}.tiptap ul[data-type=taskList] li>label{flex-shrink:0;margin-top:.2em}.tiptap ul[data-type=taskList] li>label input[type=checkbox]{cursor:pointer;width:16px;height:16px}.tiptap ul[data-type=taskList] li>div{flex:1}.tiptap ul[data-type=taskList] li[data-checked=true]>div p{text-decoration:line-through;color:var(--ink-muted)}.tiptap img{max-width:100%;height:auto;border-radius:6px;margin-bottom:1em;display:block}.tiptap img.ProseMirror-selectednode{outline:2px solid var(--accent);outline-offset:2px}.tiptap pre code .hljs-keyword{color:#569cd6}.tiptap pre code .hljs-string{color:#ce9178}.tiptap pre code .hljs-number{color:#b5cea8}.tiptap pre code .hljs-comment{color:#6a9955;font-style:italic}.tiptap pre code .hljs-function,.tiptap pre code .hljs-title{color:#dcdcaa}.tiptap pre code .hljs-params{color:#9cdcfe}.tiptap pre code .hljs-built_in,.tiptap pre code .hljs-type{color:#4ec9b0}.tiptap pre code .hljs-attr,.tiptap pre code .hljs-variable{color:#9cdcfe}.tiptap pre code .hljs-selector-class{color:#d7ba7d}.tiptap pre code .hljs-selector-tag,.tiptap pre code .hljs-tag,.tiptap pre code .hljs-name{color:#569cd6}.tiptap pre code .hljs-attribute{color:#9cdcfe}.tiptap pre code .hljs-literal,.tiptap pre code .hljs-meta{color:#569cd6}.tiptap pre code .hljs-regexp{color:#d16969}.tiptap pre code .hljs-symbol{color:#b5cea8}
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>OpenWriter</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <link href="https://fonts.googleapis.com/css2?family=Charter:ital,wght@0,400;0,700;1,400&family=Crimson+Pro:ital,wght@0,300;0,400;0,600;0,700;1,400&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=DM+Serif+Display&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600&family=Inter:wght@400;500;600;700&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Literata:ital,opsz,wght@0,7..72,400;0,7..72,600;0,7..72,700;1,7..72,400&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,600;1,6..72,400&family=Playfair+Display:wght@400;600;700;900&family=Source+Serif+4:ital,opsz,wght@0,8..60,400;0,8..60,600;0,8..60,700;1,8..60,400&family=Space+Grotesk:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet" />
10
+ <script type="module" crossorigin src="/assets/index-DNJs7lC-.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-WweytMO1.css">
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ </body>
16
+ </html>
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Compact wire format for MCP tool communication.
3
+ * Tagged-line representation: ~10x token reduction vs pretty JSON.
4
+ *
5
+ * Format:
6
+ * title: My Document
7
+ * words: 1,247
8
+ * pending: 0
9
+ * ---
10
+ * [h1:abc12345] Chapter One
11
+ * [p:def45678] The quick brown fox.
12
+ * [ul:ghi78901]
13
+ * [li:jkl01234] First bullet
14
+ */
15
+ import { markdownToNodes } from './markdown.js';
16
+ // ============================================================================
17
+ // TipTap JSON -> Compact tagged-line format
18
+ // ============================================================================
19
+ const TYPE_MAP = {
20
+ heading: 'h',
21
+ paragraph: 'p',
22
+ blockquote: 'bq',
23
+ bulletList: 'ul',
24
+ orderedList: 'ol',
25
+ listItem: 'li',
26
+ codeBlock: 'cb',
27
+ horizontalRule: 'hr',
28
+ table: 'tbl',
29
+ tableRow: 'tr',
30
+ tableHeader: 'th',
31
+ tableCell: 'td',
32
+ taskList: 'tasks',
33
+ taskItem: 'task',
34
+ image: 'img',
35
+ };
36
+ function nodeId(id) {
37
+ return id || '________';
38
+ }
39
+ function compactType(node) {
40
+ if (node.type === 'heading') {
41
+ const level = node.attrs?.level || 1;
42
+ return `h${level}`;
43
+ }
44
+ return TYPE_MAP[node.type] || node.type;
45
+ }
46
+ function inlineToCompact(nodes) {
47
+ if (!nodes)
48
+ return '';
49
+ return nodes.map((node) => {
50
+ if (node.type === 'hardBreak')
51
+ return '\n';
52
+ if (node.type !== 'text')
53
+ return '';
54
+ let text = node.text || '';
55
+ if (!node.marks)
56
+ return text;
57
+ // Apply marks as markdown syntax
58
+ for (const mark of [...node.marks].reverse()) {
59
+ switch (mark.type) {
60
+ case 'bold':
61
+ text = `**${text}**`;
62
+ break;
63
+ case 'italic':
64
+ text = `*${text}*`;
65
+ break;
66
+ case 'code':
67
+ text = `\`${text}\``;
68
+ break;
69
+ case 'strike':
70
+ text = `~~${text}~~`;
71
+ break;
72
+ case 'underline':
73
+ text = `++${text}++`;
74
+ break;
75
+ case 'highlight':
76
+ text = `==${text}==`;
77
+ break;
78
+ case 'subscript':
79
+ text = `~${text}~`;
80
+ break;
81
+ case 'superscript':
82
+ text = `^${text}^`;
83
+ break;
84
+ case 'link':
85
+ text = `[${text}](${mark.attrs?.href || ''})`;
86
+ break;
87
+ }
88
+ }
89
+ return text;
90
+ }).join('');
91
+ }
92
+ function nodeToCompactLines(node, indent) {
93
+ const lines = [];
94
+ const tag = `[${compactType(node)}:${nodeId(node.attrs?.id)}]`;
95
+ if (node.type === 'horizontalRule') {
96
+ lines.push(`${indent}${tag}`);
97
+ return lines;
98
+ }
99
+ if (node.type === 'codeBlock') {
100
+ const lang = node.attrs?.language || '';
101
+ const text = (node.content || []).map((n) => n.text || '').join('');
102
+ lines.push(`${indent}${tag} \`\`\`${lang}`);
103
+ for (const codeLine of text.split('\n')) {
104
+ lines.push(`${indent} ${codeLine}`);
105
+ }
106
+ lines.push(`${indent} \`\`\``);
107
+ return lines;
108
+ }
109
+ // Table: render as container with rows, cells show inline content
110
+ if (node.type === 'table') {
111
+ lines.push(`${indent}${tag}`);
112
+ for (const row of node.content || []) {
113
+ const rowTag = `[${compactType(row)}:${nodeId(row.attrs?.id)}]`;
114
+ const cellTexts = (row.content || []).map((cell) => {
115
+ const para = cell.content?.[0];
116
+ return para ? inlineToCompact(para.content) : '';
117
+ });
118
+ lines.push(`${indent} ${rowTag} | ${cellTexts.join(' | ')} |`);
119
+ }
120
+ return lines;
121
+ }
122
+ // Image: inline representation
123
+ if (node.type === 'image') {
124
+ const src = node.attrs?.src || '';
125
+ const alt = node.attrs?.alt || '';
126
+ lines.push(`${indent}${tag} ![${alt}](${src})`);
127
+ return lines;
128
+ }
129
+ // Container nodes (lists, blockquotes, taskLists)
130
+ if (['bulletList', 'orderedList', 'blockquote', 'taskList'].includes(node.type)) {
131
+ lines.push(`${indent}${tag}`);
132
+ for (const child of node.content || []) {
133
+ lines.push(...nodeToCompactLines(child, indent + ' '));
134
+ }
135
+ return lines;
136
+ }
137
+ // Task items — checkbox prefix + first paragraph inline
138
+ if (node.type === 'taskItem') {
139
+ const checked = node.attrs?.checked ? '[x]' : '[ ]';
140
+ const children = node.content || [];
141
+ if (children.length > 0 && children[0].type === 'paragraph') {
142
+ const text = inlineToCompact(children[0].content);
143
+ lines.push(`${indent}${tag} ${checked} ${text}`);
144
+ for (let i = 1; i < children.length; i++) {
145
+ lines.push(...nodeToCompactLines(children[i], indent + ' '));
146
+ }
147
+ }
148
+ else {
149
+ lines.push(`${indent}${tag} ${checked}`);
150
+ for (const child of children) {
151
+ lines.push(...nodeToCompactLines(child, indent + ' '));
152
+ }
153
+ }
154
+ return lines;
155
+ }
156
+ // List items — show first paragraph inline, nest rest
157
+ if (node.type === 'listItem') {
158
+ const children = node.content || [];
159
+ if (children.length > 0 && children[0].type === 'paragraph') {
160
+ const text = inlineToCompact(children[0].content);
161
+ lines.push(`${indent}${tag} ${text}`);
162
+ for (let i = 1; i < children.length; i++) {
163
+ lines.push(...nodeToCompactLines(children[i], indent + ' '));
164
+ }
165
+ }
166
+ else {
167
+ lines.push(`${indent}${tag}`);
168
+ for (const child of children) {
169
+ lines.push(...nodeToCompactLines(child, indent + ' '));
170
+ }
171
+ }
172
+ return lines;
173
+ }
174
+ // Leaf nodes (heading, paragraph) — inline content on same line
175
+ const text = inlineToCompact(node.content);
176
+ lines.push(`${indent}${tag} ${text}`);
177
+ return lines;
178
+ }
179
+ export function toCompactFormat(doc, title, wordCount, pendingCount) {
180
+ const header = [
181
+ `title: ${title}`,
182
+ `words: ${wordCount.toLocaleString()}`,
183
+ `pending: ${pendingCount}`,
184
+ '---',
185
+ ];
186
+ const body = [];
187
+ for (const node of doc.content || []) {
188
+ body.push(...nodeToCompactLines(node, ''));
189
+ }
190
+ return [...header, ...body].join('\n');
191
+ }
192
+ /**
193
+ * Convert an array of TipTap nodes to compact tagged-line format.
194
+ * Used by get_nodes tool.
195
+ */
196
+ export function compactNodes(nodes) {
197
+ const lines = [];
198
+ for (const node of nodes) {
199
+ lines.push(...nodeToCompactLines(node, ''));
200
+ }
201
+ return lines.join('\n');
202
+ }
203
+ // ============================================================================
204
+ // Markdown string -> TipTap JSONContent (for write_to_pad)
205
+ // ============================================================================
206
+ /**
207
+ * Parse a markdown string into TipTap node(s).
208
+ * Single paragraph -> single node. Multiple blocks -> array.
209
+ * Used when agents send markdown strings as content in write_to_pad.
210
+ */
211
+ export function parseMarkdownContent(content) {
212
+ const nodes = markdownToNodes(content);
213
+ return nodes.length === 1 ? nodes[0] : nodes;
214
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Multi-document operations for OpenWriter workspace.
3
+ * Manages listing, switching, creating, deleting documents.
4
+ * Each document is a .md file in ~/.openwriter/.
5
+ */
6
+ import { existsSync, readFileSync, writeFileSync, unlinkSync, readdirSync, statSync, mkdirSync } from 'fs';
7
+ import { join } from 'path';
8
+ import matter from 'gray-matter';
9
+ import { tiptapToMarkdown, markdownToTiptap } from './markdown.js';
10
+ import { parseMarkdownContent } from './compact.js';
11
+ import { getDocument, getTitle, getFilePath, save, cancelDebouncedSave, setActiveDocument, registerExternalDoc, unregisterExternalDoc, getExternalDocs, } from './state.js';
12
+ import { DATA_DIR, TEMP_PREFIX, ensureDataDir, filePathForTitle, tempFilePath, generateNodeId, resolveDocPath, isExternalDoc } from './helpers.js';
13
+ import { ensureDocId } from './versions.js';
14
+ export function listDocuments() {
15
+ ensureDataDir();
16
+ const currentPath = getFilePath();
17
+ const files = readdirSync(DATA_DIR)
18
+ .filter((f) => f.endsWith('.md'))
19
+ .map((f) => {
20
+ const fullPath = join(DATA_DIR, f);
21
+ try {
22
+ const stat = statSync(fullPath);
23
+ const raw = readFileSync(fullPath, 'utf-8');
24
+ // Use gray-matter directly — skip full TipTap parse for listing
25
+ const { data, content } = matter(raw);
26
+ const title = data.title || 'Untitled';
27
+ // Skip empty temp files (not the active doc)
28
+ const trimmed = content.trim();
29
+ if (f.startsWith(TEMP_PREFIX) && !trimmed && fullPath !== currentPath)
30
+ return null;
31
+ const wordCount = trimmed ? trimmed.split(/\s+/).length : 0;
32
+ return {
33
+ filename: f,
34
+ title,
35
+ path: fullPath,
36
+ lastModified: stat.mtime.toISOString(),
37
+ wordCount,
38
+ isActive: fullPath === currentPath,
39
+ };
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ })
45
+ .filter((f) => f !== null);
46
+ // Append registered external docs
47
+ for (const extPath of getExternalDocs()) {
48
+ try {
49
+ if (!existsSync(extPath)) {
50
+ unregisterExternalDoc(extPath); // Clean up stale registry entries
51
+ continue;
52
+ }
53
+ const stat = statSync(extPath);
54
+ const raw = readFileSync(extPath, 'utf-8');
55
+ const { data, content } = matter(raw);
56
+ const title = data.title || 'Untitled';
57
+ const trimmed = content.trim();
58
+ const wordCount = trimmed ? trimmed.split(/\s+/).length : 0;
59
+ files.push({
60
+ filename: extPath, // Full path as identifier
61
+ title,
62
+ path: extPath,
63
+ lastModified: stat.mtime.toISOString(),
64
+ wordCount,
65
+ isActive: extPath === currentPath,
66
+ });
67
+ }
68
+ catch { /* skip unreadable external files */ }
69
+ }
70
+ // Stable sort: alphabetical by filename (no reordering on switch)
71
+ files.sort((a, b) => a.filename.localeCompare(b.filename));
72
+ return files;
73
+ }
74
+ export function switchDocument(filename) {
75
+ // Cancel any pending debounced save, then save current doc immediately
76
+ cancelDebouncedSave();
77
+ save();
78
+ // Read target from disk — markdownToTiptap rehydrates pending state
79
+ const targetPath = resolveDocPath(filename);
80
+ if (!existsSync(targetPath)) {
81
+ throw new Error(`Document not found: ${filename}`);
82
+ }
83
+ // Register external docs so they appear in listings
84
+ if (isExternalDoc(filename)) {
85
+ registerExternalDoc(targetPath);
86
+ }
87
+ const raw = readFileSync(targetPath, 'utf-8');
88
+ const parsed = markdownToTiptap(raw);
89
+ const mtime = new Date(statSync(targetPath).mtimeMs);
90
+ // Ensure docId exists on loaded doc metadata (lazy migration)
91
+ ensureDocId(parsed.metadata);
92
+ const baseName = targetPath.split(/[/\\]/).pop() || '';
93
+ setActiveDocument(parsed.document, parsed.title, targetPath, baseName.startsWith(TEMP_PREFIX), mtime, parsed.metadata);
94
+ return { document: getDocument(), title: getTitle(), filename };
95
+ }
96
+ export function createDocument(title, content, path) {
97
+ // Cancel any pending debounced save, then save current doc immediately
98
+ cancelDebouncedSave();
99
+ save();
100
+ const docTitle = title || 'Untitled';
101
+ let filePath;
102
+ let isTemp;
103
+ let filename;
104
+ if (path) {
105
+ // External path — create file at the specified location
106
+ filePath = path;
107
+ isTemp = false;
108
+ filename = path; // Full path as identifier for external docs
109
+ registerExternalDoc(path);
110
+ // Ensure parent directory exists
111
+ const dir = filePath.substring(0, Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\')));
112
+ if (dir && !existsSync(dir)) {
113
+ mkdirSync(dir, { recursive: true });
114
+ }
115
+ }
116
+ else {
117
+ isTemp = !title;
118
+ filePath = isTemp ? tempFilePath() : filePathForTitle(docTitle);
119
+ filename = filePath.split(/[/\\]/).pop();
120
+ }
121
+ let newDoc;
122
+ if (content) {
123
+ if (typeof content === 'string') {
124
+ // Markdown string → TipTap JSON
125
+ newDoc = { type: 'doc', content: parseMarkdownContent(content) };
126
+ }
127
+ else {
128
+ // Already TipTap JSON
129
+ newDoc = content;
130
+ }
131
+ }
132
+ else {
133
+ newDoc = { type: 'doc', content: [{ type: 'paragraph', content: [] }] };
134
+ }
135
+ const metadata = { title: docTitle, docId: generateNodeId() };
136
+ setActiveDocument(newDoc, docTitle, filePath, isTemp, undefined, metadata);
137
+ // Write doc to disk
138
+ const markdown = tiptapToMarkdown(newDoc, docTitle, metadata);
139
+ ensureDataDir();
140
+ writeFileSync(filePath, markdown, 'utf-8');
141
+ return { document: getDocument(), title: getTitle(), filename };
142
+ }
143
+ export function deleteDocument(filename) {
144
+ ensureDataDir();
145
+ const targetPath = resolveDocPath(filename);
146
+ // Unregister if external
147
+ if (isExternalDoc(filename)) {
148
+ unregisterExternalDoc(targetPath);
149
+ }
150
+ const allDocs = readdirSync(DATA_DIR).filter((f) => f.endsWith('.md'));
151
+ if (allDocs.length <= 1) {
152
+ throw new Error('Cannot delete the only document');
153
+ }
154
+ const isDeletingActive = targetPath === getFilePath();
155
+ if (existsSync(targetPath)) {
156
+ unlinkSync(targetPath);
157
+ }
158
+ if (isDeletingActive) {
159
+ const remaining = readdirSync(DATA_DIR)
160
+ .filter((f) => f.endsWith('.md'))
161
+ .map((f) => ({ name: f, path: join(DATA_DIR, f), mtime: statSync(join(DATA_DIR, f)).mtimeMs }))
162
+ .sort((a, b) => b.mtime - a.mtime);
163
+ if (remaining.length > 0) {
164
+ const next = remaining[0];
165
+ const raw = readFileSync(next.path, 'utf-8');
166
+ const parsed = markdownToTiptap(raw);
167
+ setActiveDocument(parsed.document, parsed.title, next.path, next.name.startsWith(TEMP_PREFIX), new Date(next.mtime), parsed.metadata);
168
+ return { switched: true, newDoc: { document: getDocument(), title: getTitle(), filename: next.name } };
169
+ }
170
+ }
171
+ return { switched: false };
172
+ }
173
+ export function reloadDocument() {
174
+ const filePath = getFilePath();
175
+ if (!existsSync(filePath)) {
176
+ throw new Error('Active document file not found on disk');
177
+ }
178
+ const filename = filePath.split(/[/\\]/).pop();
179
+ const raw = readFileSync(filePath, 'utf-8');
180
+ const parsed = markdownToTiptap(raw);
181
+ const mtime = new Date(statSync(filePath).mtimeMs);
182
+ setActiveDocument(parsed.document, parsed.title, filePath, filename.startsWith(TEMP_PREFIX), mtime, parsed.metadata);
183
+ return { document: getDocument(), title: getTitle(), filename };
184
+ }
185
+ export function updateDocumentTitle(filename, newTitle) {
186
+ ensureDataDir();
187
+ const filePath = resolveDocPath(filename);
188
+ if (!existsSync(filePath)) {
189
+ throw new Error(`Document not found: ${filename}`);
190
+ }
191
+ const raw = readFileSync(filePath, 'utf-8');
192
+ const parsed = markdownToTiptap(raw);
193
+ const metadata = { ...parsed.metadata, title: newTitle };
194
+ const markdown = tiptapToMarkdown(parsed.document, newTitle, metadata);
195
+ writeFileSync(filePath, markdown, 'utf-8');
196
+ // Update state if this is the active document
197
+ const baseName = filePath.split(/[/\\]/).pop() || '';
198
+ if (getFilePath() === filePath) {
199
+ setActiveDocument(getDocument(), newTitle, filePath, baseName.startsWith(TEMP_PREFIX), undefined, metadata);
200
+ }
201
+ }
202
+ /** Open an existing file from any path. Saves current doc, registers as external, sets as active. */
203
+ export function openFile(fullPath) {
204
+ if (!existsSync(fullPath)) {
205
+ throw new Error(`File not found: ${fullPath}`);
206
+ }
207
+ // Cancel any pending debounced save, then save current doc immediately
208
+ cancelDebouncedSave();
209
+ save();
210
+ // Register as external if not in DATA_DIR
211
+ if (isExternalDoc(fullPath)) {
212
+ registerExternalDoc(fullPath);
213
+ }
214
+ const raw = readFileSync(fullPath, 'utf-8');
215
+ const parsed = markdownToTiptap(raw);
216
+ const mtime = new Date(statSync(fullPath).mtimeMs);
217
+ ensureDocId(parsed.metadata);
218
+ const baseName = fullPath.split(/[/\\]/).pop() || '';
219
+ setActiveDocument(parsed.document, parsed.title, fullPath, baseName.startsWith(TEMP_PREFIX), mtime, parsed.metadata);
220
+ // Use full path as filename for external docs, basename for DATA_DIR docs
221
+ const filename = isExternalDoc(fullPath) ? fullPath : baseName;
222
+ return { document: getDocument(), title: getTitle(), filename };
223
+ }
224
+ export function getActiveFilename() {
225
+ const filePath = getFilePath();
226
+ // For external docs, return the full path as the identifier
227
+ if (isExternalDoc(filePath))
228
+ return filePath;
229
+ return filePath.split(/[/\\]/).pop() || '';
230
+ }