← Notes results

Notes

Qwen 3.6 35b a3b · full

Initial view of Notes

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 61,835 bytes · SHA-256 5da70ed2dfd6
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Noteflow</title>
<style>
  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

  :root {
    --bg-primary: #1e1e2e;
    --bg-secondary: #181825;
    --bg-tertiary: #11111b;
    --bg-hover: #2a2a3d;
    --bg-active: #313244;
    --bg-input: #1e1e2e;
    --text-primary: #cdd6f4;
    --text-secondary: #a6adc8;
    --text-muted: #6c7086;
    --accent: #89b4fa;
    --accent-hover: #74c7ec;
    --accent-subtle: rgba(137, 180, 250, 0.1);
    --border: #313244;
    --red: #f38ba8;
    --green: #a6e3a1;
    --yellow: #f9e2af;
    --purple: #cba6f7;
    --orange: #fab387;
    --pink: #f5c2e7;
    --teal: #94e2d5;
    --scrollbar-thumb: #45475a;
    --shadow: rgba(0,0,0,0.3);
    --font-mono: 'SF Mono', 'Cascadia Code', 'Fira Code', 'JetBrains Mono', monospace;
    --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', Roboto, sans-serif;
    --font-serif: 'Georgia', 'Times New Roman', serif;
    --radius: 8px;
    --radius-sm: 4px;
    --transition: 150ms ease;
  }

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

  ::-webkit-scrollbar { width: 6px; height: 6px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 3px; }
  ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

  .app {
    display: flex;
    height: 100vh;
    width: 100vw;
  }

  /* ===== SIDEBAR ===== */
  .sidebar {
    width: 260px;
    min-width: 260px;
    background: var(--bg-secondary);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    transition: width var(--transition), min-width var(--transition), opacity var(--transition);
    overflow: hidden;
    position: relative;
  }

  .sidebar.collapsed {
    width: 0;
    min-width: 0;
    opacity: 0;
    border-right: none;
  }

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

  .sidebar-header .logo {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    flex-shrink: 0;
  }

  .sidebar-header .logo svg { flex-shrink: 0; }

  .sidebar-search {
    padding: 4px 12px 12px;
    flex-shrink: 0;
  }

  .sidebar-search input {
    width: 100%;
    padding: 8px 12px 8px 34px;
    background: var(--bg-input);
    border: 1px solid transparent;
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 13px;
    font-family: var(--font-sans);
    outline: none;
    transition: border-color var(--transition), background var(--transition);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%236c7086' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 10px center;
    background-size: 14px;
  }

  .sidebar-search input:focus {
    border-color: var(--accent);
    background-color: var(--bg-hover);
  }

  .sidebar-search input::placeholder { color: var(--text-muted); }

  .sidebar-section {
    flex-shrink: 0;
    padding: 0 8px;
  }

  .sidebar-section-title {
    padding: 8px 8px 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    user-select: none;
  }

  .sidebar-section-title:hover { color: var(--text-secondary); }

  .sidebar-section-title .chevron {
    transition: transform var(--transition);
    display: inline-block;
  }

  .sidebar-section-title .chevron.collapsed { transform: rotate(-90deg); }

  .sidebar-list {
    overflow-y: auto;
    max-height: 0;
    transition: max-height 300ms ease;
  }

  .sidebar-list.expanded { max-height: 600px; }

  .sidebar-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 13px;
    transition: background var(--transition), color var(--transition);
    user-select: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .sidebar-item:hover { background: var(--bg-hover); color: var(--text-primary); }
  .sidebar-item.active { background: var(--accent-subtle); color: var(--accent); }

  .sidebar-item .icon { flex-shrink: 0; width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; }

  .sidebar-item .count {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-muted);
  }

  .folder-children {
    padding-left: 16px;
    max-height: 0;
    overflow: hidden;
    transition: max-height 300ms ease;
  }

  .folder-children.expanded { max-height: 200px; }

  /* ===== NOTE LIST ===== */
  .note-list-panel {
    width: 280px;
    min-width: 200px;
    max-width: 400px;
    background: var(--bg-primary);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    flex-shrink: 0;
  }

  .note-list-header {
    padding: 16px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
  }

  .note-list-header h2 {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
  }

  .note-list-header-actions {
    display: flex;
    gap: 2px;
  }

  .note-list-header-actions button {
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: color var(--transition), background var(--transition);
  }

  .note-list-header-actions button:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
  }

  .note-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
  }

  .note-card {
    padding: 12px;
    border-radius: var(--radius);
    cursor: pointer;
    margin-bottom: 2px;
    transition: background var(--transition);
    border: 1px solid transparent;
  }

  .note-card:hover { background: var(--bg-hover); }
  .note-card.active { background: var(--bg-active); border-color: var(--border); }

  .note-card-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .note-card-preview {
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-bottom: 6px;
  }

  .note-card-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    color: var(--text-muted);
  }

  .note-card-tags {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    margin-top: 4px;
  }

  .note-card-tag {
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--accent-subtle);
    color: var(--accent);
  }

  /* ===== EDITOR ===== */
  .editor-panel {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
  }

  .editor-toolbar {
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    background: var(--bg-primary);
  }

  .editor-toolbar button {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: color var(--transition), background var(--transition);
    font-size: 13px;
  }

  .editor-toolbar button:hover { background: var(--bg-hover); color: var(--text-primary); }
  .editor-toolbar button.active { background: var(--accent-subtle); color: var(--accent); }

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

  .editor-breadcrumb {
    margin-left: auto;
    font-size: 12px;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: 4px;
  }

  .editor-content {
    flex: 1;
    overflow-y: auto;
    padding: 32px 48px;
    display: flex;
    flex-direction: column;
  }

  .editor-title {
    font-size: 32px;
    font-weight: 700;
    color: var(--text-primary);
    border: none;
    background: none;
    outline: none;
    width: 100%;
    margin-bottom: 8px;
    font-family: var(--font-sans);
    line-height: 1.3;
  }

  .editor-title::placeholder { color: var(--text-muted); }

  .editor-meta {
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 24px;
    display: flex;
    gap: 16px;
  }

  .editor-body {
    flex: 1;
    outline: none;
    font-size: 15px;
    line-height: 1.75;
    color: var(--text-primary);
    min-height: 300px;
    font-family: var(--font-sans);
  }

  .editor-body:empty::before {
    content: 'Start writing...';
    color: var(--text-muted);
    pointer-events: none;
  }

  .editor-body h1 { font-size: 28px; font-weight: 700; margin: 24px 0 12px; color: var(--text-primary); }
  .editor-body h2 { font-size: 22px; font-weight: 600; margin: 20px 0 10px; color: var(--text-primary); }
  .editor-body h3 { font-size: 18px; font-weight: 600; margin: 16px 0 8px; color: var(--text-primary); }
  .editor-body p { margin-bottom: 12px; }
  .editor-body blockquote {
    border-left: 3px solid var(--accent);
    padding: 8px 16px;
    margin: 12px 0;
    background: var(--accent-subtle);
    border-radius: 0 var(--radius) var(--radius) 0;
    color: var(--text-secondary);
  }
  .editor-body code {
    font-family: var(--font-mono);
    background: var(--bg-hover);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    font-size: 0.9em;
    color: var(--pink);
  }
  .editor-body pre {
    background: var(--bg-tertiary);
    padding: 16px;
    border-radius: var(--radius);
    overflow-x: auto;
    margin: 12px 0;
    border: 1px solid var(--border);
  }
  .editor-body pre code {
    background: none;
    padding: 0;
    color: var(--text-primary);
  }
  .editor-body ul, .editor-body ol { padding-left: 24px; margin: 8px 0; }
  .editor-body li { margin-bottom: 4px; }
  .editor-body hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 24px 0;
  }
  .editor-body a { color: var(--accent); text-decoration: underline; }
  .editor-body strong { font-weight: 600; color: var(--text-primary); }
  .editor-body em { font-style: italic; }
  .editor-body img { max-width: 100%; border-radius: var(--radius); margin: 8px 0; }
  .editor-body table { border-collapse: collapse; width: 100%; margin: 12px 0; }
  .editor-body th, .editor-body td { border: 1px solid var(--border); padding: 8px 12px; text-align: left; }
  .editor-body th { background: var(--bg-hover); font-weight: 600; }
  .editor-body .task-list { list-style: none; padding-left: 0; }
  .editor-body .task-list li { display: flex; align-items: flex-start; gap: 8px; }
  .editor-body .task-list input[type="checkbox"] { margin-top: 4px; accent-color: var(--accent); }

  /* ===== STATUS BAR ===== */
  .status-bar {
    padding: 4px 16px;
    font-size: 11px;
    color: var(--text-muted);
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--bg-secondary);
    flex-shrink: 0;
  }

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

  /* ===== CONTEXT MENU ===== */
  .context-menu {
    position: fixed;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 4px;
    min-width: 180px;
    box-shadow: 0 8px 32px var(--shadow);
    z-index: 1000;
    display: none;
  }

  .context-menu.visible { display: block; }

  .context-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 13px;
    color: var(--text-secondary);
    transition: background var(--transition), color var(--transition);
  }

  .context-menu-item:hover { background: var(--bg-hover); color: var(--text-primary); }
  .context-menu-item.danger { color: var(--red); }
  .context-menu-item.danger:hover { background: rgba(243, 139, 168, 0.1); }

  .context-menu-divider {
    height: 1px;
    background: var(--border);
    margin: 4px 0;
  }

  .context-menu-shortcut {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-muted);
  }

  /* ===== MODAL ===== */
  .modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 2000;
  }

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

  .modal {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    min-width: 400px;
    max-width: 500px;
    box-shadow: 0 16px 64px var(--shadow);
  }

  .modal h3 {
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 16px;
    color: var(--text-primary);
  }

  .modal input {
    width: 100%;
    padding: 10px 14px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 14px;
    font-family: var(--font-sans);
    outline: none;
    margin-bottom: 16px;
  }

  .modal input:focus { border-color: var(--accent); }

  .modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }

  .modal-btn {
    padding: 8px 16px;
    border-radius: var(--radius);
    border: none;
    cursor: pointer;
    font-size: 13px;
    font-family: var(--font-sans);
    transition: background var(--transition);
  }

  .modal-btn.cancel {
    background: var(--bg-hover);
    color: var(--text-secondary);
  }

  .modal-btn.cancel:hover { background: var(--bg-active); }

  .modal-btn.primary {
    background: var(--accent);
    color: var(--bg-tertiary);
    font-weight: 600;
  }

  .modal-btn.primary:hover { background: var(--accent-hover); }

  /* ===== EMPTY STATE ===== */
  .empty-state {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    gap: 12px;
  }

  .empty-state svg { opacity: 0.3; }
  .empty-state p { font-size: 14px; }
  .empty-state .hint { font-size: 12px; color: var(--text-muted); opacity: 0.6; }

  /* ===== RESIZE HANDLE ===== */
  .resize-handle {
    width: 4px;
    cursor: col-resize;
    background: transparent;
    flex-shrink: 0;
    transition: background var(--transition);
    position: relative;
  }

  .resize-handle:hover, .resize-handle.active { background: var(--accent); }

  /* ===== WELCOME ===== */
  .welcome-screen {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    padding: 40px;
  }

  .welcome-screen .welcome-icon {
    width: 80px;
    height: 80px;
    background: var(--accent-subtle);
    border-radius: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
  }

  .welcome-screen h1 {
    font-size: 28px;
    font-weight: 700;
    color: var(--text-primary);
  }

  .welcome-screen p {
    color: var(--text-muted);
    text-align: center;
    max-width: 400px;
    line-height: 1.6;
  }

  .welcome-shortcuts {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
  }

  .welcome-shortcut {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 13px;
    color: var(--text-secondary);
  }

  .welcome-shortcut kbd {
    background: var(--bg-hover);
    border: 1px solid var(--border);
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-muted);
  }

  /* ===== ANIMATIONS ===== */
  @keyframes fadeIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
  }

  .note-card { animation: fadeIn 200ms ease; }

  /* ===== FIND BAR ===== */
  .find-bar {
    position: absolute;
    top: 0;
    right: 24px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius) var(--radius);
    padding: 8px 12px;
    display: none;
    align-items: center;
    gap: 8px;
    box-shadow: 0 4px 16px var(--shadow);
    z-index: 100;
  }

  .find-bar.visible { display: flex; }

  .find-bar input {
    padding: 6px 10px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-size: 13px;
    outline: none;
    width: 240px;
    font-family: var(--font-sans);
  }

  .find-bar input:focus { border-color: var(--accent); }

  .find-bar button {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
  }

  .find-bar button:hover { color: var(--text-primary); background: var(--bg-hover); }

  /* ===== TAG PANEL ===== */
  .tag-panel {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-secondary);
    border-top: 1px solid var(--border);
    padding: 12px 16px;
    display: none;
    gap: 8px;
    flex-wrap: wrap;
    z-index: 50;
  }

  .tag-panel.visible { display: flex; }

  .tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 20px;
    font-size: 12px;
    cursor: pointer;
    transition: background var(--transition), transform var(--transition);
  }

  .tag:hover { transform: scale(1.05); }

  .tag-red { background: rgba(243,139,168,0.15); color: var(--red); }
  .tag-green { background: rgba(166,227,161,0.15); color: var(--green); }
  .tag-yellow { background: rgba(249,226,175,0.15); color: var(--yellow); }
  .tag-blue { background: rgba(137,180,250,0.15); color: var(--accent); }
  .tag-purple { background: rgba(203,166,247,0.15); color: var(--purple); }
  .tag-orange { background: rgba(250,179,135,0.15); color: var(--orange); }
  .tag-teal { background: rgba(148,226,213,0.15); color: var(--teal); }
  .tag-pink { background: rgba(245,194,231,0.15); color: var(--pink); }

  /* ===== TOOLTIP ===== */
  [data-tooltip] {
    position: relative;
  }

  [data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 8px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 11px;
    border-radius: var(--radius-sm);
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--transition);
    z-index: 100;
  }

  [data-tooltip]:hover::after { opacity: 1; }

  /* ===== NOTIFICATION ===== */
  .notification {
    position: fixed;
    bottom: 48px;
    left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 10px 20px;
    color: var(--text-primary);
    font-size: 13px;
    box-shadow: 0 8px 32px var(--shadow);
    opacity: 0;
    transition: all 300ms ease;
    z-index: 3000;
    pointer-events: none;
  }

  .notification.visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }

  /* ===== VIEW MODES ===== */
  .app.view-welcome .note-list-panel,
  .app.view-welcome .sidebar { display: none; }
  .app.view-welcome .editor-panel { background: var(--bg-primary); }

  /* ===== PRINT ===== */
  @media print {
    .sidebar, .note-list-panel, .editor-toolbar, .status-bar { display: none !important; }
    .editor-panel { width: 100% !important; }
    .editor-content { padding: 20px; }
  }
