{"version":3,"file":"Annotator-BOtagLkA.cjs","sources":["../app/components/annotator/database.ts","../app/components/annotator/store.ts","../app/components/annotator/types.ts","../app/components/annotator/engine.ts","../app/components/annotator/Annotator.tsx"],"sourcesContent":["/**\n * Modern IndexedDB wrapper for annotation persistence\n */\n\"use client\";\n\nimport type { Annotation } from \"./types\";\n\nconst DB_NAME = \"AnnotationDB\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"annotations\";\n\nclass AnnotationDatabase {\n  private dbPromise: Promise<IDBDatabase> | null = null;\n\n  private async getDB(): Promise<IDBDatabase> {\n    if (this.dbPromise) return this.dbPromise;\n\n    this.dbPromise = new Promise((resolve, reject) => {\n      const request = indexedDB.open(DB_NAME, DB_VERSION);\n\n      request.onerror = () => reject(request.error);\n      request.onsuccess = () => resolve(request.result);\n\n      request.onupgradeneeded = (event) => {\n        const db = (event.target as IDBOpenDBRequest).result;\n\n        if (!db.objectStoreNames.contains(STORE_NAME)) {\n          const store = db.createObjectStore(STORE_NAME, { keyPath: \"id\" });\n          store.createIndex(\"pageUrl\", \"pageUrl\", { unique: false });\n          store.createIndex(\"created\", \"created\", { unique: false });\n        }\n      };\n    });\n\n    return this.dbPromise;\n  }\n\n  async saveAnnotation(annotation: Annotation): Promise<void> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readwrite\");\n      const store = tx.objectStore(STORE_NAME);\n      const request = store.put(annotation);\n\n      request.onsuccess = () => resolve();\n      request.onerror = () => reject(request.error);\n    });\n  }\n\n  async getAnnotation(id: string): Promise<Annotation | undefined> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readonly\");\n      const store = tx.objectStore(STORE_NAME);\n      const request = store.get(id);\n\n      request.onsuccess = () => resolve(request.result);\n      request.onerror = () => reject(request.error);\n    });\n  }\n\n  async getAnnotationsByPage(pageUrl: string): Promise<Annotation[]> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readonly\");\n      const store = tx.objectStore(STORE_NAME);\n      const index = store.index(\"pageUrl\");\n      const request = index.getAll(pageUrl);\n\n      request.onsuccess = () => resolve(request.result || []);\n      request.onerror = () => reject(request.error);\n    });\n  }\n\n  async getAllAnnotations(): Promise<Annotation[]> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readonly\");\n      const store = tx.objectStore(STORE_NAME);\n      const request = store.getAll();\n\n      request.onsuccess = () => resolve(request.result || []);\n      request.onerror = () => reject(request.error);\n    });\n  }\n\n  async deleteAnnotation(id: string): Promise<void> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readwrite\");\n      const store = tx.objectStore(STORE_NAME);\n      const request = store.delete(id);\n\n      request.onsuccess = () => resolve();\n      request.onerror = () => reject(request.error);\n    });\n  }\n\n  async clearAll(): Promise<void> {\n    const db = await this.getDB();\n    return new Promise((resolve, reject) => {\n      const tx = db.transaction(STORE_NAME, \"readwrite\");\n      const store = tx.objectStore(STORE_NAME);\n      const request = store.clear();\n\n      request.onsuccess = () => resolve();\n      request.onerror = () => reject(request.error);\n    });\n  }\n}\n\nexport const db = new AnnotationDatabase();\n","/**\n * Annotation State Management using Zustand\n */\n\"use client\";\n\nimport { create } from \"zustand\";\nimport type { Annotation, AnnotationStyle, AnnotationColor } from \"./types\";\nimport { db } from \"./database\";\n\ninterface AnnotationState {\n  annotations: Map<string, Annotation>;\n  selectedId: string | null;\n  isEnabled: boolean;\n  activeStyle: AnnotationStyle;\n  activeColor: AnnotationColor;\n\n  // Actions\n  addAnnotation: (annotation: Annotation) => Promise<void>;\n  removeAnnotation: (id: string) => Promise<void>;\n  updateAnnotation: (id: string, updates: Partial<Annotation>) => Promise<void>;\n  selectAnnotation: (id: string | null) => void;\n  setEnabled: (enabled: boolean) => void;\n  setActiveStyle: (style: AnnotationStyle) => void;\n  setActiveColor: (color: AnnotationColor) => void;\n  loadAnnotations: (pageUrl: string) => Promise<void>;\n  clearAll: () => Promise<void>;\n}\n\nexport const useAnnotationStore = create<AnnotationState>((set, get) => ({\n  annotations: new Map(),\n  selectedId: null,\n  isEnabled: false,\n  activeStyle: \"highlight\",\n  activeColor: \"yellow\",\n\n  addAnnotation: async (annotation) => {\n    await db.saveAnnotation(annotation);\n    set((state) => ({\n      annotations: new Map(state.annotations).set(annotation.id, annotation),\n    }));\n  },\n\n  removeAnnotation: async (id) => {\n    await db.deleteAnnotation(id);\n    set((state) => {\n      const newMap = new Map(state.annotations);\n      newMap.delete(id);\n      return {\n        annotations: newMap,\n        selectedId: state.selectedId === id ? null : state.selectedId,\n      };\n    });\n  },\n\n  updateAnnotation: async (id, updates) => {\n    const annotation = get().annotations.get(id);\n    if (!annotation) return;\n\n    const updated = { ...annotation, ...updates, updated: Date.now() };\n    await db.saveAnnotation(updated);\n    set((state) => ({\n      annotations: new Map(state.annotations).set(id, updated),\n    }));\n  },\n\n  selectAnnotation: (id) => {\n    set({ selectedId: id });\n  },\n\n  setEnabled: (enabled) => {\n    set({ isEnabled: enabled });\n  },\n\n  setActiveStyle: (style) => {\n    set({ activeStyle: style });\n  },\n\n  setActiveColor: (color) => {\n    set({ activeColor: color });\n  },\n\n  loadAnnotations: async (pageUrl) => {\n    const annotations = await db.getAnnotationsByPage(pageUrl);\n    const annotationMap = new Map<string, Annotation>(\n      annotations.map((a: Annotation) => [a.id, a])\n    );\n    set({ annotations: annotationMap });\n  },\n\n  clearAll: async () => {\n    const annotations = get().annotations;\n    for (const id of annotations.keys()) {\n      await db.deleteAnnotation(id);\n    }\n    set({ annotations: new Map(), selectedId: null });\n  },\n}));\n","/**\n * Modern Annotation System Types\n * Following W3C Web Annotation Data Model principles\n */\n\nexport type AnnotationStyle = \"highlight\" | \"underline\";\n\nexport type AnnotationColor = \"yellow\" | \"green\" | \"blue\" | \"pink\";\n\n/**\n * Serialized range using CSS selector + text position\n * More stable than DOM paths across page changes\n */\nexport interface AnnotationTarget {\n  /** CSS selector for the container element */\n  selector: string;\n  /** Text content for verification */\n  quote: string;\n  /** Character offset from container start */\n  startOffset: number;\n  /** Character offset from container end */\n  endOffset: number;\n}\n\n/**\n * Core annotation data structure\n */\nexport interface Annotation {\n  id: string;\n  style: AnnotationStyle;\n  color: AnnotationColor;\n  target: AnnotationTarget;\n  note?: string;\n  tags?: string[];\n  created: number;\n  updated: number;\n  /** Page URL where annotation exists */\n  pageUrl: string;\n}\n\n/**\n * Annotation with DOM references (runtime only, not serialized)\n */\nexport interface AnnotationWithRefs extends Annotation {\n  /** DOM elements that represent this annotation */\n  elements: HTMLElement[];\n}\n\n/**\n * Color configuration\n */\nexport interface ColorConfig {\n  name: string;\n  highlight: string;\n  underline: string;\n  strikethrough: string;\n}\n\nexport const COLORS: Record<AnnotationColor, ColorConfig> = {\n  yellow: {\n    name: \"Yellow\",\n    highlight: \"rgba(255, 235, 59, 0.4)\",\n    underline: \"#fbc02d\",\n    strikethrough: \"#fbc02d\",\n  },\n  green: {\n    name: \"Green\",\n    highlight: \"rgba(102, 187, 106, 0.4)\",\n    underline: \"#43a047\",\n    strikethrough: \"#43a047\",\n  },\n  blue: {\n    name: \"Blue\",\n    highlight: \"rgba(66, 165, 245, 0.4)\",\n    underline: \"#1e88e5\",\n    strikethrough: \"#1e88e5\",\n  },\n  pink: {\n    name: \"Pink\",\n    highlight: \"rgba(240, 98, 146, 0.4)\",\n    underline: \"#e91e63\",\n    strikethrough: \"#e91e63\",\n  },\n};\n","/**\n * Core Annotation Engine\n * Handles text selection, range serialization, and annotation rendering\n */\n\nimport type {\n  Annotation,\n  AnnotationTarget,\n  AnnotationColor,\n  AnnotationStyle,\n} from \"./types\";\nimport { COLORS } from \"./types\";\n\nconst ANNOTATION_CLASS = \"annotation-mark\";\nconst ANNOTATION_ATTR = \"data-annotation-id\";\n\nexport class AnnotationEngine {\n  private root: HTMLElement;\n  private rendered: Map<string, HTMLElement[]> = new Map();\n\n  constructor(root: HTMLElement = document.body) {\n    this.root = root;\n  }\n\n  /**\n   * Create annotation from current text selection\n   */\n  createFromSelection(): AnnotationTarget | null {\n    const selection = window.getSelection();\n    if (!selection || selection.isCollapsed) return null;\n\n    const range = selection.getRangeAt(0);\n    const quote = range.toString().trim();\n\n    // Validate selection\n    if (!quote) return null;\n\n    // Prevent excessively large selections (max 500 characters)\n    if (quote.length > 500) {\n      console.warn(\"Selection too large (max 500 characters)\");\n      alert(\"Please select a shorter text (max 500 characters)\");\n      return null;\n    }\n\n    // Check if selection is inside an existing annotation (prevent nesting)\n    const node = range.commonAncestorContainer;\n    let checkNode: HTMLElement | null =\n      node.nodeType === Node.TEXT_NODE\n        ? node.parentElement\n        : (node as HTMLElement);\n\n    while (checkNode && checkNode !== document.body) {\n      if (checkNode.classList?.contains(ANNOTATION_CLASS)) {\n        console.warn(\"Cannot annotate inside an existing annotation\");\n        alert(\n          \"Cannot create annotation inside another annotation. Please select text outside.\"\n        );\n        return null;\n      }\n      checkNode = checkNode.parentElement;\n    }\n\n    const container = this.findContainer(range.commonAncestorContainer);\n    if (!container) {\n      console.warn(\"Could not find suitable container for selection\");\n      return null;\n    }\n\n    // Get selector for container\n    const selector = this.generateSelector(container);\n    if (!selector || selector.trim() === \"\") {\n      console.warn(\"Generated empty selector, cannot create annotation\");\n      return null;\n    }\n\n    // Calculate offsets relative to container\n    const { startOffset, endOffset } = this.getOffsets(range, container);\n\n    console.log(\"✓ Created annotation target:\", {\n      selector,\n      quote: quote.substring(0, 50) + (quote.length > 50 ? \"...\" : \"\"),\n      startOffset,\n      endOffset,\n    });\n\n    return {\n      selector,\n      quote,\n      startOffset,\n      endOffset,\n    };\n  }\n\n  /**\n   * Render annotation on page\n   */\n  render(annotation: Annotation): boolean {\n    try {\n      // Validate selector\n      if (\n        !annotation.target.selector ||\n        annotation.target.selector.trim() === \"\"\n      ) {\n        console.warn(\"Empty selector, skipping annotation:\", annotation.id);\n        return false;\n      }\n\n      const container = document.querySelector(\n        annotation.target.selector\n      ) as HTMLElement;\n      if (!container) {\n        console.warn(\n          `Container not found for selector: ${annotation.target.selector}`,\n          annotation\n        );\n        return false;\n      }\n\n      const range = this.createRange(annotation.target, container);\n      if (!range) {\n        console.warn(\"Failed to create range for annotation:\", annotation.id);\n        return false;\n      }\n\n      const elements = this.applyHighlight(range, annotation);\n      if (elements.length > 0) {\n        this.rendered.set(annotation.id, elements);\n        console.log(\n          `✓ Rendered annotation ${annotation.id} (${elements.length} elements)`\n        );\n        return true;\n      } else {\n        console.warn(\"No elements created for annotation:\", annotation.id);\n      }\n    } catch (error) {\n      console.error(\"Failed to render annotation:\", annotation.id, error);\n    }\n    return false;\n  }\n\n  /**\n   * Remove annotation from page\n   */\n  remove(annotationId: string): void {\n    const elements = this.rendered.get(annotationId);\n    if (!elements) return;\n\n    elements.forEach((el) => {\n      const parent = el.parentNode;\n      if (!parent) return;\n\n      // Move children out of wrapper\n      while (el.firstChild) {\n        parent.insertBefore(el.firstChild, el);\n      }\n      parent.removeChild(el);\n    });\n\n    // Normalize to merge adjacent text nodes\n    elements.forEach((el) => el.parentNode?.normalize());\n\n    this.rendered.delete(annotationId);\n  }\n\n  /**\n   * Remove all annotations\n   */\n  removeAll(): void {\n    for (const id of this.rendered.keys()) {\n      this.remove(id);\n    }\n    this.rendered.clear();\n  }\n\n  /**\n   * Clean up any malformed annotation marks (e.g., from previous versions)\n   */\n  cleanupMalformed(): void {\n    // Find all annotation marks\n    const marks = document.querySelectorAll(`.${ANNOTATION_CLASS}`);\n\n    marks.forEach((mark) => {\n      // Check if mark contains block-level elements (invalid structure)\n      const hasBlockElements = mark.querySelector(\n        \"div, p, h1, h2, h3, h4, h5, h6, section, article, header, footer, main, nav, aside\"\n      );\n\n      if (hasBlockElements) {\n        // Remove this malformed mark\n        const parent = mark.parentNode;\n        if (parent) {\n          while (mark.firstChild) {\n            parent.insertBefore(mark.firstChild, mark);\n          }\n          parent.removeChild(mark);\n          parent.normalize();\n        }\n      }\n    });\n  }\n\n  /**\n   * Find suitable container element for annotation\n   */\n  private findContainer(node: Node): HTMLElement | null {\n    let current =\n      node.nodeType === Node.TEXT_NODE\n        ? node.parentElement\n        : (node as HTMLElement);\n\n    // Traverse up to find a good container\n    while (current && current !== this.root) {\n      // Prefer elements with IDs or specific attributes\n      if (current.id || current.hasAttribute(\"data-annotatable\")) {\n        return current;\n      }\n      // Also accept semantic HTML elements as containers\n      const tagName = current.tagName?.toLowerCase();\n      if (\n        tagName === \"p\" ||\n        tagName === \"div\" ||\n        tagName === \"section\" ||\n        tagName === \"article\" ||\n        tagName === \"main\" ||\n        tagName === \"li\" ||\n        tagName === \"td\" ||\n        tagName === \"th\"\n      ) {\n        return current;\n      }\n      current = current.parentElement;\n    }\n\n    // Fallback to body if nothing better found\n    return document.body;\n  }\n\n  /**\n   * Generate CSS selector for element\n   */\n  private generateSelector(element: HTMLElement): string {\n    // If element has an ID, use it (most reliable)\n    if (element.id) {\n      return `#${CSS.escape(element.id)}`;\n    }\n\n    // If element is body, return body selector\n    if (element === document.body) {\n      return \"body\";\n    }\n\n    const path: string[] = [];\n    let current: HTMLElement | null = element;\n    let maxDepth = 10; // Prevent infinite loops\n\n    while (current && current !== document.body && maxDepth > 0) {\n      let selector = current.tagName.toLowerCase();\n\n      // Add classes (excluding annotation-related classes)\n      if (current.className) {\n        const classes = Array.from(current.classList)\n          .filter(\n            (c) => !c.startsWith(\"annotation-\") && !c.startsWith(\"highlight-\")\n          )\n          .slice(0, 3); // Limit to 3 classes for brevity\n        if (classes.length > 0) {\n          selector += \".\" + classes.map((c) => CSS.escape(c)).join(\".\");\n        }\n      }\n\n      // Add nth-child for specificity\n      const parent = current.parentElement;\n      if (parent) {\n        const siblings = Array.from(parent.children).filter(\n          (s) => s.tagName === current!.tagName\n        );\n        if (siblings.length > 1) {\n          const index = siblings.indexOf(current) + 1;\n          selector += `:nth-of-type(${index})`;\n        }\n      }\n\n      path.unshift(selector);\n      current = current.parentElement;\n      maxDepth--;\n    }\n\n    return path.length > 0 ? path.join(\" > \") : \"body\";\n  }\n\n  /**\n   * Get character offsets relative to container\n   */\n  private getOffsets(\n    range: Range,\n    container: HTMLElement\n  ): { startOffset: number; endOffset: number } {\n    const beforeRange = document.createRange();\n    beforeRange.setStart(container, 0);\n    beforeRange.setEnd(range.startContainer, range.startOffset);\n    const startOffset = beforeRange.toString().length;\n    const endOffset = startOffset + range.toString().length;\n\n    return { startOffset, endOffset };\n  }\n\n  /**\n   * Create Range from serialized target\n   */\n  private createRange(\n    target: AnnotationTarget,\n    container: HTMLElement\n  ): Range | null {\n    const textContent = container.textContent || \"\";\n\n    // Verify quote exists\n    const quoteIndex = textContent.indexOf(target.quote);\n    if (quoteIndex === -1) {\n      console.warn(\"Quote not found in container\");\n      return null;\n    }\n\n    try {\n      const range = document.createRange();\n      const treeWalker = document.createTreeWalker(\n        container,\n        NodeFilter.SHOW_TEXT\n      );\n\n      let currentOffset = 0;\n      let startNode: Node | null = null;\n      let startNodeOffset = 0;\n      let endNode: Node | null = null;\n      let endNodeOffset = 0;\n\n      while (treeWalker.nextNode()) {\n        const node = treeWalker.currentNode;\n        const nodeLength = node.textContent?.length || 0;\n        const nextOffset = currentOffset + nodeLength;\n\n        if (!startNode && nextOffset >= target.startOffset) {\n          startNode = node;\n          startNodeOffset = target.startOffset - currentOffset;\n        }\n\n        if (nextOffset >= target.endOffset) {\n          endNode = node;\n          endNodeOffset = target.endOffset - currentOffset;\n          break;\n        }\n\n        currentOffset = nextOffset;\n      }\n\n      if (!startNode || !endNode) {\n        return null;\n      }\n\n      range.setStart(startNode, Math.max(0, startNodeOffset));\n      range.setEnd(endNode, Math.max(0, endNodeOffset));\n\n      return range;\n    } catch (error) {\n      console.error(\"Failed to create range:\", error);\n      return null;\n    }\n  }\n\n  /**\n   * Apply visual highlight to range\n   */\n  private applyHighlight(range: Range, annotation: Annotation): HTMLElement[] {\n    const elements: HTMLElement[] = [];\n    const { style, color, id } = annotation;\n    const colorConfig = COLORS[color];\n\n    try {\n      // Get all text nodes in the range\n      const textNodes = this.getTextNodesInRange(range);\n\n      if (textNodes.length === 0) {\n        console.warn(\"No text nodes found in range\");\n        return elements;\n      }\n\n      // Process nodes in reverse order to avoid offset issues from DOM modifications\n      for (let i = textNodes.length - 1; i >= 0; i--) {\n        const { node, startOffset, endOffset } = textNodes[i];\n\n        try {\n          // Validate node is still in document\n          if (!node.parentNode || !document.contains(node)) {\n            continue;\n          }\n\n          // Split text node if needed\n          const textLength = node.textContent?.length || 0;\n          let targetNode: Text = node;\n\n          // Split at end first (to preserve offsets)\n          if (endOffset < textLength) {\n            targetNode.splitText(endOffset);\n          }\n\n          // Split at start\n          if (startOffset > 0) {\n            targetNode = targetNode.splitText(startOffset) as Text;\n          }\n\n          // Validate we have content to wrap\n          if (!targetNode.textContent || targetNode.textContent.length === 0) {\n            continue;\n          }\n\n          // Create wrapper for this text node\n          const wrapper = document.createElement(\"mark\");\n          wrapper.className = ANNOTATION_CLASS;\n          wrapper.setAttribute(ANNOTATION_ATTR, id);\n\n          // Apply styles\n          this.applyStyle(wrapper, style, color, colorConfig);\n\n          // Wrap the text node\n          const parent = targetNode.parentNode;\n          if (parent) {\n            parent.insertBefore(wrapper, targetNode);\n            wrapper.appendChild(targetNode);\n            elements.push(wrapper);\n          }\n        } catch (err) {\n          console.warn(\"Failed to wrap text node:\", err);\n        }\n      }\n    } catch (error) {\n      console.error(\"Failed to apply highlight:\", error);\n    }\n\n    return elements;\n  }\n\n  /**\n   * Get all text nodes within a range with their offsets\n   */\n  private getTextNodesInRange(range: Range): Array<{\n    node: Text;\n    startOffset: number;\n    endOffset: number;\n  }> {\n    const textNodes: Array<{\n      node: Text;\n      startOffset: number;\n      endOffset: number;\n    }> = [];\n\n    // Handle simple case: range starts and ends in the same text node\n    if (\n      range.startContainer === range.endContainer &&\n      range.startContainer.nodeType === Node.TEXT_NODE\n    ) {\n      textNodes.push({\n        node: range.startContainer as Text,\n        startOffset: range.startOffset,\n        endOffset: range.endOffset,\n      });\n      console.log(`Found ${textNodes.length} text node(s) (simple case)`);\n      return textNodes;\n    }\n\n    // Complex case: range spans multiple nodes\n    const treeWalker = document.createTreeWalker(\n      range.commonAncestorContainer,\n      NodeFilter.SHOW_TEXT,\n      null\n    );\n\n    let currentNode: Node | null;\n    while ((currentNode = treeWalker.nextNode())) {\n      const textNode = currentNode as Text;\n\n      // Skip empty text nodes\n      if (!textNode.textContent || textNode.textContent.length === 0) {\n        continue;\n      }\n\n      // Check if this text node is within the range\n      if (!this.isNodeInRange(textNode, range)) {\n        continue;\n      }\n\n      const textLength = textNode.textContent.length;\n      let startOffset = 0;\n      let endOffset = textLength;\n\n      // Adjust offsets for start node\n      if (textNode === range.startContainer) {\n        startOffset = range.startOffset;\n      }\n\n      // Adjust offsets for end node\n      if (textNode === range.endContainer) {\n        endOffset = range.endOffset;\n      }\n\n      // Only add if there's actual content to wrap\n      if (endOffset > startOffset) {\n        textNodes.push({ node: textNode, startOffset, endOffset });\n      }\n    }\n\n    console.log(`Found ${textNodes.length} text node(s) (complex case)`);\n    return textNodes;\n  }\n\n  /**\n   * Check if a node is within a range\n   */\n  private isNodeInRange(node: Node, range: Range): boolean {\n    try {\n      const nodeRange = document.createRange();\n      nodeRange.selectNode(node);\n\n      // Check if node is completely before the range\n      if (range.compareBoundaryPoints(Range.START_TO_END, nodeRange) <= 0) {\n        return false;\n      }\n\n      // Check if node is completely after the range\n      if (range.compareBoundaryPoints(Range.END_TO_START, nodeRange) >= 0) {\n        return false;\n      }\n\n      return true;\n    } catch {\n      return false;\n    }\n  }\n\n  /**\n   * Apply annotation styles\n   */\n  private applyStyle(\n    element: HTMLElement,\n    style: AnnotationStyle,\n    color: AnnotationColor,\n    config: (typeof COLORS)[AnnotationColor]\n  ): void {\n    element.style.cursor = \"pointer\";\n    element.style.transition = \"all 0.2s ease\";\n    element.style.color = \"inherit\"; // Preserve text color\n\n    if (style === \"highlight\") {\n      element.style.backgroundColor = config.highlight;\n      element.style.borderBottom = \"none\";\n    } else {\n      // underline\n      element.style.backgroundColor = \"transparent\";\n      element.style.borderBottom = `3px solid ${config.underline}`;\n      element.style.paddingBottom = \"1px\";\n    }\n  }\n}\n\nexport const engine = new AnnotationEngine();\n","\"use client\";\n\nimport { useEffect, useCallback } from \"react\";\nimport { useAnnotationStore } from \"./store\";\nimport { engine } from \"./engine\";\nimport type { Annotation, AnnotationStyle, AnnotationColor } from \"./types\";\nimport { COLORS } from \"./types\";\n\nfunction generateId(): string {\n  return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\nexport default function Annotator() {\n  const {\n    annotations,\n    isEnabled,\n    activeStyle,\n    activeColor,\n    addAnnotation,\n    removeAnnotation,\n    setEnabled,\n    setActiveStyle,\n    setActiveColor,\n    loadAnnotations,\n    clearAll,\n  } = useAnnotationStore();\n\n  useEffect(() => {\n    // Clean up any malformed annotations from previous versions\n    engine.cleanupMalformed();\n\n    const pageUrl = window.location.href;\n    loadAnnotations(pageUrl);\n  }, [loadAnnotations]);\n\n  useEffect(() => {\n    engine.removeAll();\n    annotations.forEach((annotation) => {\n      engine.render(annotation);\n    });\n  }, [annotations]);\n\n  const handleSelection = useCallback(async () => {\n    if (!isEnabled) return;\n\n    const target = engine.createFromSelection();\n    if (!target) return;\n\n    const annotation: Annotation = {\n      id: generateId(),\n      style: activeStyle,\n      color: activeColor,\n      target,\n      created: Date.now(),\n      updated: Date.now(),\n      pageUrl: window.location.href,\n    };\n\n    await addAnnotation(annotation);\n    window.getSelection()?.removeAllRanges();\n  }, [isEnabled, activeStyle, activeColor, addAnnotation]);\n\n  useEffect(() => {\n    if (!isEnabled) return;\n\n    const handleMouseUp = () => {\n      setTimeout(handleSelection, 10);\n    };\n\n    document.addEventListener(\"mouseup\", handleMouseUp);\n    return () => document.removeEventListener(\"mouseup\", handleMouseUp);\n  }, [isEnabled, handleSelection]);\n\n  const handleRemove = useCallback(\n    async (id: string) => {\n      engine.remove(id);\n      await removeAnnotation(id);\n    },\n    [removeAnnotation]\n  );\n\n  const handleClearAll = useCallback(async () => {\n    if (!confirm(\"Remove all annotations from this page?\")) return;\n    engine.removeAll();\n    await clearAll();\n  }, [clearAll]);\n\n  const annotationsList = Array.from(annotations.values()).sort(\n    (a, b) => b.created - a.created\n  );\n\n  return (\n    <div className=\"flex h-full w-full flex-col gap-3\">\n      {/* Enable Toggle */}\n      <label className=\"flex items-center gap-2 cursor-pointer select-none\">\n        <input\n          type=\"checkbox\"\n          checked={isEnabled}\n          onChange={(e) => setEnabled(e.target.checked)}\n          className=\"h-4 w-4 accent-[--color-accent]\"\n        />\n        <span className=\"text-sm font-medium\">Enable Annotations</span>\n      </label>\n\n      {/* Style & Color Controls */}\n      <div className=\"flex flex-col gap-3 p-3 rounded-md border border-[--color-border] bg-card\">\n        {/* Style Selector */}\n        <div>\n          <div className=\"text-xs font-medium text-[color:var(--color-muted-foreground)] mb-2\">\n            STYLE\n          </div>\n          <div className=\"flex gap-2\">\n            {([\"highlight\", \"underline\"] as AnnotationStyle[]).map((style) => (\n              <button\n                key={style}\n                onClick={() => setActiveStyle(style)}\n                className={`flex-1 h-9 rounded-md text-sm font-medium transition-all ${\n                  activeStyle === style\n                    ? \"bg-[--color-accent] text-[--color-accent-foreground] shadow-lg ring-2 ring-[--color-accent] ring-offset-2\"\n                    : \"bg-[--surface] hover:bg-[--surface]/80\"\n                }`}\n              >\n                {style.charAt(0).toUpperCase() + style.slice(1)}\n              </button>\n            ))}\n          </div>\n        </div>\n\n        {/* Color Selector */}\n        <div>\n          <div className=\"text-xs font-medium text-[color:var(--color-muted-foreground)] mb-2\">\n            COLOR\n          </div>\n          <div className=\"grid grid-cols-4 gap-2\">\n            {(Object.keys(COLORS) as AnnotationColor[]).map((color) => {\n              const config = COLORS[color];\n              const isSelected = activeColor === color;\n              return (\n                <button\n                  key={color}\n                  onClick={() => setActiveColor(color)}\n                  className={`h-10 rounded-md transition-all relative overflow-hidden ${\n                    isSelected\n                      ? \"ring-[3px] ring-[--color-accent] ring-offset-2 shadow-lg scale-105\"\n                      : \"ring-1 ring-[--color-border] hover:scale-105 hover:shadow-md\"\n                  }`}\n                  title={config.name}\n                  aria-label={`Select ${config.name}`}\n                  style={{\n                    backgroundColor:\n                      activeStyle === \"highlight\"\n                        ? config.highlight\n                        : \"#f5f5f5\",\n                    borderBottom:\n                      activeStyle === \"underline\"\n                        ? `3px solid ${config.underline}`\n                        : undefined,\n                  }}\n                >\n                  {isSelected && (\n                    <div className=\"absolute inset-0 flex items-center justify-center\">\n                      <svg\n                        className=\"w-5 h-5 text-[--color-accent] drop-shadow-lg\"\n                        fill=\"currentColor\"\n                        viewBox=\"0 0 20 20\"\n                      >\n                        <path\n                          fillRule=\"evenodd\"\n                          d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n                          clipRule=\"evenodd\"\n                        />\n                      </svg>\n                    </div>\n                  )}\n                </button>\n              );\n            })}\n          </div>\n        </div>\n      </div>\n\n      {/* Annotations List */}\n      <div className=\"flex-1 flex flex-col overflow-hidden rounded-md border border-[--color-border] bg-card\">\n        <div className=\"flex items-center justify-between px-3 py-2 border-b border-[--color-border]\">\n          <div className=\"text-sm font-medium\">\n            Annotations ({annotationsList.length})\n          </div>\n          {annotationsList.length > 0 && (\n            <button\n              onClick={handleClearAll}\n              className=\"text-xs text-[color:var(--color-muted-foreground)] hover:text-[color:var(--color-foreground)] transition-colors\"\n            >\n              Clear All\n            </button>\n          )}\n        </div>\n\n        <div className=\"flex-1 overflow-auto\">\n          {annotationsList.length === 0 ? (\n            <div className=\"p-4 text-center text-sm text-[color:var(--color-muted-foreground)]\">\n              {isEnabled\n                ? \"Select text on the page to create annotations\"\n                : \"Enable annotations to get started\"}\n            </div>\n          ) : (\n            <ul className=\"divide-y divide-[--color-border]\">\n              {annotationsList.map((annotation) => {\n                const config = COLORS[annotation.color];\n                return (\n                  <li\n                    key={annotation.id}\n                    className=\"group p-3 hover:bg-[--surface] transition-colors\"\n                  >\n                    <div className=\"flex items-start gap-3\">\n                      <div\n                        className=\"w-1 h-12 rounded-full flex-shrink-0\"\n                        style={{\n                          backgroundColor: config.underline,\n                        }}\n                      />\n                      <div className=\"flex-1 min-w-0\">\n                        <div className=\"text-sm mb-1 line-clamp-2\">\n                          {annotation.target.quote}\n                        </div>\n                        <div className=\"flex items-center gap-2 text-xs text-[color:var(--color-muted-foreground)]\">\n                          <span className=\"capitalize\">{annotation.style}</span>\n                          <span>•</span>\n                          <span>{config.name}</span>\n                        </div>\n                      </div>\n                      <button\n                        type=\"button\"\n                        onClick={() => handleRemove(annotation.id)}\n                        className=\"text-xs text-[color:var(--color-muted-foreground)] hover:text-red-500 opacity-0 group-hover:opacity-100 transition-all\"\n                      >\n                        Delete\n                      </button>\n                    </div>\n                  </li>\n                );\n              })}\n            </ul>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n"],"names":["DB_NAME","DB_VERSION","STORE_NAME","AnnotationDatabase","resolve","reject","request","event","db","store","annotation","id","pageUrl","useAnnotationStore","create","set","get","state","newMap","updates","updated","enabled","style","color","annotations","annotationMap","a","COLORS","ANNOTATION_CLASS","ANNOTATION_ATTR","AnnotationEngine","root","selection","range","quote","node","checkNode","container","selector","startOffset","endOffset","elements","error","annotationId","el","parent","mark","current","tagName","element","path","maxDepth","classes","c","siblings","s","index","beforeRange","target","treeWalker","currentOffset","startNode","startNodeOffset","endNode","endNodeOffset","nodeLength","nextOffset","colorConfig","textNodes","i","textLength","targetNode","wrapper","err","currentNode","textNode","nodeRange","config","engine","generateId","Annotator","isEnabled","activeStyle","activeColor","addAnnotation","removeAnnotation","setEnabled","setActiveStyle","setActiveColor","loadAnnotations","clearAll","useEffect","handleSelection","useCallback","handleMouseUp","handleRemove","handleClearAll","annotationsList","b","jsxs","jsx","e","isSelected"],"mappings":"6JAOMA,EAAU,eACVC,EAAa,EACbC,EAAa,cAEnB,MAAMC,CAAmB,CAAzB,aAAA,CACE,KAAQ,UAAyC,IAAA,CAEjD,MAAc,OAA8B,CAC1C,OAAI,KAAK,UAAkB,KAAK,WAEhC,KAAK,UAAY,IAAI,QAAQ,CAACC,EAASC,IAAW,CAChD,MAAMC,EAAU,UAAU,KAAKN,EAASC,CAAU,EAElDK,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,EAC5CA,EAAQ,UAAY,IAAMF,EAAQE,EAAQ,MAAM,EAEhDA,EAAQ,gBAAmBC,GAAU,CACnC,MAAMC,EAAMD,EAAM,OAA4B,OAE9C,GAAI,CAACC,EAAG,iBAAiB,SAASN,CAAU,EAAG,CAC7C,MAAMO,EAAQD,EAAG,kBAAkBN,EAAY,CAAE,QAAS,KAAM,EAChEO,EAAM,YAAY,UAAW,UAAW,CAAE,OAAQ,GAAO,EACzDA,EAAM,YAAY,UAAW,UAAW,CAAE,OAAQ,GAAO,CAC3D,CACF,CACF,CAAC,EAEM,KAAK,UACd,CAEA,MAAM,eAAeC,EAAuC,CAC1D,MAAMF,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAGtC,MAAMC,EAFKE,EAAG,YAAYN,EAAY,WAAW,EAChC,YAAYA,CAAU,EACjB,IAAIQ,CAAU,EAEpCJ,EAAQ,UAAY,IAAMF,EAAA,EAC1BE,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAEA,MAAM,cAAcK,EAA6C,CAC/D,MAAMH,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAGtC,MAAMC,EAFKE,EAAG,YAAYN,EAAY,UAAU,EAC/B,YAAYA,CAAU,EACjB,IAAIS,CAAE,EAE5BL,EAAQ,UAAY,IAAMF,EAAQE,EAAQ,MAAM,EAChDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAEA,MAAM,qBAAqBM,EAAwC,CACjE,MAAMJ,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAItC,MAAMC,EAHKE,EAAG,YAAYN,EAAY,UAAU,EAC/B,YAAYA,CAAU,EACnB,MAAM,SAAS,EACb,OAAOU,CAAO,EAEpCN,EAAQ,UAAY,IAAMF,EAAQE,EAAQ,QAAU,CAAA,CAAE,EACtDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAEA,MAAM,mBAA2C,CAC/C,MAAME,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAGtC,MAAMC,EAFKE,EAAG,YAAYN,EAAY,UAAU,EAC/B,YAAYA,CAAU,EACjB,OAAA,EAEtBI,EAAQ,UAAY,IAAMF,EAAQE,EAAQ,QAAU,CAAA,CAAE,EACtDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAEA,MAAM,iBAAiBK,EAA2B,CAChD,MAAMH,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAGtC,MAAMC,EAFKE,EAAG,YAAYN,EAAY,WAAW,EAChC,YAAYA,CAAU,EACjB,OAAOS,CAAE,EAE/BL,EAAQ,UAAY,IAAMF,EAAA,EAC1BE,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAEA,MAAM,UAA0B,CAC9B,MAAME,EAAK,MAAM,KAAK,MAAA,EACtB,OAAO,IAAI,QAAQ,CAACJ,EAASC,IAAW,CAGtC,MAAMC,EAFKE,EAAG,YAAYN,EAAY,WAAW,EAChC,YAAYA,CAAU,EACjB,MAAA,EAEtBI,EAAQ,UAAY,IAAMF,EAAA,EAC1BE,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CACF,CAEO,MAAME,EAAK,IAAIL,ECnFTU,EAAqBC,EAAAA,OAAwB,CAACC,EAAKC,KAAS,CACvE,gBAAiB,IACjB,WAAY,KACZ,UAAW,GACX,YAAa,YACb,YAAa,SAEb,cAAe,MAAON,GAAe,CACnC,MAAMF,EAAG,eAAeE,CAAU,EAClCK,EAAKE,IAAW,CACd,YAAa,IAAI,IAAIA,EAAM,WAAW,EAAE,IAAIP,EAAW,GAAIA,CAAU,CAAA,EACrE,CACJ,EAEA,iBAAkB,MAAOC,GAAO,CAC9B,MAAMH,EAAG,iBAAiBG,CAAE,EAC5BI,EAAKE,GAAU,CACb,MAAMC,EAAS,IAAI,IAAID,EAAM,WAAW,EACxC,OAAAC,EAAO,OAAOP,CAAE,EACT,CACL,YAAaO,EACb,WAAYD,EAAM,aAAeN,EAAK,KAAOM,EAAM,UAAA,CAEvD,CAAC,CACH,EAEA,iBAAkB,MAAON,EAAIQ,IAAY,CACvC,MAAMT,EAAaM,EAAA,EAAM,YAAY,IAAIL,CAAE,EAC3C,GAAI,CAACD,EAAY,OAEjB,MAAMU,EAAU,CAAE,GAAGV,EAAY,GAAGS,EAAS,QAAS,KAAK,KAAI,EAC/D,MAAMX,EAAG,eAAeY,CAAO,EAC/BL,EAAKE,IAAW,CACd,YAAa,IAAI,IAAIA,EAAM,WAAW,EAAE,IAAIN,EAAIS,CAAO,CAAA,EACvD,CACJ,EAEA,iBAAmBT,GAAO,CACxBI,EAAI,CAAE,WAAYJ,EAAI,CACxB,EAEA,WAAaU,GAAY,CACvBN,EAAI,CAAE,UAAWM,EAAS,CAC5B,EAEA,eAAiBC,GAAU,CACzBP,EAAI,CAAE,YAAaO,EAAO,CAC5B,EAEA,eAAiBC,GAAU,CACzBR,EAAI,CAAE,YAAaQ,EAAO,CAC5B,EAEA,gBAAiB,MAAOX,GAAY,CAClC,MAAMY,EAAc,MAAMhB,EAAG,qBAAqBI,CAAO,EACnDa,EAAgB,IAAI,IACxBD,EAAY,IAAKE,GAAkB,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAA,EAE9CX,EAAI,CAAE,YAAaU,EAAe,CACpC,EAEA,SAAU,SAAY,CACpB,MAAMD,EAAcR,IAAM,YAC1B,UAAWL,KAAMa,EAAY,OAC3B,MAAMhB,EAAG,iBAAiBG,CAAE,EAE9BI,EAAI,CAAE,YAAa,IAAI,IAAO,WAAY,KAAM,CAClD,CACF,EAAE,ECtCWY,EAA+C,CAC1D,OAAQ,CACN,KAAM,SACN,UAAW,0BACX,UAAW,UACX,cAAe,SAAA,EAEjB,MAAO,CACL,KAAM,QACN,UAAW,2BACX,UAAW,UACX,cAAe,SAAA,EAEjB,KAAM,CACJ,KAAM,OACN,UAAW,0BACX,UAAW,UACX,cAAe,SAAA,EAEjB,KAAM,CACJ,KAAM,OACN,UAAW,0BACX,UAAW,UACX,cAAe,SAAA,CAEnB,ECtEMC,EAAmB,kBACnBC,EAAkB,qBAEjB,MAAMC,CAAiB,CAI5B,YAAYC,EAAoB,SAAS,KAAM,CAF/C,KAAQ,aAA2C,IAGjD,KAAK,KAAOA,CACd,CAKA,qBAA+C,CAC7C,MAAMC,EAAY,OAAO,aAAA,EACzB,GAAI,CAACA,GAAaA,EAAU,YAAa,OAAO,KAEhD,MAAMC,EAAQD,EAAU,WAAW,CAAC,EAC9BE,EAAQD,EAAM,SAAA,EAAW,KAAA,EAG/B,GAAI,CAACC,EAAO,OAAO,KAGnB,GAAIA,EAAM,OAAS,IACjB,eAAQ,KAAK,0CAA0C,EACvD,MAAM,mDAAmD,EAClD,KAIT,MAAMC,EAAOF,EAAM,wBACnB,IAAIG,EACFD,EAAK,WAAa,KAAK,UACnBA,EAAK,cACJA,EAEP,KAAOC,GAAaA,IAAc,SAAS,MAAM,CAC/C,GAAIA,EAAU,WAAW,SAASR,CAAgB,EAChD,eAAQ,KAAK,+CAA+C,EAC5D,MACE,iFAAA,EAEK,KAETQ,EAAYA,EAAU,aACxB,CAEA,MAAMC,EAAY,KAAK,cAAcJ,EAAM,uBAAuB,EAClE,GAAI,CAACI,EACH,eAAQ,KAAK,iDAAiD,EACvD,KAIT,MAAMC,EAAW,KAAK,iBAAiBD,CAAS,EAChD,GAAI,CAACC,GAAYA,EAAS,KAAA,IAAW,GACnC,eAAQ,KAAK,oDAAoD,EAC1D,KAIT,KAAM,CAAE,YAAAC,EAAa,UAAAC,CAAA,EAAc,KAAK,WAAWP,EAAOI,CAAS,EAEnE,eAAQ,IAAI,+BAAgC,CAC1C,SAAAC,EACA,MAAOJ,EAAM,UAAU,EAAG,EAAE,GAAKA,EAAM,OAAS,GAAK,MAAQ,IAC7D,YAAAK,EACA,UAAAC,CAAA,CACD,EAEM,CACL,SAAAF,EACA,MAAAJ,EACA,YAAAK,EACA,UAAAC,CAAA,CAEJ,CAKA,OAAO9B,EAAiC,CACtC,GAAI,CAEF,GACE,CAACA,EAAW,OAAO,UACnBA,EAAW,OAAO,SAAS,KAAA,IAAW,GAEtC,eAAQ,KAAK,uCAAwCA,EAAW,EAAE,EAC3D,GAGT,MAAM2B,EAAY,SAAS,cACzB3B,EAAW,OAAO,QAAA,EAEpB,GAAI,CAAC2B,EACH,eAAQ,KACN,qCAAqC3B,EAAW,OAAO,QAAQ,GAC/DA,CAAA,EAEK,GAGT,MAAMuB,EAAQ,KAAK,YAAYvB,EAAW,OAAQ2B,CAAS,EAC3D,GAAI,CAACJ,EACH,eAAQ,KAAK,yCAA0CvB,EAAW,EAAE,EAC7D,GAGT,MAAM+B,EAAW,KAAK,eAAeR,EAAOvB,CAAU,EACtD,GAAI+B,EAAS,OAAS,EACpB,YAAK,SAAS,IAAI/B,EAAW,GAAI+B,CAAQ,EACzC,QAAQ,IACN,yBAAyB/B,EAAW,EAAE,KAAK+B,EAAS,MAAM,YAAA,EAErD,GAEP,QAAQ,KAAK,sCAAuC/B,EAAW,EAAE,CAErE,OAASgC,EAAO,CACd,QAAQ,MAAM,+BAAgChC,EAAW,GAAIgC,CAAK,CACpE,CACA,MAAO,EACT,CAKA,OAAOC,EAA4B,CACjC,MAAMF,EAAW,KAAK,SAAS,IAAIE,CAAY,EAC1CF,IAELA,EAAS,QAASG,GAAO,CACvB,MAAMC,EAASD,EAAG,WAClB,GAAKC,EAGL,MAAOD,EAAG,YACRC,EAAO,aAAaD,EAAG,WAAYA,CAAE,EAEvCC,EAAO,YAAYD,CAAE,EACvB,CAAC,EAGDH,EAAS,QAASG,GAAOA,EAAG,YAAY,WAAW,EAEnD,KAAK,SAAS,OAAOD,CAAY,EACnC,CAKA,WAAkB,CAChB,UAAWhC,KAAM,KAAK,SAAS,KAAA,EAC7B,KAAK,OAAOA,CAAE,EAEhB,KAAK,SAAS,MAAA,CAChB,CAKA,kBAAyB,CAET,SAAS,iBAAiB,IAAIiB,CAAgB,EAAE,EAExD,QAASkB,GAAS,CAMtB,GAJyBA,EAAK,cAC5B,oFAAA,EAGoB,CAEpB,MAAMD,EAASC,EAAK,WACpB,GAAID,EAAQ,CACV,KAAOC,EAAK,YACVD,EAAO,aAAaC,EAAK,WAAYA,CAAI,EAE3CD,EAAO,YAAYC,CAAI,EACvBD,EAAO,UAAA,CACT,CACF,CACF,CAAC,CACH,CAKQ,cAAcV,EAAgC,CACpD,IAAIY,EACFZ,EAAK,WAAa,KAAK,UACnBA,EAAK,cACJA,EAGP,KAAOY,GAAWA,IAAY,KAAK,MAAM,CAEvC,GAAIA,EAAQ,IAAMA,EAAQ,aAAa,kBAAkB,EACvD,OAAOA,EAGT,MAAMC,EAAUD,EAAQ,SAAS,YAAA,EACjC,GACEC,IAAY,KACZA,IAAY,OACZA,IAAY,WACZA,IAAY,WACZA,IAAY,QACZA,IAAY,MACZA,IAAY,MACZA,IAAY,KAEZ,OAAOD,EAETA,EAAUA,EAAQ,aACpB,CAGA,OAAO,SAAS,IAClB,CAKQ,iBAAiBE,EAA8B,CAErD,GAAIA,EAAQ,GACV,MAAO,IAAI,IAAI,OAAOA,EAAQ,EAAE,CAAC,GAInC,GAAIA,IAAY,SAAS,KACvB,MAAO,OAGT,MAAMC,EAAiB,CAAA,EACvB,IAAIH,EAA8BE,EAC9BE,EAAW,GAEf,KAAOJ,GAAWA,IAAY,SAAS,MAAQI,EAAW,GAAG,CAC3D,IAAIb,EAAWS,EAAQ,QAAQ,YAAA,EAG/B,GAAIA,EAAQ,UAAW,CACrB,MAAMK,EAAU,MAAM,KAAKL,EAAQ,SAAS,EACzC,OACEM,GAAM,CAACA,EAAE,WAAW,aAAa,GAAK,CAACA,EAAE,WAAW,YAAY,CAAA,EAElE,MAAM,EAAG,CAAC,EACTD,EAAQ,OAAS,IACnBd,GAAY,IAAMc,EAAQ,IAAKC,GAAM,IAAI,OAAOA,CAAC,CAAC,EAAE,KAAK,GAAG,EAEhE,CAGA,MAAMR,EAASE,EAAQ,cACvB,GAAIF,EAAQ,CACV,MAAMS,EAAW,MAAM,KAAKT,EAAO,QAAQ,EAAE,OAC1CU,GAAMA,EAAE,UAAYR,EAAS,OAAA,EAEhC,GAAIO,EAAS,OAAS,EAAG,CACvB,MAAME,EAAQF,EAAS,QAAQP,CAAO,EAAI,EAC1CT,GAAY,gBAAgBkB,CAAK,GACnC,CACF,CAEAN,EAAK,QAAQZ,CAAQ,EACrBS,EAAUA,EAAQ,cAClBI,GACF,CAEA,OAAOD,EAAK,OAAS,EAAIA,EAAK,KAAK,KAAK,EAAI,MAC9C,CAKQ,WACNjB,EACAI,EAC4C,CAC5C,MAAMoB,EAAc,SAAS,YAAA,EAC7BA,EAAY,SAASpB,EAAW,CAAC,EACjCoB,EAAY,OAAOxB,EAAM,eAAgBA,EAAM,WAAW,EAC1D,MAAMM,EAAckB,EAAY,SAAA,EAAW,OACrCjB,EAAYD,EAAcN,EAAM,SAAA,EAAW,OAEjD,MAAO,CAAE,YAAAM,EAAa,UAAAC,CAAA,CACxB,CAKQ,YACNkB,EACArB,EACc,CAKd,IAJoBA,EAAU,aAAe,IAGd,QAAQqB,EAAO,KAAK,IAChC,GACjB,eAAQ,KAAK,8BAA8B,EACpC,KAGT,GAAI,CACF,MAAMzB,EAAQ,SAAS,YAAA,EACjB0B,EAAa,SAAS,iBAC1BtB,EACA,WAAW,SAAA,EAGb,IAAIuB,EAAgB,EAChBC,EAAyB,KACzBC,EAAkB,EAClBC,EAAuB,KACvBC,EAAgB,EAEpB,KAAOL,EAAW,YAAY,CAC5B,MAAMxB,EAAOwB,EAAW,YAClBM,EAAa9B,EAAK,aAAa,QAAU,EACzC+B,EAAaN,EAAgBK,EAOnC,GALI,CAACJ,GAAaK,GAAcR,EAAO,cACrCG,EAAY1B,EACZ2B,EAAkBJ,EAAO,YAAcE,GAGrCM,GAAcR,EAAO,UAAW,CAClCK,EAAU5B,EACV6B,EAAgBN,EAAO,UAAYE,EACnC,KACF,CAEAA,EAAgBM,CAClB,CAEA,MAAI,CAACL,GAAa,CAACE,EACV,MAGT9B,EAAM,SAAS4B,EAAW,KAAK,IAAI,EAAGC,CAAe,CAAC,EACtD7B,EAAM,OAAO8B,EAAS,KAAK,IAAI,EAAGC,CAAa,CAAC,EAEzC/B,EACT,OAASS,EAAO,CACd,eAAQ,MAAM,0BAA2BA,CAAK,EACvC,IACT,CACF,CAKQ,eAAeT,EAAcvB,EAAuC,CAC1E,MAAM+B,EAA0B,CAAA,EAC1B,CAAE,MAAAnB,EAAO,MAAAC,EAAO,GAAAZ,CAAA,EAAOD,EACvByD,EAAcxC,EAAOJ,CAAK,EAEhC,GAAI,CAEF,MAAM6C,EAAY,KAAK,oBAAoBnC,CAAK,EAEhD,GAAImC,EAAU,SAAW,EACvB,eAAQ,KAAK,8BAA8B,EACpC3B,EAIT,QAAS4B,EAAID,EAAU,OAAS,EAAGC,GAAK,EAAGA,IAAK,CAC9C,KAAM,CAAE,KAAAlC,EAAM,YAAAI,EAAa,UAAAC,CAAA,EAAc4B,EAAUC,CAAC,EAEpD,GAAI,CAEF,GAAI,CAAClC,EAAK,YAAc,CAAC,SAAS,SAASA,CAAI,EAC7C,SAIF,MAAMmC,EAAanC,EAAK,aAAa,QAAU,EAC/C,IAAIoC,EAAmBpC,EAavB,GAVIK,EAAY8B,GACdC,EAAW,UAAU/B,CAAS,EAI5BD,EAAc,IAChBgC,EAAaA,EAAW,UAAUhC,CAAW,GAI3C,CAACgC,EAAW,aAAeA,EAAW,YAAY,SAAW,EAC/D,SAIF,MAAMC,EAAU,SAAS,cAAc,MAAM,EAC7CA,EAAQ,UAAY5C,EACpB4C,EAAQ,aAAa3C,EAAiBlB,CAAE,EAGxC,KAAK,WAAW6D,EAASlD,EAAOC,EAAO4C,CAAW,EAGlD,MAAMtB,EAAS0B,EAAW,WACtB1B,IACFA,EAAO,aAAa2B,EAASD,CAAU,EACvCC,EAAQ,YAAYD,CAAU,EAC9B9B,EAAS,KAAK+B,CAAO,EAEzB,OAASC,EAAK,CACZ,QAAQ,KAAK,4BAA6BA,CAAG,CAC/C,CACF,CACF,OAAS/B,EAAO,CACd,QAAQ,MAAM,6BAA8BA,CAAK,CACnD,CAEA,OAAOD,CACT,CAKQ,oBAAoBR,EAIzB,CACD,MAAMmC,EAID,CAAA,EAGL,GACEnC,EAAM,iBAAmBA,EAAM,cAC/BA,EAAM,eAAe,WAAa,KAAK,UAEvC,OAAAmC,EAAU,KAAK,CACb,KAAMnC,EAAM,eACZ,YAAaA,EAAM,YACnB,UAAWA,EAAM,SAAA,CAClB,EACD,QAAQ,IAAI,SAASmC,EAAU,MAAM,6BAA6B,EAC3DA,EAIT,MAAMT,EAAa,SAAS,iBAC1B1B,EAAM,wBACN,WAAW,UACX,IAAA,EAGF,IAAIyC,EACJ,KAAQA,EAAcf,EAAW,YAAa,CAC5C,MAAMgB,EAAWD,EAQjB,GALI,CAACC,EAAS,aAAeA,EAAS,YAAY,SAAW,GAKzD,CAAC,KAAK,cAAcA,EAAU1C,CAAK,EACrC,SAGF,MAAMqC,EAAaK,EAAS,YAAY,OACxC,IAAIpC,EAAc,EACdC,EAAY8B,EAGZK,IAAa1C,EAAM,iBACrBM,EAAcN,EAAM,aAIlB0C,IAAa1C,EAAM,eACrBO,EAAYP,EAAM,WAIhBO,EAAYD,GACd6B,EAAU,KAAK,CAAE,KAAMO,EAAU,YAAApC,EAAa,UAAAC,EAAW,CAE7D,CAEA,eAAQ,IAAI,SAAS4B,EAAU,MAAM,8BAA8B,EAC5DA,CACT,CAKQ,cAAcjC,EAAYF,EAAuB,CACvD,GAAI,CACF,MAAM2C,EAAY,SAAS,YAAA,EAS3B,OARAA,EAAU,WAAWzC,CAAI,EAGrB,EAAAF,EAAM,sBAAsB,MAAM,aAAc2C,CAAS,GAAK,GAK9D3C,EAAM,sBAAsB,MAAM,aAAc2C,CAAS,GAAK,EAKpE,MAAQ,CACN,MAAO,EACT,CACF,CAKQ,WACN3B,EACA3B,EACAC,EACAsD,EACM,CACN5B,EAAQ,MAAM,OAAS,UACvBA,EAAQ,MAAM,WAAa,gBAC3BA,EAAQ,MAAM,MAAQ,UAElB3B,IAAU,aACZ2B,EAAQ,MAAM,gBAAkB4B,EAAO,UACvC5B,EAAQ,MAAM,aAAe,SAG7BA,EAAQ,MAAM,gBAAkB,cAChCA,EAAQ,MAAM,aAAe,aAAa4B,EAAO,SAAS,GAC1D5B,EAAQ,MAAM,cAAgB,MAElC,CACF,CAEO,MAAM6B,EAAS,IAAIhD,EC1iB1B,SAASiD,GAAqB,CAC5B,MAAO,GAAG,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,CAAC,EACjE,CAEA,SAAwBC,GAAY,CAClC,KAAM,CACJ,YAAAxD,EACA,UAAAyD,EACA,YAAAC,EACA,YAAAC,EACA,cAAAC,EACA,iBAAAC,EACA,WAAAC,EACA,eAAAC,EACA,eAAAC,EACA,gBAAAC,EACA,SAAAC,CAAA,EACE7E,EAAA,EAEJ8E,EAAAA,UAAU,IAAM,CAEdb,EAAO,iBAAA,EAEP,MAAMlE,EAAU,OAAO,SAAS,KAChC6E,EAAgB7E,CAAO,CACzB,EAAG,CAAC6E,CAAe,CAAC,EAEpBE,EAAAA,UAAU,IAAM,CACdb,EAAO,UAAA,EACPtD,EAAY,QAASd,GAAe,CAClCoE,EAAO,OAAOpE,CAAU,CAC1B,CAAC,CACH,EAAG,CAACc,CAAW,CAAC,EAEhB,MAAMoE,EAAkBC,EAAAA,YAAY,SAAY,CAC9C,GAAI,CAACZ,EAAW,OAEhB,MAAMvB,EAASoB,EAAO,oBAAA,EACtB,GAAI,CAACpB,EAAQ,OAEb,MAAMhD,EAAyB,CAC7B,GAAIqE,EAAA,EACJ,MAAOG,EACP,MAAOC,EACP,OAAAzB,EACA,QAAS,KAAK,IAAA,EACd,QAAS,KAAK,IAAA,EACd,QAAS,OAAO,SAAS,IAAA,EAG3B,MAAM0B,EAAc1E,CAAU,EAC9B,OAAO,aAAA,GAAgB,gBAAA,CACzB,EAAG,CAACuE,EAAWC,EAAaC,EAAaC,CAAa,CAAC,EAEvDO,EAAAA,UAAU,IAAM,CACd,GAAI,CAACV,EAAW,OAEhB,MAAMa,EAAgB,IAAM,CAC1B,WAAWF,EAAiB,EAAE,CAChC,EAEA,gBAAS,iBAAiB,UAAWE,CAAa,EAC3C,IAAM,SAAS,oBAAoB,UAAWA,CAAa,CACpE,EAAG,CAACb,EAAWW,CAAe,CAAC,EAE/B,MAAMG,EAAeF,EAAAA,YACnB,MAAOlF,GAAe,CACpBmE,EAAO,OAAOnE,CAAE,EAChB,MAAM0E,EAAiB1E,CAAE,CAC3B,EACA,CAAC0E,CAAgB,CAAA,EAGbW,EAAiBH,EAAAA,YAAY,SAAY,CACxC,QAAQ,wCAAwC,IACrDf,EAAO,UAAA,EACP,MAAMY,EAAA,EACR,EAAG,CAACA,CAAQ,CAAC,EAEPO,EAAkB,MAAM,KAAKzE,EAAY,OAAA,CAAQ,EAAE,KACvD,CAACE,EAAGwE,IAAMA,EAAE,QAAUxE,EAAE,OAAA,EAG1B,OACEyE,EAAAA,KAAC,MAAA,CAAI,UAAU,oCAEb,SAAA,CAAAA,EAAAA,KAAC,QAAA,CAAM,UAAU,qDACf,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,QAASnB,EACT,SAAWoB,GAAMf,EAAWe,EAAE,OAAO,OAAO,EAC5C,UAAU,iCAAA,CAAA,EAEZD,EAAAA,IAAC,OAAA,CAAK,UAAU,sBAAsB,SAAA,oBAAA,CAAkB,CAAA,EAC1D,EAGAD,EAAAA,KAAC,MAAA,CAAI,UAAU,4EAEb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,sEAAsE,SAAA,QAErF,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,aACX,SAAA,CAAC,YAAa,WAAW,EAAwB,IAAK9E,GACtD8E,EAAAA,IAAC,SAAA,CAEC,QAAS,IAAMb,EAAejE,CAAK,EACnC,UAAW,4DACT4D,IAAgB5D,EACZ,4GACA,wCACN,GAEC,SAAAA,EAAM,OAAO,CAAC,EAAE,cAAgBA,EAAM,MAAM,CAAC,CAAA,EARzCA,CAAA,CAUR,CAAA,CACH,CAAA,EACF,SAGC,MAAA,CACC,SAAA,CAAA8E,EAAAA,IAAC,MAAA,CAAI,UAAU,sEAAsE,SAAA,QAErF,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,yBACX,SAAA,OAAO,KAAKzE,CAAM,EAAwB,IAAKJ,GAAU,CACzD,MAAMsD,EAASlD,EAAOJ,CAAK,EACrB+E,EAAanB,IAAgB5D,EACnC,OACE6E,EAAAA,IAAC,SAAA,CAEC,QAAS,IAAMZ,EAAejE,CAAK,EACnC,UAAW,2DACT+E,EACI,qEACA,8DACN,GACA,MAAOzB,EAAO,KACd,aAAY,UAAUA,EAAO,IAAI,GACjC,MAAO,CACL,gBACEK,IAAgB,YACZL,EAAO,UACP,UACN,aACEK,IAAgB,YACZ,aAAaL,EAAO,SAAS,GAC7B,MAAA,EAGP,SAAAyB,GACCF,MAAC,MAAA,CAAI,UAAU,oDACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,+CACV,KAAK,eACL,QAAQ,YAER,SAAAA,EAAAA,IAAC,OAAA,CACC,SAAS,UACT,EAAE,qHACF,SAAS,SAAA,CAAA,CACX,CAAA,CACF,CACF,CAAA,EAjCG7E,CAAA,CAqCX,CAAC,CAAA,CACH,CAAA,CAAA,CACF,CAAA,EACF,EAGA4E,EAAAA,KAAC,MAAA,CAAI,UAAU,yFACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,+EACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,sBAAsB,SAAA,CAAA,gBACrBF,EAAgB,OAAO,GAAA,EACvC,EACCA,EAAgB,OAAS,GACxBG,EAAAA,IAAC,SAAA,CACC,QAASJ,EACT,UAAU,kHACX,SAAA,WAAA,CAAA,CAED,EAEJ,EAEAI,EAAAA,IAAC,OAAI,UAAU,uBACZ,WAAgB,SAAW,EAC1BA,EAAAA,IAAC,MAAA,CAAI,UAAU,qEACZ,WACG,gDACA,oCACN,EAEAA,EAAAA,IAAC,KAAA,CAAG,UAAU,mCACX,SAAAH,EAAgB,IAAKvF,GAAe,CACnC,MAAMmE,EAASlD,EAAOjB,EAAW,KAAK,EACtC,OACE0F,EAAAA,IAAC,KAAA,CAEC,UAAU,mDAEV,SAAAD,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAC,EAAAA,IAAC,MAAA,CACC,UAAU,sCACV,MAAO,CACL,gBAAiBvB,EAAO,SAAA,CAC1B,CAAA,EAEFsB,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAC,MAAC,MAAA,CAAI,UAAU,4BACZ,SAAA1F,EAAW,OAAO,MACrB,EACAyF,EAAAA,KAAC,MAAA,CAAI,UAAU,6EACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,aAAc,SAAA1F,EAAW,MAAM,EAC/C0F,EAAAA,IAAC,QAAK,SAAA,GAAA,CAAC,EACPA,EAAAA,IAAC,OAAA,CAAM,SAAAvB,EAAO,IAAA,CAAK,CAAA,CAAA,CACrB,CAAA,EACF,EACAuB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAML,EAAarF,EAAW,EAAE,EACzC,UAAU,yHACX,SAAA,QAAA,CAAA,CAED,CAAA,CACF,CAAA,EA3BKA,EAAW,EAAA,CA8BtB,CAAC,EACH,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,CAEJ"}