{"version":3,"sources":["../src/core/disposable.ts","../src/core/errors.ts","../src/core/events.ts","../src/core/a11y.ts"],"names":["ResourceTracker","cleanup","id","toError","error","logLasciiError","type","context","err","LasciiEvent","LasciiEmitter","listener","options","detail","REDUCE_MOTION_QUERY","prefersReducedMotion","override","ensureLiveRegion","element","beginAccessibleTransition","label","endAccessibleTransition"],"mappings":"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","file":"chunk-SJQRBAXT.cjs","sourcesContent":["/**\r\n * Contract for effects that own timers, animation frames, or DOM resources.\r\n */\r\nexport interface Disposable {\r\n  dispose(): void;\r\n}\r\n\r\n/**\r\n * Tracks cleanup callbacks for timers, rAF, listeners, and DOM nodes.\r\n * Safe to call dispose() multiple times.\r\n */\r\nexport class ResourceTracker {\r\n  private readonly resources: Array<() => void> = [];\r\n  private disposed = false;\r\n\r\n  get isDisposed(): boolean {\r\n    return this.disposed;\r\n  }\r\n\r\n  track(cleanup: () => void): void {\r\n    if (this.disposed) {\r\n      cleanup();\r\n      return;\r\n    }\r\n    this.resources.push(cleanup);\r\n  }\r\n\r\n  trackTimeout(id: ReturnType<typeof setTimeout>): ReturnType<typeof setTimeout> {\r\n    this.track(() => clearTimeout(id));\r\n    return id;\r\n  }\r\n\r\n  trackInterval(\r\n    id: ReturnType<typeof setInterval>,\r\n  ): ReturnType<typeof setInterval> {\r\n    this.track(() => clearInterval(id));\r\n    return id;\r\n  }\r\n\r\n  trackAnimationFrame(id: number): number {\r\n    this.track(() => cancelAnimationFrame(id));\r\n    return id;\r\n  }\r\n\r\n  dispose(): void {\r\n    if (this.disposed) return;\r\n    this.disposed = true;\r\n    for (const cleanup of this.resources.splice(0)) {\r\n      try {\r\n        cleanup();\r\n      } catch {\r\n        // Cleanup must not throw; ignore individual failures.\r\n      }\r\n    }\r\n  }\r\n}\r\n","export type LasciiErrorType =\r\n  | \"canvas_context_unavailable\"\r\n  | \"canvas_initialization_failed\"\r\n  | \"image_load_failed\"\r\n  | \"image_animation_failed\"\r\n  | \"text_effect_initialization_failed\"\r\n  | \"text_effect_animation_failed\";\r\n\r\nexport interface LasciiErrorContext {\r\n  [key: string]: unknown;\r\n}\r\n\r\nexport function toError(error: unknown): Error {\r\n  if (error instanceof Error) return error;\r\n  return new Error(String(error));\r\n}\r\n\r\n/**\r\n * Structured logging for recoverable lascii failures.\r\n * Keeps production debugging possible without throwing to the page.\r\n */\r\nexport function logLasciiError(\r\n  type: LasciiErrorType | string,\r\n  error: unknown,\r\n  context: LasciiErrorContext = {},\r\n): void {\r\n  const err = toError(error);\r\n  console.warn(`[lascii] ${type}:`, err.message, context);\r\n}\r\n","export const LasciiEvent = {\r\n  Start: \"start\",\r\n  Progress: \"progress\",\r\n  Complete: \"complete\",\r\n  Error: \"error\",\r\n} as const;\r\n\r\nexport type LasciiEventName = (typeof LasciiEvent)[keyof typeof LasciiEvent];\r\n\r\nexport interface LasciiStartDetail {\r\n  text: string;\r\n}\r\n\r\nexport interface LasciiProgressDetail {\r\n  progress: number;\r\n}\r\n\r\nexport interface LasciiCompleteDetail {\r\n  text: string;\r\n}\r\n\r\nexport interface LasciiErrorDetail {\r\n  error: Error;\r\n}\r\n\r\nexport interface LasciiEventDetailMap {\r\n  start: LasciiStartDetail;\r\n  progress: LasciiProgressDetail;\r\n  complete: LasciiCompleteDetail;\r\n  error: LasciiErrorDetail;\r\n}\r\n\r\ntype LasciiListener<K extends keyof LasciiEventDetailMap> = (\r\n  event: CustomEvent<LasciiEventDetailMap[K]>,\r\n) => void;\r\n\r\n/**\r\n * Typed EventTarget used by lascii effects.\r\n * Listeners can be attached after construction; the first animation\r\n * frame is scheduled on a microtask.\r\n */\r\nexport class LasciiEmitter extends EventTarget {\r\n  addEventListener<K extends keyof LasciiEventDetailMap>(\r\n    type: K,\r\n    listener: LasciiListener<K>,\r\n    options?: boolean | AddEventListenerOptions,\r\n  ): void;\r\n  addEventListener(\r\n    type: string,\r\n    listener: EventListenerOrEventListenerObject | null,\r\n    options?: boolean | AddEventListenerOptions,\r\n  ): void;\r\n  addEventListener(\r\n    type: string,\r\n    listener: unknown,\r\n    options?: boolean | AddEventListenerOptions,\r\n  ): void {\r\n    super.addEventListener(\r\n      type,\r\n      listener as EventListenerOrEventListenerObject | null,\r\n      options,\r\n    );\r\n  }\r\n\r\n  removeEventListener<K extends keyof LasciiEventDetailMap>(\r\n    type: K,\r\n    listener: LasciiListener<K>,\r\n    options?: boolean | EventListenerOptions,\r\n  ): void;\r\n  removeEventListener(\r\n    type: string,\r\n    listener: EventListenerOrEventListenerObject | null,\r\n    options?: boolean | EventListenerOptions,\r\n  ): void;\r\n  removeEventListener(\r\n    type: string,\r\n    listener: unknown,\r\n    options?: boolean | EventListenerOptions,\r\n  ): void {\r\n    super.removeEventListener(\r\n      type,\r\n      listener as EventListenerOrEventListenerObject | null,\r\n      options,\r\n    );\r\n  }\r\n\r\n  protected emit<K extends keyof LasciiEventDetailMap>(\r\n    type: K,\r\n    detail: LasciiEventDetailMap[K],\r\n  ): void {\r\n    this.dispatchEvent(new CustomEvent(type, { detail }));\r\n  }\r\n}\r\n","const REDUCE_MOTION_QUERY = \"(prefers-reduced-motion: reduce)\";\r\n\r\nexport function prefersReducedMotion(override?: boolean): boolean {\r\n  if (typeof override === \"boolean\") return override;\r\n  if (typeof matchMedia !== \"function\") return false;\r\n  return matchMedia(REDUCE_MOTION_QUERY).matches;\r\n}\r\n\r\nexport function ensureLiveRegion(element: HTMLElement): void {\r\n  if (!element.hasAttribute(\"aria-live\")) {\r\n    element.setAttribute(\"aria-live\", \"polite\");\r\n  }\r\n  if (!element.hasAttribute(\"aria-atomic\")) {\r\n    element.setAttribute(\"aria-atomic\", \"true\");\r\n  }\r\n}\r\n\r\nexport function beginAccessibleTransition(\r\n  element: HTMLElement,\r\n  label: string,\r\n): void {\r\n  element.setAttribute(\"aria-busy\", \"true\");\r\n  element.setAttribute(\"aria-label\", label);\r\n}\r\n\r\nexport function endAccessibleTransition(element: HTMLElement): void {\r\n  element.removeAttribute(\"aria-busy\");\r\n  element.removeAttribute(\"aria-label\");\r\n}\r\n"]}