</style>
</head>
<body>
<div class="app" id="app">
  <!-- Sidebar -->
  <aside class="sidebar" id="sidebar">
    <div class="sidebar-header">
      <div class="logo">
        <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
        </svg>
        Noteflow
      </div>
    </div>

    <div class="sidebar-search">
      <input type="text" id="sidebarSearch" placeholder="Search notes..." autocomplete="off">
    </div>

    <div class="sidebar-section">
      <div class="sidebar-section-title" data-toggle="unsorted">
        <span>All Notes</span>
        <span class="chevron">▾</span>
      </div>
      <div class="sidebar-list expanded" id="unsortedList"></div>
    </div>

    <div class="sidebar-section">
      <div class="sidebar-section-title" data-toggle="folders">
        <span>Folders</span>
        <span class="chevron">▾</span>
      </div>
      <div class="sidebar-list expanded" id="foldersList"></div>
    </div>

    <div class="sidebar-section">
      <div class="sidebar-section-title" data-toggle="tags">
        <span>Tags</span>
        <span class="chevron">▾</span>
      </div>
      <div class="sidebar-list expanded" id="tagsList"></div>
    </div>

    <div class="sidebar-section">
      <div class="sidebar-section-title" data-toggle="recent">
        <span>Recent</span>
        <span class="chevron">▾</span>
      </div>
      <div class="sidebar-list expanded" id="recentList"></div>
    </div>
  </aside>

  <!-- Note List Panel -->
  <div class="note-list-panel" id="noteListPanel">
    <div class="note-list-header">
      <h2 id="noteListTitle">All Notes</h2>
      <div class="note-list-header-actions">
        <button id="btnNewNote" data-tooltip="New Note (Ctrl+N)">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
        </button>
        <button id="btnCollapseList" data-tooltip="Collapse">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="15 18 9 12 15 6"/></svg>
        </button>
      </div>
    </div>
    <div class="note-list" id="noteList"></div>
  </div>

  <!-- Resize Handle -->
  <div class="resize-handle" id="resizeHandle"></div>

  <!-- Editor Panel -->
  <div class="editor-panel" id="editorPanel">
    <div class="editor-toolbar" id="editorToolbar">
      <button id="btnToggleSidebar" data-tooltip="Toggle Sidebar (Ctrl+B)">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="9" y1="3" x2="9" y2="21"/></svg>
      </button>
      <div class="toolbar-divider"></div>
      <button id="btnBold" data-tooltip="Bold (Ctrl+B)" onclick="execCmd('bold')"><strong>B</strong></button>
      <button id="btnItalic" data-tooltip="Italic (Ctrl+I)" onclick="execCmd('italic')"><em>I</em></button>
      <button id="btnUnderline" data-tooltip="Underline (Ctrl+U)" onclick="execCmd('underline')"><u>U</u></button>
      <button id="btnStrike" data-tooltip="Strikethrough" onclick="execCmd('strikeThrough')"><s>S</s></button>
      <div class="toolbar-divider"></div>
      <button id="btnH1" data-tooltip="Heading 1" onclick="execCmd('formatBlock','<h1>')">H1</button>
      <button id="btnH2" data-tooltip="Heading 2" onclick="execCmd('formatBlock','<h2>')">H2</button>
      <button id="btnH3" data-tooltip="Heading 3" onclick="execCmd('formatBlock','<h3>')">H3</button>
      <div class="toolbar-divider"></div>
      <button data-tooltip="Unordered List" onclick="execCmd('insertUnorderedList')">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="4" cy="6" r="1" fill="currentColor"/><circle cx="4" cy="12" r="1" fill="currentColor"/><circle cx="4" cy="18" r="1" fill="currentColor"/></svg>
      </button>
      <button data-tooltip="Ordered List" onclick="execCmd('insertOrderedList')">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><text x="2" y="8" font-size="7" fill="currentColor" stroke="none">1</text><text x="2" y="14" font-size="7" fill="currentColor" stroke="none">2</text><text x="2" y="20" font-size="7" fill="currentColor" stroke="none">3</text></svg>
      </button>
      <button data-tooltip="Blockquote" onclick="execCmd('formatBlock','<blockquote>')">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></svg>
      </button>
      <div class="toolbar-divider"></div>
      <button data-tooltip="Insert Code Block" onclick="insertCodeBlock()">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
      </button>
      <button data-tooltip="Insert Horizontal Rule" onclick="execCmd('insertHorizontalRule')">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="2" y1="12" x2="22" y2="12"/></svg>
      </button>
      <button data-tooltip="Insert Link" onclick="insertLink()">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
      </button>
      <div class="toolbar-divider"></div>
      <button data-tooltip="Find (Ctrl+F)" onclick="toggleFindBar()">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      </button>
      <div class="editor-breadcrumb" id="breadcrumb"></div>
    </div>

    <!-- Find Bar -->
    <div class="find-bar" id="findBar">
      <input type="text" id="findInput" placeholder="Find in note...">
      <span id="findCount" style="font-size:12px;color:var(--text-muted);min-width:40px;">0/0</span>
      <button onclick="findPrev()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="18 15 12 9 6 15"/></svg>
      </button>
      <button onclick="findNext()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
      </button>
      <button onclick="toggleFindBar()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
      </button>
    </div>

    <!-- Editor Content -->
    <div class="editor-content" id="editorContent">
      <div class="welcome-screen" id="welcomeScreen">
        <div class="welcome-icon">
          <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
            <path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
          </svg>
        </div>
        <h1>Welcome to Noteflow</h1>
        <p>A beautiful, distraction-free notes app. Create your first note to get started.</p>
        <div class="welcome-shortcuts">
          <div class="welcome-shortcut"><kbd>Ctrl+N</kbd> New note</div>
          <div class="welcome-shortcut"><kbd>Ctrl+S</kbd> Save note</div>
          <div class="welcome-shortcut"><kbd>Ctrl+F</kbd> Find</div>
          <div class="welcome-shortcut"><kbd>Ctrl+B</kbd> Toggle sidebar</div>
          <div class="welcome-shortcut"><kbd>Ctrl+Shift+T</kbd> New folder</div>
        </div>
      </div>
    </div>

    <!-- Status Bar -->
    <div class="status-bar" id="statusBar">
      <span class="status-item" id="statusWords">0 words</span>
      <span class="status-item" id="statusChars">0 characters</span>
      <span class="status-item" id="statusLines">0 lines</span>
      <span class="status-item" style="margin-left:auto" id="statusSaved">Saved</span>
    </div>
  </div>
</div>

<!-- Context Menu -->
<div class="context-menu" id="contextMenu">
  <div class="context-menu-item" onclick="contextAction('rename')">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
    Rename
  </div>
  <div class="context-menu-item" onclick="contextAction('duplicate')">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
    Duplicate
  </div>
  <div class="context-menu-item" onclick="contextAction('moveToFolder')">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
    Move to folder...
  </div>
  <div class="context-menu-divider"></div>
  <div class="context-menu-item" onclick="contextAction('addTag')">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>
    Add tag
  </div>
  <div class="context-menu-divider"></div>
  <div class="context-menu-item danger" onclick="contextAction('delete')">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
    Delete
    <span class="context-menu-shortcut">Del</span>
  </div>
</div>

<!-- Modal -->
<div class="modal-overlay" id="modalOverlay">
  <div class="modal" id="modal">
    <h3 id="modalTitle">New Folder</h3>
    <input type="text" id="modalInput" placeholder="Enter name...">
    <div class="modal-actions">
      <button class="modal-btn cancel" onclick="closeModal()">Cancel</button>
      <button class="modal-btn primary" id="modalConfirm">Create</button>
    </div>
  </div>
</div>

<!-- Notification -->
<div class="notification" id="notification"></div>

<script>
// ===== STATE =====
let state = {
  notes: [],
  folders: [],
  tags: {},
  activeNoteId: null,
  activeFolder: null,
  activeTag: null,
  sidebarCollapsed: false,
  searchQuery: '',
  contextNoteId: null,
};

let saveTimeout = null;

// ===== DATA =====
function generateId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
}

function getTagColors() {
  return ['tag-red', 'tag-green', 'tag-yellow', 'tag-blue', 'tag-purple', 'tag-orange', 'tag-teal', 'tag-pink'];
}

function loadState() {
  try {
    const saved = localStorage.getItem('noteflow_state');
    if (saved) {
      const parsed = JSON.parse(saved);
      state.notes = parsed.notes || [];
      state.folders = parsed.folders || [];
      state.tags = parsed.tags || {};
      state.activeNoteId = parsed.activeNoteId || null;
    }
  } catch(e) { console.error('Failed to load state:', e); }

  if (state.notes.length === 0) {
    createDefaultNotes();
  }
}

function createDefaultNotes() {
  state.folders = [
    { id: generateId(), name: 'Personal', icon: '📁' },
    { id: generateId(), name: 'Work', icon: '💼' },
    { id: generateId(), name: 'Ideas', icon: '💡' },
  ];

  const note1Id = generateId();
  const note2Id = generateId();
  const note3Id = generateId();

  state.notes = [
    {
      id: note1Id,
      title: 'Welcome to Noteflow',
      content: '<h1>Welcome to Noteflow</h1><p>Your beautiful, distraction-free notes app. Here are some things you can do:</p><ul><li><strong>Create new notes</strong> with Ctrl+N</li><li><strong>Format text</strong> using the toolbar or keyboard shortcuts</li><li><strong>Organize</strong> notes into folders</li><li><strong>Tag your notes</strong> for easy filtering</li><li><strong>Search</strong> across all your notes</li></ul><blockquote>Everything is saved automatically to your browser.</blockquote><hr><p>Try editing this note or create a new one to get started!</p>',
      folderId: state.folders[0]?.id,
      tags: ['welcome', 'getting-started'],
      created: Date.now(),
      modified: Date.now(),
    },
    {
      id: note2Id,
      title: 'Meeting Notes',
      content: '<h2>Project Kickoff Meeting</h2><p><strong>Date:</strong> Today</p><p><strong>Attendees:</strong> Team leads</p><h3>Agenda</h3><ol><li>Project overview</li><li>Timeline discussion</li><li>Role assignments</li><li>Next steps</ol><h3>Action Items</h3><ul><li>Review project requirements</li><li>Set up development environment</li><li>Prepare initial design mockups</ul>',
      folderId: state.folders[1]?.id,
      tags: ['work', 'meetings'],
      created: Date.now() - 86400000,
      modified: Date.now() - 3600000,
    },
    {
      id: note3Id,
      content: '',
      folderId: state.folders[2]?.id,
      tags: ['ideas'],
      created: Date.now() - 172800000,
      modified: Date.now() - 7200000,
    },
  ];

  state.tags = {
    'welcome': { color: getTagColors()[3], notes: [note1Id] },
    'getting-started': { color: getTagColors()[4], notes: [note1Id] },
    'work': { color: getTagColors()[0], notes: [note2Id] },
    'meetings': { color: getTagColors()[5], notes: [note2Id] },
    'ideas': { color: getTagColors()[6], notes: [note1Id, note3Id] },
  };

  saveState();
}

function saveState() {
  try {
    localStorage.setItem('noteflow_state', JSON.stringify({
      notes: state.notes,
      folders: state.folders,
      tags: state.tags,
      activeNoteId: state.activeNoteId,
    }));
  } catch(e) { console.error('Failed to save state:', e); }
}

function saveNote() {
  if (!state.activeNoteId) return;
  const note = state.notes.find(n => n.id === state.activeNoteId);
  if (!note) return;

  const titleEl = document.getElementById('editorTitle');
  const bodyEl = document.getElementById('editorBody');

  note.title = titleEl.value || 'Untitled';
  note.content = bodyEl.innerHTML;
  note.modified = Date.now();

  saveState();
  updateStatusBar();

  document.getElementById('statusSaved').textContent = 'Saved';
  document.getElementById('statusSaved').style.color = 'var(--green)';
  setTimeout(() => {
    document.getElementById('statusSaved').style.color = '';
  }, 2000);
}

function autoSave() {
  clearTimeout(saveTimeout);
  document.getElementById('statusSaved').textContent = 'Saving...';
  saveTimeout = setTimeout(saveNote, 500);
}

// ===== RENDERING =====
function getFilteredNotes() {
  let notes = [...state.notes];

  if (state.activeFolder) {
    notes = notes.filter(n => n.folderId === state.activeFolder);
  }

  if (state.activeTag) {
    const tagNotes = state.tags[state.activeTag]?.notes || [];
    notes = notes.filter(n => tagNotes.includes(n.id));
  }

  if (state.searchQuery) {
    const q = state.searchQuery.toLowerCase();
    notes = notes.filter(n =>
      n.title.toLowerCase().includes(q) ||
      stripHtml(n.content).toLowerCase().includes(q)
    );
  }

  notes.sort((a, b) => b.modified - a.modified);
  return notes;
}

function stripHtml(html) {
  const tmp = document.createElement('div');
  tmp.innerHTML = html;
  return tmp.textContent || tmp.innerText || '';
}

function formatDate(ts) {
  const now = Date.now();
  const diff = now - ts;
  if (diff < 60000) return 'Just now';
  if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
  if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
  if (diff < 604800000) return `${Math.floor(diff / 86400000)}d ago`;
  return new Date(ts).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}

function renderNoteList() {
  const list = document.getElementById('noteList');
  const title = document.getElementById('noteListTitle');
  const notes = getFilteredNotes();

  if (state.activeTag) {
    title.textContent = `#${state.activeTag}`;
  } else if (state.activeFolder) {
    const folder = state.folders.find(f => f.id === state.activeFolder);
    title.textContent = folder ? folder.name : 'Folder';
  } else if (state.searchQuery) {
    title.textContent = `Search: "${state.searchQuery}"`;
  } else {
    title.textContent = 'All Notes';
  }

  if (notes.length === 0) {
    list.innerHTML = `
      <div class="empty-state" style="padding:40px 20px;">
        <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" style="opacity:0.3">
          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>
        </svg>
        <p style="font-size:13px;">No notes yet</p>
        <button class="modal-btn primary" onclick="createNote()" style="margin-top:8px;">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align:middle;margin-right:4px"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
          New Note
        </button>
      </div>
    `;
    return;
  }

  list.innerHTML = notes.map(note => {
    const isActive = note.id === state.activeNoteId;
    const preview = stripHtml(note.content).substring(0, 100);
    const noteTags = note.tags || [];

    return `
      <div class="note-card ${isActive ? 'active' : ''}" data-note-id="${note.id}" onclick="selectNote('${note.id}')">
        <div class="note-card-title">${note.title || 'Untitled'}</div>
        <div class="note-card-preview">${preview || 'Empty note'}</div>
        <div class="note-card-meta">
          <span>${formatDate(note.modified)}</span>
        </div>
        ${noteTags.length ? `<div class="note-card-tags">${noteTags.map(t => `<span class="note-card-tag">#${t}</span>`).join('')}</div>` : ''}
      </div>
    `;
  }).join('');
}

function renderSidebar() {
  // Folders
  const foldersList = document.getElementById('foldersList');
  foldersList.innerHTML = state.folders.map(folder => {
    const count = state.notes.filter(n => n.folderId === folder.id).length;
    const isActive = state.activeFolder === folder.id;
    return `
      <div class="sidebar-item ${isActive ? 'active' : ''}" onclick="selectFolder('${folder.id}')">
        <span class="icon">📁</span>
        <span>${folder.name}</span>
        <span class="count">${count}</span>
      </div>
    `;
  }).join('');

  // Tags
  const tagsList = document.getElementById('tagsList');
  const allTags = Object.keys(state.tags);
  if (allTags.length === 0) {
    tagsList.innerHTML = '<div style="padding:8px;font-size:12px;color:var(--text-muted)">No tags yet</div>';
  } else {
    tagsList.innerHTML = allTags.map(tag => {
      const colorClass = state.tags[tag].color;
      const count = state.tags[tag].notes.length;
      const isActive = state.activeTag === tag;
      return `
        <div class="sidebar-item ${isActive ? 'active' : ''}" onclick="selectTag('${tag}')">
          <span class="icon"><span class="tag ${colorClass}" style="font-size:10px;padding:1px 5px;">#${tag}</span></span>
          <span>${tag}</span>
          <span class="count">${count}</span>
        </div>
      `;
    }).join('');
  }

  // Recent
  const recentList = document.getElementById('recentList');
  const recent = [...state.notes].sort((a, b) => b.modified - a.modified).slice(0, 8);
  recentList.innerHTML = recent.map(note => {
    const isActive = note.id === state.activeNoteId;
    return `
      <div class="sidebar-item ${isActive ? 'active' : ''}" onclick="selectNote('${note.id}')">
        <span class="icon">📄</span>
        <span>${note.title || 'Untitled'}</span>
      </div>
    `;
  }).join('');
}

function updateStatusBar() {
  if (!state.activeNoteId) return;
  const note = state.notes.find(n => n.id === state.activeNoteId);
  if (!note) return;

  const text = stripHtml(note.content);
  const words = text.trim() ? text.trim().split(/\s+/).length : 0;
  const chars = text.length;
  const lines = text.split('\n').length;

  document.getElementById('statusWords').textContent = `${words} word${words !== 1 ? 's' : ''}`;
  document.getElementById('statusChars').textContent = `${chars} character${chars !== 1 ? 's' : ''}`;
  document.getElementById('statusLines').textContent = `${lines} line${lines !== 1 ? 's' : ''}`;
}

function renderBreadcrumb() {
  const bc = document.getElementById('breadcrumb');
  if (!state.activeNoteId) { bc.innerHTML = ''; return; }

  const note = state.notes.find(n => n.id === state.activeNoteId);
  if (!note) { bc.innerHTML = ''; return; }

  let parts = [];
  if (note.folderId) {
    const folder = state.folders.find(f => f.id === note.folderId);
    if (folder) parts.push(folder.name);
  }
  parts.push(note.title || 'Untitled');

  bc.innerHTML = parts.map((p, i) => {
    if (i < parts.length - 1) return `<span>${p}</span><span style="opacity:0.3">/</span>`;
    return `<span style="color:var(--text-primary);font-weight:500">${p}</span>`;
  }).join('');
}

function renderAll() {
  renderNoteList();
  renderSidebar();
  renderBreadcrumb();
}

// ===== NOTE OPERATIONS =====
function createNote(folderId) {
  const note = {
    id: generateId(),
    title: '',
    content: '',
    folderId: folderId || state.activeFolder,
    tags: [],
    created: Date.now(),
    modified: Date.now(),
  };

  state.notes.unshift(note);
  state.activeNoteId = note.id;
  saveState();
  renderAll();
  openNote(note.id);
  notify('New note created');

  setTimeout(() => {
    document.getElementById('editorTitle')?.focus();
  }, 100);
}

function selectNote(id) {
  if (state.activeNoteId === id) return;
  state.activeNoteId = id;
  state.activeTag = null;
  saveState();
  renderAll();
  openNote(id);
}

function openNote(id) {
  const note = state.notes.find(n => n.id === id);
  if (!note) return;

  const welcome = document.getElementById('welcomeScreen');
  if (welcome) welcome.style.display = 'none';

  const editorContent = document.getElementById('editorContent');
  // Remove welcome if present
  const existing = editorContent.querySelector('.welcome-screen');
  if (existing) existing.remove();

  // Remove editor body if exists
  const existingBody = editorContent.querySelector('#editorBody');
  if (existingBody) existingBody.remove();

  // Remove title if exists
  const existingTitle = editorContent.querySelector('#editorTitle');
  if (existingTitle) existingTitle.remove();

  const titleHtml = `<input class="editor-title" id="editorTitle" value="${escapeHtml(note.title)}" placeholder="Untitled" oninput="autoSave()">`;
  const metaHtml = `<div class="editor-meta"><span>Created ${formatDate(note.created)}</span><span>Modified ${formatDate(note.modified)}</span></div>`;
  const bodyHtml = `<div class="editor-body" id="editorBody" contenteditable="true" oninput="autoSave()" onkeydown="handleEditorKey(event)">${note.content}</div>`;

  editorContent.insertAdjacentHTML('beforeend', titleHtml + metaHtml + bodyHtml);

  renderAll();
  updateStatusBar();
  updateToolbarState();
}

function escapeHtml(str) {
  return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function deleteNote(id) {
  state.notes = state.notes.filter(n => n.id !== id);
  if (state.activeNoteId === id) {
    state.activeNoteId = state.notes.length > 0 ? state.notes[0].id : null;
  }
  saveState();
  renderAll();
  if (state.activeNoteId) {
    openNote(state.activeNoteId);
  } else {
    showWelcome();
  }
  notify('Note deleted');
}

function showWelcome() {
  const editorContent = document.getElementById('editorContent');
  editorContent.innerHTML = `
    <div class="welcome-screen" id="welcomeScreen">
      <div class="welcome-icon">
        <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
        </svg>
      </div>
      <h1>Welcome to Noteflow</h1>
      <p>A beautiful, distraction-free notes app. Create your first note to get started.</p>
      <div class="welcome-shortcuts">
        <div class="welcome-shortcut"><kbd>Ctrl+N</kbd> New note</div>
        <div class="welcome-shortcut"><kbd>Ctrl+S</kbd> Save note</div>
        <div class="welcome-shortcut"><kbd>Ctrl+F</kbd> Find</div>
        <div class="welcome-shortcut"><kbd>Ctrl+B</kbd> Toggle sidebar</div>
        <div class="welcome-shortcut"><kbd>Ctrl+Shift+T</kbd> New folder</div>
      </div>
    </div>
  `;
}

// ===== FOLDER OPERATIONS =====
function selectFolder(id) {
  state.activeFolder = state.activeFolder === id ? null : id;
  state.activeTag = null;
  saveState();
  renderAll();
}

function createFolder() {
  showModal('New Folder', 'Enter folder name...', (name) => {
    if (!name.trim()) return;
    state.folders.push({
      id: generateId(),
      name: name.trim(),
      icon: '📁',
    });
    saveState();
    renderAll();
    notify(`Folder "${name.trim()}" created`);
  });
}

function deleteFolder(id) {
  state.folders = state.folders.filter(f => f.id !== id);
  state.notes.forEach(n => { if (n.folderId === id) n.folderId = null; });
  if (state.activeFolder === id) state.activeFolder = null;
  saveState();
  renderAll();
  notify('Folder deleted');
}

// ===== TAG OPERATIONS =====
function selectTag(tag) {
  state.activeTag = state.activeTag === tag ? null : tag;
  state.activeFolder = null;
  saveState();
  renderAll();
}

function addTagToNote(noteId) {
  const note = state.notes.find(n => n.id === noteId);
  if (!note) return;

  showModal('Add Tag', 'Enter tag name (comma separated)...', (value) => {
    if (!value.trim()) return;
    const newTags = value.split(',').map(t => t.trim().toLowerCase()).filter(Boolean);
    const colorMap = getTagColors();

    newTags.forEach(tag => {
      if (!note.tags.includes(tag)) {
        note.tags.push(tag);
      }
      if (!state.tags[tag]) {
        state.tags[tag] = {
          color: colorMap[Object.keys(state.tags).length % colorMap.length],
          notes: [],
        };
      }
      if (!state.tags[tag].notes.includes(noteId)) {
        state.tags[tag].notes.push(noteId);
      }
    });

    saveState();
    renderAll();
    if (state.activeNoteId === noteId) openNote(noteId);
    notify(`Tag${newTags.length > 1 ? 's' : ''} added`);
  });
}

// ===== CONTEXT MENU =====
function showContextMenu(e, noteId) {
  e.preventDefault();
  state.contextNoteId = noteId;
  const menu = document.getElementById('contextMenu');
  menu.classList.add('visible');

  let x = e.clientX;
  let y = e.clientY;

  menu.style.left = x + 'px';
  menu.style.top = y + 'px';

  requestAnimationFrame(() => {
    const rect = menu.getBoundingClientRect();
    if (rect.right > window.innerWidth) menu.style.left = (x - rect.width) + 'px';
    if (rect.bottom > window.innerHeight) menu.style.top = (y - rect.height) + 'px';
  });
}

function hideContextMenu() {
  document.getElementById('contextMenu').classList.remove('visible');
}

function contextAction(action) {
  hideContextMenu();
  const noteId = state.contextNoteId;
  const note = state.notes.find(n => n.id === noteId);
  if (!note) return;

  switch(action) {
    case 'rename':
      showModal('Rename Note', 'Enter new name...', (name) => {
        if (name.trim()) {
          note.title = name.trim();
          saveState();
          renderAll();
          if (state.activeNoteId === noteId) openNote(noteId);
        }
      });
      break;
    case 'duplicate':
      const dup = {
        ...note,
        id: generateId(),
        title: note.title + ' (copy)',
        created: Date.now(),
        modified: Date.now(),
      };
      state.notes.unshift(dup);
      state.activeNoteId = dup.id;
      saveState();
      renderAll();
      openNote(dup.id);
      notify('Note duplicated');
      break;
    case 'moveToFolder':
      showModal('Move to Folder', '', (value) => {
        if (state.folders.length === 0) {
          notify('Create a folder first');
          return;
        }
        if (value.trim()) {
          const folder = state.folders.find(f => f.name.toLowerCase() === value.trim().toLowerCase());
          if (folder) {
            note.folderId = folder.id;
            saveState();
            renderAll();
            if (state.activeNoteId === noteId) openNote(noteId);
            notify(`Moved to ${folder.name}`);
          } else {
            notify('Folder not found');
          }
        }
      });
      break;
    case 'addTag':
      addTagToNote(noteId);
      break;
    case 'delete':
      deleteNote(noteId);
      break;
  }
}

// ===== EDITOR COMMANDS =====
function execCmd(command, value) {
  document.getElementById('editorBody')?.focus();
  document.execCommand(command, false, value || null);
  autoSave();
}

function insertCodeBlock() {
  const body = document.getElementById('editorBody');
  if (!body) return;
  body.focus();
  document.execCommand('insertHTML', false, '<pre><code>// Your code here\n</code></pre><p></p>');
  autoSave();
}

function insertLink() {
  const url = prompt('Enter URL:');
  if (url) {
    document.execCommand('createLink', false, url);
    autoSave();
  }
}

function handleEditorKey(e) {
  if (e.key === 'Tab') {
    e.preventDefault();
    document.execCommand('insertHTML', false, '&nbsp;&nbsp;&nbsp;&nbsp;');
  }
}

function updateToolbarState() {
  // Update button states based on current selection
  const commands = ['bold', 'italic', 'underline', 'strikeThrough'];
  commands.forEach(cmd => {
    const btn = document.getElementById('btn' + cmd.charAt(0).toUpperCase() + cmd.slice(1));
    if (btn) {
      btn.classList.toggle('active', document.queryCommandState(cmd));
    }
  });
}

// ===== FIND BAR =====
let findIndex = -1;
let findMatches = [];

function toggleFindBar() {
  const bar = document.getElementById('findBar');
  bar.classList.toggle('visible');
  if (bar.classList.contains('visible')) {
    document.getElementById('findInput').focus();
  }
}

function findInNote(query) {
  if (!query) { findMatches = []; findIndex = -1; updateFindCount(); return; }

  const body = document.getElementById('editorBody');
  if (!body) return;

  // Remove old highlights
  document.querySelectorAll('.find-highlight').forEach(el => {
    el.replaceWith(document.createTextNode(el.textContent));
  });
  document.body.normalize();

  const text = body.textContent;
  const lowerText = text.toLowerCase();
  const lowerQuery = query.toLowerCase();
  findMatches = [];

  let idx = 0;
  while ((idx = lowerText.indexOf(lowerQuery, idx)) !== -1) {
    findMatches.push(idx);
    idx += query.length;
  }

  findIndex = findMatches.length > 0 ? 0 : -1;
  updateFindCount();

  if (findMatches.length > 0) {
    highlightMatch(findIndex);
  }
}

function highlightMatch(index) {
  if (index < 0 || index >= findMatches.length) return;

  const body = document.getElementById('editorBody');
  if (!body) return;

  const matchPos = findMatches[index];
  const query = document.getElementById('findInput').value;
  if (!query) return;

  // Use TreeWalker to find the text node
  const walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null, false);
  let textNode = null;
  let charCount = 0;

  while (walker.nextNode()) {
    const node = walker.currentNode;
    const nodeLen = node.textContent.length;

    if (matchPos >= charCount && matchPos < charCount + nodeLen) {
      textNode = node;
      break;
    }
    charCount += nodeLen;
  }

  if (!textNode) return;

  const offset = matchPos - charCount;

  // Remove old highlights
  document.querySelectorAll('.find-highlight').forEach(el => {
    el.replaceWith(document.createTextNode(el.textContent));
  });
  document.body.normalize();

  // Re-find and highlight
  const walker2 = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null, false);
  let c = 0;
  while (walker2.nextNode()) {
    const n = walker2.currentNode;
    if (c === charCount) {
      const range = document.createRange();
      range.setStart(n, offset);
      range.setEnd(n, offset + query.length);
      const span = document.createElement('span');
      span.className = 'find-highlight';
      span.style.background = 'rgba(137, 180, 250, 0.3)';
      span.style.borderRadius = '2px';
      range.surroundContents(span);
      break;
    }
    c += n.textContent.length;
  }

  // Scroll into view
  const highlight = document.querySelector('.find-highlight');
  if (highlight) highlight.scrollIntoView({ block: 'center', behavior: 'smooth' });

  updateFindCount();
}

function findNext() {
  if (findMatches.length === 0) return;
  findIndex = (findIndex + 1) % findMatches.length;
  highlightMatch(findIndex);
}

function findPrev() {
  if (findMatches.length === 0) return;
  findIndex = (findIndex - 1 + findMatches.length) % findMatches.length;
  highlightMatch(findIndex);
}

function updateFindCount() {
  const countEl = document.getElementById('findCount');
  if (findMatches.length === 0) {
    countEl.textContent = '0/0';
  } else {
    countEl.textContent = `${findIndex + 1}/${findMatches.length}`;
  }
}

// ===== MODAL =====
let modalCallback = null;

function showModal(title, placeholder, callback) {
  modalCallback = callback;
  document.getElementById('modalTitle').textContent = title;
  const input = document.getElementById('modalInput');
  input.value = '';
  input.placeholder = placeholder;
  document.getElementById('modalOverlay').classList.add('visible');
  setTimeout(() => input.focus(), 100);
}

function closeModal() {
  document.getElementById('modalOverlay').classList.remove('visible');
  modalCallback = null;
}

function confirmModal() {
  const value = document.getElementById('modalInput').value;
  if (modalCallback) modalCallback(value);
  closeModal();
}

// ===== NOTIFICATIONS =====
let notifyTimeout = null;

function notify(message) {
  const el = document.getElementById('notification');
  el.textContent = message;
  el.classList.add('visible');
  clearTimeout(notifyTimeout);
  notifyTimeout = setTimeout(() => el.classList.remove('visible'), 2500);
}

// ===== SIDEBAR TOGGLE =====
function toggleSidebar() {
  state.sidebarCollapsed = !state.sidebarCollapsed;
  document.getElementById('sidebar').classList.toggle('collapsed', state.sidebarCollapsed);
}

// ===== RESIZE HANDLE =====
function initResize() {
  const handle = document.getElementById('resizeHandle');
  const panel = document.getElementById('noteListPanel');
  let startX, startWidth;

  handle.addEventListener('mousedown', (e) => {
    startX = e.clientX;
    startWidth = panel.offsetWidth;
    handle.classList.add('active');
    document.addEventListener('mousemove', onResize);
    document.addEventListener('mouseup', stopResize);
    e.preventDefault();
  });

  function onResize(e) {
    const diff = e.clientX - startX;
    const newWidth = Math.max(180, Math.min(500, startWidth + diff));
    panel.style.width = newWidth + 'px';
  }

  function stopResize() {
    handle.classList.remove('active');
    document.removeEventListener('mousemove', onResize);
    document.removeEventListener('mouseup', stopResize);
  }
}

// ===== KEYBOARD SHORTCUTS =====
function initKeyboard() {
  document.addEventListener('keydown', (e) => {
    // Ctrl+N: New note
    if (e.ctrlKey || e.metaKey) {
      if (e.key === 'n' || e.key === 'N') {
        e.preventDefault();
        createNote();
      }
      if (e.key === 's' || e.key === 'S') {
        e.preventDefault();
        saveNote();
        notify('Note saved');
      }
      if (e.key === 'b' || e.key === 'B') {
        if (e.shiftKey) return; // Let browser handle bold
        e.preventDefault();
        toggleSidebar();
      }
      if (e.key === 'f' || e.key === 'F') {
        e.preventDefault();
        toggleFindBar();
      }
      if (e.key === 't' || e.key === 'T') {
        if (e.shiftKey) {
          e.preventDefault();
          createFolder();
        }
      }
    }

    // Escape
    if (e.key === 'Escape') {
      const findBar = document.getElementById('findBar');
      if (findBar.classList.contains('visible')) {
        toggleFindBar();
      }
      hideContextMenu();
      closeModal();
    }

    // Delete note
    if (e.key === 'Delete' && state.activeNoteId) {
      const active = document.activeElement;
      if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) return;
      deleteNote(state.activeNoteId);
    }
  });
}

// ===== EVENT LISTENERS =====
function initEvents() {
  // New note button
  document.getElementById('btnNewNote').addEventListener('click', () => createNote());

  // Collapse list button
  document.getElementById('btnCollapseList').addEventListener('click', () => {
    const panel = document.getElementById('noteListPanel');
    panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
  });

  // Sidebar toggle
  document.getElementById('btnToggleSidebar').addEventListener('click', toggleSidebar);

  // Sidebar search
  document.getElementById('sidebarSearch').addEventListener('input', (e) => {
    state.searchQuery = e.target.value;
    renderAll();
  });

  // Folder section toggle
  document.querySelectorAll('.sidebar-section-title').forEach(title => {
    title.addEventListener('click', () => {
      const listId = title.getAttribute('data-toggle') + 'List';
      const list = document.getElementById(listId);
      const chevron = title.querySelector('.chevron');
      list.classList.toggle('expanded');
      chevron.classList.toggle('collapsed');
    });
  });

  // Context menu
  document.addEventListener('contextmenu', (e) => {
    const card = e.target.closest('.note-card');
    if (card) {
      showContextMenu(e, card.dataset.noteId);
    } else {
      hideContextMenu();
    }
  });

  document.addEventListener('click', (e) => {
    if (!e.target.closest('.context-menu')) {
      hideContextMenu();
    }
  });

  // Modal
  document.getElementById('modalConfirm').addEventListener('click', confirmModal);
  document.getElementById('modalInput').addEventListener('keydown', (e) => {
    if (e.key === 'Enter') confirmModal();
    if (e.key === 'Escape') closeModal();
  });
  document.getElementById('modalOverlay').addEventListener('click', (e) => {
    if (e.target === e.currentTarget) closeModal();
  });

  // Find bar
  document.getElementById('findInput').addEventListener('input', (e) => {
    findInNote(e.target.value);
  });
  document.getElementById('findInput').addEventListener('keydown', (e) => {
    if (e.key === 'Enter') {
      e.shiftKey ? findPrev() : findNext();
    }
    if (e.key === 'Escape') toggleFindBar();
  });

  // Editor focus
  document.getElementById('editorContent').addEventListener('click', (e) => {
    const body = document.getElementById('editorBody');
    if (body && !e.target.closest('.editor-title')) {
      body.focus();
    }
  });

  // Right-click on notes for context menu
  document.addEventListener('mousedown', (e) => {
    const card = e.target.closest('.note-card');
    if (card && e.button === 2) {
      showContextMenu(e, card.dataset.noteId);
    }
  });

  // Init
  initResize();
  initKeyboard();
}

// ===== INIT =====
function init() {
  loadState();
  renderAll();

  if (state.activeNoteId) {
    const note = state.notes.find(n => n.id === state.activeNoteId);
    if (note) {
      openNote(state.activeNoteId);
    } else {
      state.activeNoteId = null;
      showWelcome();
    }
  } else {
    showWelcome();
  }

  initEvents();
}

init();
</script>
</body>
</html>
<!-- agent-meta {"model":"qwen/qwen3.6-35b-a3b","provider":"lmstudio","persona":"full","sessionId":"ca1ebfad-5bac-428b-b659-4b8bd4fb5e5d","tokensIn":82288,"tokensOut":20788,"tokensTotal":103076,"turns":4,"toolCalls":3,"failedToolCalls":0,"timestamp":"2026-07-21T01:12:20.444Z"} -->