{"version":3,"file":"alrdy-animate.umd.cjs","sources":["../src/core/gsap-detect.ts","../src/core/settings.ts","../src/core/match-media.ts","../src/core/named-eases.ts","../src/core/presets.ts","../src/core/scroll-trigger.ts","../src/core/parse.ts","../src/core/scanner.ts","../src/core/trigger.ts","../src/core/reduced-motion.ts","../src/core/registry.ts","../src/core/resize.ts","../src/core/scroll-state.ts","../src/core/scroll-target.ts","../src/core/state.ts","../src/smooth-scroll/index.ts","../src/core/index.ts","../src/core/stagger.ts","../src/core/triggered-animation.ts","../src/features/appear/index.ts","../src/split/runtime.ts","../src/features/text/index.ts","../src/features/appear/reveal.ts","../src/features/appear/slices.ts","../src/features/parallax/index.ts","../src/core/autoplay.ts","../src/features/tabs/controller.ts","../src/core/progress-bar.ts","../src/core/viewport-gate.ts","../src/features/tabs/autoplay.ts","../src/features/tabs/keyboard.ts","../src/features/tabs/scroll.ts","../src/features/tabs/state.ts","../src/features/tabs/index.ts","../src/features/marquee/index.ts","../src/features/nav/index.ts","../src/core/visibility.ts","../src/features/slider/autoplay.ts","../src/features/slider/touch-guard.ts","../src/features/slider/finite-track.ts","../src/features/slider/horizontal-loop.ts","../src/features/slider/keyboard.ts","../src/features/slider/nav.ts","../src/features/slider/index.ts","../src/features/modal/animation.ts","../src/features/modal/a11y.ts","../src/features/modal/scroll-lock.ts","../src/features/modal/state.ts","../src/features/modal/index.ts","../src/features/hover/direction.ts","../src/features/hover/host.ts","../src/features/hover/effects.ts","../src/features/hover/index.ts","../src/features/cursor/index.ts","../src/features/stack/index.ts","../src/split/index.ts"],"sourcesContent":["export interface GsapHandle {\n  gsap: GsapInstance\n  plugins: Record<string, unknown>\n  has: (pluginName: string) => boolean\n}\n\nexport interface GsapInstance {\n  registerPlugin: (...plugins: unknown[]) => void\n  matchMedia: (scope?: Element | string) => GsapMatchMedia\n  context: (fn: (ctx: GsapContext) => void, scope?: Element | string | null) => GsapContext\n  to: (...args: unknown[]) => GsapTween\n  from: (...args: unknown[]) => GsapTween\n  fromTo: (...args: unknown[]) => GsapTween\n  set: (...args: unknown[]) => GsapTween\n  killTweensOf: (targets: unknown, props?: string) => void\n  getProperty: (target: unknown, property: string, unit?: string) => number | string\n  delayedCall: (delay: number, callback: () => void, params?: unknown[], scope?: unknown) => GsapTween\n  timeline: (...args: unknown[]) => GsapTimeline\n  defaults: (vars?: Record<string, unknown>) => Record<string, unknown>\n  ticker: {\n    add: (fn: (time: number) => void) => void\n    remove: (fn: (time: number) => void) => void\n    lagSmoothing: (threshold?: number, adjustedLag?: number) => void\n  }\n  utils: Record<string, unknown>\n}\n\nexport interface GsapContext {\n  add: (key: string | (() => void), fn?: () => void) => void\n  revert: () => void\n  kill: () => void\n}\n\nexport interface GsapMatchMedia {\n  add: (query: string | Record<string, string>, handler: (ctx: GsapContext) => void | (() => void)) => GsapMatchMedia\n  revert: () => void\n  // GSAP source: matchMedia.kill(revert) calls Context.kill(revert, true) on\n  // each registered context. With no truthy `revert` arg, Context.kill skips\n  // clearProps and just removes tweens/triggers — preserving inline GSAP\n  // styles. The `true` second arg ensures the matchMedia listener bookkeeping\n  // is cleaned up either way (no leaked media-query listeners).\n  kill: () => void\n}\n\nexport interface GsapTween {\n  kill: () => void\n  /** The elements/objects this tween animates. */\n  targets: () => Element[]\n  progress: {\n    (): number\n    (value: number): GsapTween\n  }\n  timeScale: {\n    (): number\n    (value: number): GsapTween\n  }\n  /** Optional `from` time / label to jump to before resuming forward. */\n  play: (from?: number | string, suppressEvents?: boolean) => GsapTween\n  pause: (atTime?: number | string, suppressEvents?: boolean) => GsapTween\n  reverse: (from?: number | string, suppressEvents?: boolean) => GsapTween\n  /**\n   * Rewind to the start and play forward. `includeDelay` (default false in GSAP)\n   * replays the tween's `delay` — unlike `play(0)`, whose time 0 sits *after* the\n   * delay, so a paused tween's delay is otherwise skipped on replay.\n   */\n  restart: (includeDelay?: boolean, suppressEvents?: boolean) => GsapTween\n  /** Set or replace a lifecycle callback (`onComplete`, `onReverseComplete`, …). */\n  eventCallback: (type: string, callback?: (() => void) | null) => GsapTween\n}\n\nexport interface GsapTimeline extends GsapTween {\n  to: (...args: unknown[]) => GsapTimeline\n  from: (...args: unknown[]) => GsapTimeline\n  fromTo: (...args: unknown[]) => GsapTimeline\n  set: (...args: unknown[]) => GsapTimeline\n  add: (...args: unknown[]) => GsapTimeline\n  progress: {\n    (): number\n    (value: number): GsapTimeline\n  }\n  timeScale: {\n    (): number\n    (value: number): GsapTimeline\n  }\n  play: (from?: number | string, suppressEvents?: boolean) => GsapTimeline\n  pause: (atTime?: number | string, suppressEvents?: boolean) => GsapTimeline\n  reverse: (from?: number | string, suppressEvents?: boolean) => GsapTimeline\n  /** Rewind to time 0 and play forward. */\n  restart: (includeDelay?: boolean, suppressEvents?: boolean) => GsapTimeline\n  /** True if the timeline has at least one active child tween right now. */\n  isActive: () => boolean\n  /** Set or replace a timeline lifecycle callback (`onComplete`, `onUpdate`, …). */\n  eventCallback: (type: string, callback?: (() => void) | null) => GsapTimeline\n}\n\nconst PLUGIN_GLOBAL_NAMES: Record<string, string> = {\n  ScrollTrigger: 'ScrollTrigger',\n  SplitText: 'SplitText',\n  Draggable: 'Draggable',\n  InertiaPlugin: 'InertiaPlugin',\n  Flip: 'Flip',\n  CustomEase: 'CustomEase',\n}\n\nexport function detectGsap(\n  requiredPlugins: string[] = [],\n  debug = false,\n): GsapHandle | null {\n  if (typeof window === 'undefined') return null\n  const w = window as unknown as Record<string, unknown>\n  const gsap = w.gsap as GsapInstance | undefined\n  if (!gsap || typeof gsap.registerPlugin !== 'function') {\n    if (debug) {\n      console.warn(\n        '[alrdy-animate] window.gsap not found. Add a <script> tag for GSAP before alrdy-animate.',\n      )\n    }\n    return null\n  }\n  const plugins: Record<string, unknown> = {}\n  const missing: string[] = []\n  for (const name of requiredPlugins) {\n    const globalName = PLUGIN_GLOBAL_NAMES[name] ?? name\n    const plugin = w[globalName]\n    if (plugin) {\n      plugins[name] = plugin\n      try {\n        gsap.registerPlugin(plugin)\n      } catch {\n        // already registered; ignore\n      }\n    } else {\n      missing.push(name)\n    }\n  }\n  if (missing.length > 0 && debug) {\n    console.warn(\n      `[alrdy-animate] Missing GSAP plugins: ${missing.join(', ')}. Add the corresponding <script> tags before alrdy-animate.`,\n    )\n  }\n  return {\n    gsap,\n    plugins,\n    has: (n: string) => n in plugins,\n  }\n}\n","import type { Breakpoints } from '../types/index'\n\nexport const VALUE_BEARING_ATTRS = [\n  'aa-animate',\n  'aa-trigger',\n  'aa-split',\n  'aa-stagger',\n  'aa-duration',\n  'aa-delay',\n  'aa-ease',\n  'aa-intensity',\n  'aa-scroll-start',\n  'aa-scroll-end',\n  'aa-scrub',\n  'aa-anchor',\n  'aa-again',\n  'aa-parallax-start',\n  'aa-parallax-end',\n  'aa-slider',\n  'aa-tabs',\n  'aa-marquee',\n  'aa-marquee-scroller',\n  'aa-autoplay',\n  'aa-nav',\n  'aa-hover',\n  'aa-color',\n  'aa-stack',\n  'aa-stack-in',\n  'aa-stack-lock',\n  'aa-stack-out',\n] as const\n\nexport type ValueAttr = (typeof VALUE_BEARING_ATTRS)[number]\n\nexport const SUFFIX_KEYS: Array<keyof Breakpoints> = ['sm', 'md', 'lg', 'xl']\n\nexport type BucketKey = 'base' | keyof Breakpoints | 'reduce'\n\nexport type Config = Partial<Record<ValueAttr, string>>\n\nexport interface ResolvedAttrs {\n  buckets: Map<BucketKey, Config>\n}\n\nexport function readAttrs(\n  el: Element,\n  presetEntry?: ReadonlyMap<string, string>,\n): ResolvedAttrs {\n  const buckets = new Map<BucketKey, Config>()\n  const bucket = (k: BucketKey): Config => {\n    let b = buckets.get(k)\n    if (!b) {\n      b = {}\n      buckets.set(k, b)\n    }\n    return b\n  }\n\n  // Real attribute on the element wins; preset entry fills holes.\n  const getValue = (name: string): string | null => {\n    const real = el.getAttribute(name)\n    if (real !== null) return real\n    return presetEntry?.get(name) ?? null\n  }\n\n  for (const attr of VALUE_BEARING_ATTRS) {\n    const baseValue = getValue(attr)\n    if (baseValue !== null) {\n      const parts = baseValue.split('|')\n      if (parts.length === 2) {\n        bucket('base')[attr] = parts[1].trim()\n        bucket('md')[attr] = parts[0].trim()\n      } else {\n        bucket('base')[attr] = baseValue\n      }\n    }\n    for (const bp of SUFFIX_KEYS) {\n      const v = getValue(`${attr}-${bp}`)\n      if (v !== null) bucket(bp)[attr] = v\n    }\n  }\n\n  return { buckets }\n}\n\nexport interface ResolvedRange {\n  /** Human-readable bucket name for debugging. */\n  bucket: BucketKey\n  query: string\n  config: Config\n}\n\nconst RANGE_ORDER = ['base', 'sm', 'md', 'lg', 'xl'] as const\ntype RangeKey = (typeof RANGE_ORDER)[number]\n\nconst ACCUM_KEYS: Record<RangeKey, BucketKey[]> = {\n  base: ['base'],\n  sm: ['base', 'sm'],\n  md: ['base', 'sm', 'md'],\n  lg: ['base', 'sm', 'md', 'lg'],\n  xl: ['base', 'sm', 'md', 'lg', 'xl'],\n}\n\nfunction configsEqual(a: Config, b: Config): boolean {\n  const ak = Object.keys(a)\n  const bk = Object.keys(b)\n  if (ak.length !== bk.length) return false\n  for (const k of ak) {\n    if (a[k as ValueAttr] !== b[k as ValueAttr]) return false\n  }\n  return true\n}\n\nfunction buildRangeQuery(from: number, to: number): string {\n  if (from <= 0 && to === Infinity) return 'all'\n  if (from <= 0) return `(max-width: ${to - 0.02}px)`\n  if (to === Infinity) return `(min-width: ${from}px)`\n  return `(min-width: ${from}px) and (max-width: ${to - 0.02}px)`\n}\n\n/**\n * Compute exclusive width-based ranges with their layered configs, then merge\n * adjacent ranges that resolve to the same config. Reduced motion is added as\n * an orthogonal entry on top of the base config.\n */\nexport function resolveRanges(\n  buckets: Map<BucketKey, Config>,\n  breakpoints: Breakpoints,\n): ResolvedRange[] {\n  const ranges: Array<{ key: RangeKey; from: number; to: number }> = [\n    { key: 'base', from: 0, to: breakpoints.sm },\n    { key: 'sm', from: breakpoints.sm, to: breakpoints.md },\n    { key: 'md', from: breakpoints.md, to: breakpoints.lg },\n    { key: 'lg', from: breakpoints.lg, to: breakpoints.xl },\n    { key: 'xl', from: breakpoints.xl, to: Infinity },\n  ]\n\n  const perRange = ranges.map((r) => {\n    const merged: Config = {}\n    for (const k of ACCUM_KEYS[r.key]) {\n      const b = buckets.get(k)\n      if (b) Object.assign(merged, b)\n    }\n    return { ...r, config: merged }\n  })\n\n  const groups: Array<{ key: RangeKey; from: number; to: number; config: Config }> = []\n  for (const r of perRange) {\n    const last = groups[groups.length - 1]\n    if (last && configsEqual(last.config, r.config)) {\n      last.to = r.to\n    } else {\n      groups.push({ ...r, config: { ...r.config } })\n    }\n  }\n\n  const result: ResolvedRange[] = groups.map((g) => ({\n    bucket: g.key,\n    query: buildRangeQuery(g.from, g.to),\n    config: g.config,\n  }))\n\n  const reduceBucket = buckets.get('reduce')\n  if (reduceBucket) {\n    const baseBucket = buckets.get('base') ?? {}\n    result.push({\n      bucket: 'reduce',\n      query: '(prefers-reduced-motion: reduce)',\n      config: { ...baseBucket, ...reduceBucket },\n    })\n  }\n\n  return result\n}\n\nfunction bucketForWidth(width: number, breakpoints: Breakpoints): RangeKey {\n  if (width >= breakpoints.xl) return 'xl'\n  if (width >= breakpoints.lg) return 'lg'\n  if (width >= breakpoints.md) return 'md'\n  if (width >= breakpoints.sm) return 'sm'\n  return 'base'\n}\n\n// Resolve one value-bearing attribute's effective value at a given width, with\n// the same `|` split + suffix accumulation as resolveRanges(). Trigger inference\n// uses it to tell whether a container feature is `none` at the current\n// breakpoint. Undefined when the attribute isn't set in the active range.\nexport function resolveAttrAtWidth(\n  el: Element,\n  attr: ValueAttr,\n  width: number,\n  breakpoints: Breakpoints,\n): string | undefined {\n  const { buckets } = readAttrs(el)\n  let value: string | undefined\n  for (const k of ACCUM_KEYS[bucketForWidth(width, breakpoints)]) {\n    const b = buckets.get(k)\n    if (b && b[attr] !== undefined) value = b[attr]\n  }\n  return value\n}\n","import type { Breakpoints } from '../types/index'\nimport type { GsapHandle, GsapMatchMedia } from './gsap-detect'\nimport { resolveRanges, type BucketKey, type Config, type ResolvedAttrs } from './settings'\n\nexport interface ResponsiveBindingArgs {\n  element: Element\n  config: Config\n  bucket: BucketKey\n}\n\nexport type ResponsiveBinding = (args: ResponsiveBindingArgs) => void | (() => void)\n\nexport interface ResponsiveController {\n  bind: (element: Element, attrs: ResolvedAttrs, run: ResponsiveBinding) => void\n  revertAll: () => void\n  /**\n   * Kill all tweens and ScrollTriggers in the matchMedia *without* reverting\n   * inline GSAP styles. Use only when the bound DOM is about to be removed —\n   * e.g. a Barba page-transition leave hook — so leftover `opacity:0`,\n   * `transform:translateY(...)` etc. linger briefly until the wrapper is\n   * discarded. Calling this on a long-lived container would freeze elements\n   * mid-animation indefinitely.\n   */\n  killAll: () => void\n}\n\nexport function createResponsiveController(\n  gsapHandle: GsapHandle,\n  breakpoints: Breakpoints,\n): ResponsiveController {\n  const mm: GsapMatchMedia = gsapHandle.gsap.matchMedia()\n\n  const bind: ResponsiveController['bind'] = (element, attrs, run) => {\n    const ranges = resolveRanges(attrs.buckets, breakpoints)\n    for (const { bucket, query, config } of ranges) {\n      mm.add(query, () => {\n        const cleanup = run({ element, config, bucket })\n        return typeof cleanup === 'function' ? cleanup : undefined\n      })\n    }\n  }\n\n  const revertAll = (): void => {\n    mm.revert()\n  }\n\n  const killAll = (): void => {\n    mm.kill()\n  }\n\n  return { bind, revertAll, killAll }\n}\n","export const NAMED_EASES: Record<string, string> = {\n  osmo: 'M0,0 C0.625,0.05 0,1 1,1',\n  energy: 'M0,0 C0.32,0.72 0,1 1,1',\n  smooth: 'M0,0 C0.38,0.005 0.215,1 1,1',\n  punch: 'M0,0 C0.19,1 0.22,1 1,1',\n  relaxed: 'M0,0 C0.7,0 0.3,1 1,1',\n  jump: 'M0,0 C0.35,1.5 0.6,1 1,1',\n  pop: 'M0,0 C0.17,0.67 0.3,1.33 1,1',\n  elastic:\n    'M0,0 C0.0127,0.0956 0.0562,0.434 0.076,0.5737 C0.0958,0.7134 0.1077,0.7761 0.1187,0.8382 C0.1297,0.9003 0.1341,0.9145 0.1419,0.9463 C0.1497,0.9781 0.1574,1.0055 0.1654,1.0292 C0.1734,1.0529 0.1814,1.0725 0.1897,1.0886 C0.198,1.1047 0.2086,1.1177 0.2153,1.1258 C0.222,1.1339 0.2248,1.1342 0.2297,1.137 C0.2346,1.1398 0.2396,1.1415 0.2448,1.1424 C0.25,1.1433 0.2554,1.1433 0.261,1.1423 C0.2666,1.1413 0.2704,1.1409 0.2786,1.1366 C0.2868,1.1323 0.2922,1.1308 0.3101,1.1165 C0.328,1.1022 0.3669,1.0665 0.3862,1.0507 C0.4055,1.0349 0.4118,1.0304 0.4257,1.0219 C0.4397,1.0134 0.4548,1.0053 0.4699,0.9995 C0.485,0.9937 0.4967,0.9898 0.5163,0.9872 C0.5359,0.9846 0.5383,0.9819 0.5877,0.9842 C0.6371,0.9865 0.7439,0.9985 0.8126,1.0011 C0.8813,1.0037 0.9688,1.0002 1,1',\n  anticipate: 'M0,0 C0.8,-0.4 0.5,1 1,1',\n  bounce:\n    'M0,0 C0.03,0 0.08,0.02 0.12,0.08 C0.18,0.2 0.22,0.5 0.28,0.85 C0.32,1.05 0.38,1.12 0.45,1.08 C0.52,1.02 0.6,0.98 0.7,1 C0.8,1.02 0.9,1 1,1',\n  fade: 'M0,0 C0.25,0.1 0.25,1 1,1',\n}\n","import { SUFFIX_KEYS, VALUE_BEARING_ATTRS } from './settings'\n\nexport type PresetEntry = string | Record<string, string>\nexport type PresetMap = Record<string, PresetEntry>\n\nexport type ResolvedPreset = Map<string, string>\n\nconst VALID_BARE_KEYS = (() => {\n  const out = new Set<string>()\n  for (const attr of VALUE_BEARING_ATTRS) {\n    const bare = attr.slice(3)\n    out.add(bare)\n    for (const bp of SUFFIX_KEYS) out.add(`${bare}-${bp}`)\n  }\n  return out\n})()\n\nconst ANIMATE_KEYS = (() => {\n  const out = ['aa-animate']\n  for (const bp of SUFFIX_KEYS) out.push(`aa-animate-${bp}`)\n  return out\n})()\n\nfunction normalise(value: PresetEntry, warnUnknown?: (key: string) => void): ResolvedPreset {\n  const out: ResolvedPreset = new Map()\n  if (typeof value === 'string') {\n    out.set('aa-animate', value)\n    return out\n  }\n  for (const [bareKey, v] of Object.entries(value)) {\n    if (!VALID_BARE_KEYS.has(bareKey)) {\n      warnUnknown?.(bareKey)\n      continue\n    }\n    if (v == null) continue\n    out.set(`aa-${bareKey}`, String(v))\n  }\n  return out\n}\n\nfunction hasAnyAaAttr(el: Element): boolean {\n  for (const name of el.getAttributeNames()) {\n    if (name.startsWith('aa-')) return true\n  }\n  return false\n}\n\nfunction hasAnimate(resolved: ResolvedPreset): boolean {\n  for (const k of ANIMATE_KEYS) {\n    if (resolved.has(k)) return true\n  }\n  return false\n}\n\nexport function resolvePresets(\n  root: ParentNode,\n  presets: PresetMap | undefined,\n  debug = false,\n): Map<Element, ResolvedPreset> {\n  const result = new Map<Element, ResolvedPreset>()\n  if (!presets) return result\n\n  const seenUnknown = new Set<string>()\n  const warnUnknown = debug\n    ? (key: string) => {\n        if (seenUnknown.has(key)) return\n        seenUnknown.add(key)\n        console.warn(\n          `[alrdy-animate] preset key \"${key}\" is not a known aa-* attribute — ignored. Valid keys: ${[...VALID_BARE_KEYS].sort().join(', ')}`,\n        )\n      }\n    : undefined\n\n  for (const [className, value] of Object.entries(presets)) {\n    const resolved = normalise(value, warnUnknown)\n    if (resolved.size === 0) continue\n    if (!hasAnimate(resolved)) {\n      if (debug) {\n        console.warn(\n          `[alrdy-animate] preset \"${className}\" has no \"animate\" (or per-breakpoint variant) — skipped. Presets must include an aa-animate value.`,\n        )\n      }\n      continue\n    }\n    let selector: string\n    try {\n      selector = '.' + CSS.escape(className)\n    } catch {\n      continue\n    }\n    let matched = 0\n    for (const el of root.querySelectorAll(selector)) {\n      if (result.has(el)) continue\n      if (hasAnyAaAttr(el)) continue\n      result.set(el, resolved)\n      matched++\n    }\n    if (debug && matched === 0) {\n      console.warn(`[alrdy-animate] preset \"${className}\" matched 0 elements.`)\n    }\n  }\n  return result\n}\n\nexport function resolveAnimateValue(\n  el: Element,\n  presetMap: Map<Element, ResolvedPreset>,\n): string | null {\n  return el.getAttribute('aa-animate') ?? presetMap.get(el)?.get('aa-animate') ?? null\n}\n\n/**\n * Match an element against a predicate over its `aa-animate` value (and the\n * `-sm/-md/-lg/-xl` variants), consulting the preset map when the real\n * attribute is absent. Used by every feature's `elementMatches()` to decide\n * which elements in `ctx.elements` it owns.\n */\nexport function matchAnimateValue(\n  el: Element,\n  presetMap: Map<Element, ResolvedPreset>,\n  predicate: (value: string) => boolean,\n): boolean {\n  const preset = presetMap.get(el)\n  const base = el.getAttribute('aa-animate') ?? preset?.get('aa-animate') ?? null\n  if (base) {\n    for (const part of base.split('|')) {\n      if (predicate(part.trim())) return true\n    }\n  }\n  for (const bp of SUFFIX_KEYS) {\n    const key = `aa-animate-${bp}`\n    const v = el.getAttribute(key) ?? preset?.get(key) ?? null\n    if (v && predicate(v.trim())) return true\n  }\n  return false\n}\n","import type { GsapHandle } from './gsap-detect'\n\ninterface ScrollTriggerInstance {\n  kill: () => void\n}\n\ninterface ScrollTriggerLike {\n  create: (vars: Record<string, unknown>) => ScrollTriggerInstance\n}\n\n/**\n * Resolve the effective ScrollTrigger `start` for an element.\n *\n * Precedence (highest first):\n *   1. `aa-scroll-start` on the element\n *   2. `init({ scrubStart })`, but only when `aa-scrub` is set on the element\n *   3. `init({ scrollStart })`\n *\n * `scrubStart` exists so the docs/Webflow author can fire scrubbed animations\n * earlier (e.g. `top 90%`) than the snappier non-scrubbed default (e.g.\n * `top 85%`), without touching every element. Without this resolver, only the\n * `scroll` feature consulted `scrubStart`; `text`, `reveal`, and the reduced-\n * motion scrub fallback silently fell through to `scrollStart`.\n */\nexport function resolveScrollStart(\n  attrValue: string | undefined,\n  opts: { scrollStart: string; scrubStart?: string },\n  scrub: number | boolean | undefined,\n): string {\n  if (attrValue !== undefined) return attrValue\n  // `scrub === false` is an explicit opt-out (aa-scrub=\"false\" → no scrub), so\n  // it should NOT promote scrubStart. Only truthy `scrub` activates the\n  // scrub-specific start.\n  if (scrub && opts.scrubStart !== undefined) return opts.scrubStart\n  return opts.scrollStart\n}\n\nexport interface AgainTriggerOptions {\n  gsap: GsapHandle\n  trigger: Element\n  start: string\n  again: boolean\n  onPlay: () => void\n  onReset: () => void\n}\n\n/**\n * Wires the canonical \"play once on enter, optionally reset when fully\n * scrolled past going up\" trigger pair.\n *\n * The reset point is the element's natural top minus one viewport height —\n * i.e. the moment the element fully leaves the bottom of the viewport on the\n * way back. This avoids the `toggleActions: 'play none none reverse'`\n * behaviour that reverses as soon as the element re-crosses its original\n * start position, which feels too eager for entrance animations.\n *\n * Returns a function that kills the created ScrollTriggers — useful when the\n * caller needs to tear down + rebuild without waiting for a matchMedia revert\n * (e.g. SplitText auto-resplit replaces the animated DOM nodes mid-breakpoint).\n *\n * Must be called inside a `gsap.matchMedia()` scope so the created\n * ScrollTriggers are tracked and auto-cleaned on breakpoint exit / destroy().\n */\nexport function bindAgainTrigger(opts: AgainTriggerOptions): () => void {\n  const ScrollTrigger = opts.gsap.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  if (!ScrollTrigger) return () => {}\n\n  const triggers: ScrollTriggerInstance[] = []\n\n  triggers.push(\n    ScrollTrigger.create({\n      trigger: opts.trigger,\n      start: opts.start,\n      onEnter: () => opts.onPlay(),\n    }),\n  )\n\n  if (opts.again) {\n    triggers.push(\n      ScrollTrigger.create({\n        trigger: opts.trigger,\n        start: () => {\n          const rect = opts.trigger.getBoundingClientRect()\n          const matrix = new DOMMatrix(getComputedStyle(opts.trigger).transform)\n          return rect.top + window.scrollY - matrix.f - window.innerHeight\n        },\n        onLeaveBack: () => opts.onReset(),\n      }),\n    )\n  }\n\n  return () => {\n    for (const t of triggers) t.kill()\n  }\n}\n","/**\n * Shared attribute-value parsers used by every feature module.\n *\n * Each helper here was previously inlined in 7–11 places (see PR history).\n * Centralizing them keeps the parse contract — particularly the \"empty string\n * or 'true' counts as truthy\" rule for scrub — identical across features.\n */\n\nimport type { ResolvedOptions } from '../types/index'\nimport { resolveScrollStart } from './scroll-trigger'\nimport type { Config } from './settings'\n\nexport function parseNum(value: string | null | undefined, fallback: number): number {\n  if (value === undefined || value === null) return fallback\n  const n = parseFloat(value)\n  return Number.isFinite(n) ? n : fallback\n}\n\n/**\n * Parse an `aa-scrub` attribute value.\n *\n * Returns:\n *   - `undefined` — attribute absent (caller decides default behaviour)\n *   - `true`      — attribute present without value, `\"true\"`, or non-numeric\n *   - `number`    — explicit scrub lag in seconds (e.g. `aa-scrub=\"0.5\"`)\n *\n * Note: parallax treats absent as \"scrubbed by default\" — that callsite should\n * fall back with `parseScrub(value) ?? true`.\n */\nexport function parseScrub(\n  value: string | null | undefined,\n): number | true | undefined {\n  if (value === undefined || value === null) return undefined\n  if (value === '' || value === 'true') return true\n  const n = parseFloat(value)\n  return Number.isFinite(n) ? n : true\n}\n\n/**\n * Parse a boolean `aa-*` flag that overrides a global `init()` default.\n *   - absent (null/undefined) → `fallback` (the global default)\n *   - `\"false\"`               → `false`\n *   - present otherwise (`\"\"`, `\"true\"`, any value) → `true`\n */\nexport function parseBool(\n  value: string | null | undefined,\n  fallback: boolean,\n): boolean {\n  if (value === undefined || value === null) return fallback\n  return value !== 'false'\n}\n\n/**\n * Resolve an `aa-anchor` selector to the element that should anchor the\n * ScrollTrigger. Falls back to the animating element itself when no selector\n * is given or no match is found, so a malformed anchor never breaks the page.\n */\nexport function resolveAnchor(element: Element, anchor: string | undefined): Element {\n  if (!anchor) return element\n  const root = element.closest(anchor)\n  if (root) return root\n  const found = document.querySelector(anchor)\n  return found ?? element\n}\n\nconst ANIMATE_ATTRS = [\n  'aa-animate',\n  'aa-animate-sm',\n  'aa-animate-md',\n  'aa-animate-lg',\n  'aa-animate-xl',\n] as const\n\n/**\n * True when the element carries any `aa-animate*` attribute. Used by tabs +\n * modal to detect \"author wrapped their own entrance animation on this\n * panel/card\" — when true, the feature steps out of the way (the author's\n * animation owns visibility) instead of running its default cross-fade.\n */\nexport function hasAnimateAttribute(el: Element | null): boolean {\n  if (!el) return false\n  for (const attr of ANIMATE_ATTRS) {\n    if (el.hasAttribute(attr)) return true\n  }\n  return false\n}\n\n/**\n * Common animation-timing fields read from a resolved per-element `Config`.\n * Centralises the duration / delay / ease / intensity / scroll-start / scroll-end\n * / scrub / again parsing that scroll / text / reveal repeat verbatim. Parallax\n * does its own thing (scrub defaults true, scrollStart/End get `clamp(...)`-\n * wrapped) so it doesn't use this.\n */\nexport interface AnimationConfig {\n  duration: number\n  delay: number\n  ease: string\n  intensity: number\n  scrollStart: string\n  scrollEnd: string\n  scrub: number | true | undefined\n  again: boolean\n}\n\nexport function readAnimationConfig(config: Config, opts: ResolvedOptions): AnimationConfig {\n  const scrub = parseScrub(config['aa-scrub'])\n  return {\n    duration: parseNum(config['aa-duration'], opts.duration),\n    delay: parseNum(config['aa-delay'], 0),\n    ease: config['aa-ease'] ?? opts.ease,\n    intensity: parseNum(config['aa-intensity'], opts.intensity),\n    scrollEnd: config['aa-scroll-end'] ?? opts.scrollEnd,\n    scrub,\n    scrollStart: resolveScrollStart(config['aa-scroll-start'], opts, scrub),\n    again: parseBool(config['aa-again'], opts.again),\n  }\n}\n","import type { ResolvedPreset } from './presets'\nimport { VALUE_BEARING_ATTRS } from './settings'\n\nexport type FeatureName =\n  | 'appear'\n  | 'text'\n  | 'reveal'\n  | 'slices'\n  | 'parallax'\n  | 'tabs'\n  | 'marquee'\n  | 'nav'\n  | 'slider'\n  | 'modal'\n  | 'split'\n  | 'hover'\n  | 'cursor'\n  | 'stack'\n\nexport interface ScanResult {\n  elements: Element[]\n  features: Set<FeatureName>\n  /**\n   * Some element the hover feature will process resolves to the `text` head\n   * (char/word lift) in some breakpoint segment — the only hover effect that\n   * needs SplitText. Detected during this pass so init doesn't re-walk the DOM.\n   */\n  needsHoverSplit: boolean\n  /**\n   * A `text-*` element resolves to a **line** split (line-default animation, or\n   * `aa-split` naming lines). Only line splits depend on correct font metrics\n   * up front — line wrapping changes when the webfont swaps. init() awaits\n   * `document.fonts.ready` only when this is set, so char/word-only and\n   * non-text pages aren't delayed.\n   */\n  needsFontMetrics: boolean\n}\n\n// text-* animations whose default split is `lines` (mirror the line-defaulting\n// entries in features/text TEXT_ANIMS — slide/tilt/oval/rotate and the bar\n// reveals block/marker). Char/word defaults (fade/blur/scale) are absent.\nconst LINE_DEFAULT_TEXT = /^text-(slide|tilt|oval|rotate|block|marker)/\n\n// True when a text element resolves to a line split (needs real-font metrics).\n// `aa-split` wins over the animation default: an explicit `lines` forces line\n// metrics; an explicit `chars`/`words` opts out even on a line-default anim.\nfunction textWantsLineMetrics(animateValue: string | null, splitValue: string | null): boolean {\n  if (!animateValue) return false\n  const head = animateValue.split('|')[0].trim()\n  if (!head.startsWith('text-')) return false\n  if (splitValue) {\n    const tokens = splitValue.toLowerCase().split(/[\\s|]+/)\n    if (tokens.includes('lines')) return true\n    if (tokens.includes('chars') || tokens.includes('words')) return false\n  }\n  return LINE_DEFAULT_TEXT.test(head)\n}\n\nconst HOVER_ATTRS = ['aa-hover', 'aa-hover-sm', 'aa-hover-md', 'aa-hover-lg', 'aa-hover-xl'] as const\n\n// The hover feature requires a base `aa-hover` to process an element (see\n// hover/index.ts `elementMatches`), so suffix-only hover never runs — gate on\n// the base attr, then check base + suffixes for the `text` head.\nfunction hoverWantsSplitText(el: Element): boolean {\n  if (!el.hasAttribute('aa-hover')) return false\n  for (const attr of HOVER_ATTRS) {\n    const v = el.getAttribute(attr)\n    if (v && v.split('|').some((part) => part.trim().split(/\\s+/)[0] === 'text')) return true\n  }\n  return false\n}\n\nconst ANIMATE_TO_FEATURE: Array<[RegExp, FeatureName]> = [\n  [/^text-/, 'text'],\n  [/^parallax/, 'parallax'],\n  [/^reveal/, 'reveal'],\n  [/^slices/, 'slices'],\n]\n\nexport function classifyAnimateValue(value: string | null): FeatureName {\n  if (!value) return 'appear'\n  const head = value.split('|')[0].trim()\n  for (const [pattern, feature] of ANIMATE_TO_FEATURE) {\n    if (pattern.test(head)) return feature\n  }\n  return 'appear'\n}\n\n// Anchor attribute → feature name. Iteration order doesn't matter; classification\n// runs once per element across whichever anchor attrs it carries.\nconst ANCHOR_TO_FEATURE: ReadonlyArray<[string, FeatureName]> = [\n  ['aa-tabs', 'tabs'],\n  ['aa-marquee', 'marquee'],\n  ['aa-nav', 'nav'],\n  ['aa-slider', 'slider'],\n  ['aa-modal-group', 'modal'],\n  ['aa-modal-name', 'modal'],\n  ['aa-modal-target', 'modal'],\n  ['aa-split', 'split'],\n  ['aa-hover', 'hover'],\n  ['aa-cursor', 'cursor'],\n  ['aa-stack', 'stack'],\n]\n\nexport function scan(\n  root: ParentNode = document,\n  presetMap: Map<Element, ResolvedPreset> = new Map(),\n): ScanResult {\n  const features = new Set<FeatureName>()\n  const elements = new Set<Element>()\n  let needsHoverSplit = false\n  let needsFontMetrics = false\n\n  // Single combined selector — one tree walk instead of 1 + 10. Classify by\n  // attribute presence in JS.\n  const combinedSelector = [\n    ...VALUE_BEARING_ATTRS.map((a) => `[${a}]`),\n    ...ANCHOR_TO_FEATURE.map(([a]) => `[${a}]`),\n  ].join(',')\n\n  for (const el of root.querySelectorAll(combinedSelector)) {\n    elements.add(el)\n    const animateValue = el.getAttribute('aa-animate')\n    if (animateValue !== null) features.add(classifyAnimateValue(animateValue))\n    for (const [attr, feature] of ANCHOR_TO_FEATURE) {\n      if (el.hasAttribute(attr)) features.add(feature)\n    }\n    if (!needsHoverSplit && hoverWantsSplitText(el)) needsHoverSplit = true\n    if (!needsFontMetrics && textWantsLineMetrics(animateValue, el.getAttribute('aa-split'))) {\n      needsFontMetrics = true\n    }\n  }\n\n  // Preset-resolved elements have no `aa-*` attributes (resolvePresets skips\n  // any element that already has one), so they won't be in the query above.\n  // Fold them in and classify by their virtual aa-animate value.\n  for (const [el, resolved] of presetMap) {\n    elements.add(el)\n    const animateValue = resolved.get('aa-animate') ?? null\n    if (animateValue !== null) features.add(classifyAnimateValue(animateValue))\n    if (!needsFontMetrics && textWantsLineMetrics(animateValue, resolved.get('aa-split') ?? null)) {\n      needsFontMetrics = true\n    }\n  }\n\n  return { elements: Array.from(elements), features, needsHoverSplit, needsFontMetrics }\n}\n","import type { Breakpoints } from '../types/index'\nimport { resolveAttrAtWidth, type ValueAttr } from './settings'\n\nexport type TriggerKind = 'scroll' | 'event' | 'click' | 'load-once' | 'load' | 'lcp'\n\nexport interface ParsedTrigger {\n  kind: TriggerKind\n  eventName?: string\n}\n\n/**\n * Load-timed kinds that fire on *every* init via the paused → load-gate →\n * paint-release path. `load-once` is deliberately excluded — it runs the same\n * gate but only on the first init, so callers gate it separately on\n * `firstInit`. Centralised so adding another load-timed kind (e.g. a future\n * `lcp`-like one) is a single edit instead of a grep across feature modules.\n */\nexport function isLoadKind(kind: TriggerKind): boolean {\n  return kind === 'load' || kind === 'lcp'\n}\n\nexport const CUSTOM_EVENT_NAME = 'aa:trigger'\n\n// Modal vocabulary lives here (core already encodes the modal-active event and\n// the card selector in INFERENCE_CONTAINERS) so the gate (viewport-gate.ts) and\n// the modal feature (modal/state.ts) share one definition instead of drifting.\nexport const MODAL_CARD_SELECTOR = '[aa-modal-name]'\nexport const MODAL_STATUS_ATTR = 'aa-modal-status'\n\n/**\n * Multiplier applied to event-triggered animations on reverse, so the\n * exit feels snappier than the entrance (matches v7's 2× reverse).\n * Forward = 1, reverse = `REVERSE_TIME_SCALE`. Consumers reset to 1 on\n * forward so the scale doesn't leak between cycles.\n */\nexport const REVERSE_TIME_SCALE = 2\n\n/**\n * Ease curve used on reverse via GSAP 3.15's `easeReverse`. A flat curve\n * keeps exits clean — without it, eases like `anticipate`/`bounce` play\n * their dip/overshoot at the END of the reverse, which reads as a glitch.\n */\nexport const REVERSE_EASE = 'power2.inOut'\n\nfunction parseOne(token: string): ParsedTrigger | null {\n  if (token === 'scroll') return { kind: 'scroll' }\n  if (token === 'click') return { kind: 'click' }\n  if (token === 'load-once') return { kind: 'load-once' }\n  if (token === 'load') return { kind: 'load' }\n  // `lcp` is a load-timed entrance optimised as the Largest Contentful Paint\n  // element: the companion CSS paints it immediately at ~0.01 opacity (an\n  // eligible LCP candidate, before the bundle) and the appear feature fades it\n  // to full. Timing-wise it behaves like `load` (see triggered-animation.ts).\n  if (token === 'lcp') return { kind: 'lcp' }\n  if (token.startsWith('event:')) {\n    return { kind: 'event', eventName: token.slice('event:'.length) }\n  }\n  return null\n}\n\n/**\n * Parse `aa-trigger` into one or more ParsedTriggers. Multiple values are\n * space-separated, e.g. `aa-trigger=\"load event:enter\"` means \"fire on the\n * very first init via load, then on every subsequent `aa:trigger` event with\n * `detail.name === 'enter'` thereafter.\" See feature implementations for how\n * the combination is resolved (load owns the first init cycle; non-load\n * triggers wire on subsequent inits).\n */\nexport function parseTriggers(value: string | undefined): ParsedTrigger[] {\n  if (!value) return [{ kind: 'scroll' }]\n  const trimmed = value.trim()\n  if (trimmed === '') return [{ kind: 'scroll' }]\n  const parts = trimmed.split(/\\s+/)\n  const triggers: ParsedTrigger[] = []\n  for (const part of parts) {\n    const parsed = parseOne(part)\n    if (parsed) triggers.push(parsed)\n  }\n  return triggers.length > 0 ? triggers : [{ kind: 'scroll' }]\n}\n\nexport function parseTrigger(value: string | undefined): ParsedTrigger {\n  return parseTriggers(value)[0]\n}\n\n/**\n * Containers that auto-emit lifecycle events on their items. An animation\n * inside one of these inherits the matching event trigger unless it sets an\n * explicit `aa-trigger` value.\n *\n * Order matters: the *closest* match wins, which is the right call for nested\n * components (e.g. tabs inside a slider — tab-active beats slide-active\n * because it's closer to the animated element).\n *\n * `rootSelector` + `enableAttr` let inference skip a container whose feature is\n * responsively disabled (`none`) at the current breakpoint — it never inits, so\n * inheriting its event would strand the inner animation paused forever. Modal\n * has no per-breakpoint disable, so it carries no enable mapping.\n */\nconst INFERENCE_CONTAINERS: ReadonlyArray<{\n  selector: string\n  eventName: string\n  rootSelector?: string\n  enableAttr?: ValueAttr\n}> = [\n  { selector: MODAL_CARD_SELECTOR, eventName: 'modal-active' },\n  { selector: '[aa-tabs-content]', eventName: 'tab-active', rootSelector: '[aa-tabs]', enableAttr: 'aa-tabs' },\n  { selector: '[aa-tabs-visual]', eventName: 'tab-active', rootSelector: '[aa-tabs]', enableAttr: 'aa-tabs' },\n  { selector: '[aa-slider-item]', eventName: 'slide-active', rootSelector: '[aa-slider]', enableAttr: 'aa-slider' },\n  { selector: '[aa-stack-card]', eventName: 'card-active', rootSelector: '[aa-stack]', enableAttr: 'aa-stack' },\n]\n\n// True when the container won't ever emit its event, so inference must skip it\n// and fall through to the next container (or scroll). Two cases:\n//   1. Orphan — the container has a `rootSelector` but no matching ancestor\n//      (e.g. a stray `aa-stack-card` left inside a modal with no `aa-stack`).\n//      The owning feature never inits on it, so its event never fires; treating\n//      it as active would strand the inner animation paused forever.\n//   2. Responsively disabled — the owning root resolves to `none` at the current\n//      width, so the feature skips it this breakpoint.\n// Containers without a `rootSelector` (modal) are always active.\nfunction containerDisabled(\n  container: Element,\n  def: { rootSelector?: string; enableAttr?: ValueAttr },\n  breakpoints: Breakpoints | undefined,\n): boolean {\n  if (!def.rootSelector) return false\n  const root = container.closest(def.rootSelector)\n  if (!root) return true\n  if (!breakpoints || !def.enableAttr) return false\n  const value = resolveAttrAtWidth(root, def.enableAttr, window.innerWidth, breakpoints)\n  return value !== undefined && value.trim().split(/\\s+/).includes('none')\n}\n\n/**\n * Resolve the trigger(s) for an animated element.\n *\n * If the user set `aa-trigger` explicitly, that wins (this is the escape\n * hatch — `aa-trigger=\"scroll\"` forces scroll behavior even inside a\n * container, and explicit values may be a space-separated list). Otherwise,\n * walk up the DOM looking for a known container ancestor and return the\n * matching event trigger. Default is scroll.\n *\n * Pass `breakpoints` so inference can skip a container whose feature is\n * responsively disabled at the current width (e.g. `aa-stack=\"|none\"` on\n * mobile) — without it the inner animation would inherit an event that the\n * disabled feature never emits and never play.\n */\nexport function resolveTriggers(\n  element: Element,\n  explicit: string | undefined,\n  breakpoints?: Breakpoints,\n): ParsedTrigger[] {\n  if (explicit !== undefined && explicit.trim() !== '') return parseTriggers(explicit)\n\n  // Find the closest *active* container ancestor across all known patterns. We\n  // compute the matched element for each, skip any whose feature is disabled at\n  // this breakpoint, then pick the deepest survivor (the one that doesn't\n  // contain any of the others).\n  let best: { container: Element; eventName: string } | null = null\n  for (const def of INFERENCE_CONTAINERS) {\n    const match = element.closest(def.selector)\n    if (!match) continue\n    if (containerDisabled(match, def, breakpoints)) continue\n    if (!best || best.container.contains(match)) {\n      best = { container: match, eventName: def.eventName }\n    }\n  }\n\n  if (best) return [{ kind: 'event', eventName: best.eventName }]\n  return [{ kind: 'scroll' }]\n}\n\nexport function resolveTrigger(\n  element: Element,\n  explicit: string | undefined,\n  breakpoints?: Breakpoints,\n): ParsedTrigger {\n  return resolveTriggers(element, explicit, breakpoints)[0]\n}\n\ntype Listener = (element: Element, eventName: string) => void\n\nconst listeners = new Set<Listener>()\nlet attached = false\n\nfunction onCustomEvent(e: Event): void {\n  if (!(e instanceof CustomEvent) || !e.target) return\n  const detail = e.detail as { name?: string } | undefined\n  const name = detail?.name\n  if (!name) return\n  for (const fn of listeners) fn(e.target as Element, name)\n}\n\nfunction ensureAttached(): void {\n  if (attached) return\n  if (typeof document === 'undefined') return\n  document.addEventListener(CUSTOM_EVENT_NAME, onCustomEvent)\n  attached = true\n}\n\nexport function onCustomTrigger(fn: Listener): () => void {\n  ensureAttached()\n  listeners.add(fn)\n  return () => {\n    listeners.delete(fn)\n    if (listeners.size === 0 && attached && typeof document !== 'undefined') {\n      document.removeEventListener(CUSTOM_EVENT_NAME, onCustomEvent)\n      attached = false\n    }\n  }\n}\n\nexport function emitTrigger(target: EventTarget, name: string): void {\n  target.dispatchEvent(new CustomEvent(CUSTOM_EVENT_NAME, { detail: { name }, bubbles: true }))\n}\n\n/**\n * Names ending in `-active` pair with the same name ending in `-inactive` for\n * reverse. e.g. `slide-active` ↔ `slide-inactive`. Returning null means no\n * paired reverse event.\n */\nexport function pairedReverseName(eventName: string): string | null {\n  return eventName.endsWith('-active')\n    ? eventName.slice(0, -'-active'.length) + '-inactive'\n    : null\n}\n\nexport interface PairedTriggerHandlers {\n  element: Element\n  forwardName: string\n  onForward: () => void\n  onReverse?: () => void\n}\n\n/**\n * Subscribe to a forward event and (when the name ends in `-active`) the\n * matching `-inactive` reverse event. Filters by element ancestry so animations\n * only react to events emitted on themselves or an ancestor.\n */\nexport function subscribeWithPair({\n  element,\n  forwardName,\n  onForward,\n  onReverse,\n}: PairedTriggerHandlers): () => void {\n  const reverseName = onReverse ? pairedReverseName(forwardName) : null\n  return onCustomTrigger((target, name) => {\n    if (target !== element && !target.contains(element)) return\n    if (name === forwardName) onForward()\n    else if (reverseName && name === reverseName && onReverse) onReverse()\n  })\n}\n","import type { ReducedMotionOptions, ResolvedOptions } from '../types/index'\nimport type { GsapHandle, GsapTween } from './gsap-detect'\nimport { parseNum, parseScrub } from './parse'\nimport { resolveAnimateValue, type ResolvedPreset } from './presets'\nimport { classifyAnimateValue, type FeatureName } from './scanner'\nimport { resolveScrollStart } from './scroll-trigger'\nimport { isLoadKind, onCustomTrigger, resolveTriggers } from './trigger'\n\n/**\n * Single global fade-fallback pass. Whichever conditions trigger it\n * (`reducedMotion` OS preference, or `optimizeMobile` viewport check), the\n * mechanism is the same: bypass per-feature matchMedia binding, SplitText\n * runtime, slice-panel DOM, and clip-path tweening — replace every targeted\n * decorative element with a single opacity tween.\n *\n * The caller decides WHICH features get replaced via two complementary sets\n * passed into the pass:\n *   - `featuresToReplace` — feature modules that will NOT be loaded\n *   - `fadeFor` — subset of those whose elements should still get a fade\n *\n * Examples:\n *   reducedMotion active:\n *     featuresToReplace = {appear, text, reveal, hover, parallax}\n *     fadeFor           = {appear, text, reveal}        // hover + parallax stay still\n *\n *   optimizeMobile + small viewport:\n *     featuresToReplace = {text, parallax, split}\n *     fadeFor           = {text}                        // parallax stays still\n *\n * Cost shape vs. normal motion:\n *   normal           → N modules imported · M matchMedia contexts · split DOM mutations\n *   fade-fallback    → 0 replaced modules · M plain gsap tweens · 0 DOM mutations\n */\n\nexport interface FadeFallbackDeps {\n  gsap: GsapHandle\n  options: ResolvedOptions\n  reducedMotion: ReducedMotionOptions\n  firstInit: boolean\n  /**\n   * Set of feature names whose elements should be processed by this fade\n   * pass. Other elements are ignored even if they're in the `elements`\n   * array — they belong to features that are still loading normally.\n   */\n  fadeFor: ReadonlySet<FeatureName>\n  /**\n   * Class → preset resolution. Lets the fade pass look up `aa-animate` for\n   * preset elements that have no real attribute on them. Pass an empty map\n   * when no `presets` option was set.\n   */\n  presetMap: Map<Element, ResolvedPreset>\n  /**\n   * Same paint-gated load-start hook as `FeatureContext.deferLoadStart`. The\n   * fade pass's `load` entrances are built `paused` and handed here so they\n   * don't advance during the post-init paint block, matching the main path.\n   */\n  deferLoadStart: (tween: GsapTween) => void\n}\n\n/**\n * Run the fade-fallback pass. Returns a disposer that reverts every tween +\n * listener created here.\n */\nexport function runFadeFallbackPass(\n  elements: Element[],\n  deps: FadeFallbackDeps,\n): () => void {\n  const { gsap: gsapHandle, options, reducedMotion, firstInit, fadeFor, presetMap, deferLoadStart } =\n    deps\n  const { duration, ease } = reducedMotion\n  const fromState = { opacity: 0 } as const\n  const toState = { opacity: 1 } as const\n  const listenerDisposers: Array<() => void> = []\n\n  // Same precedence as everywhere else: real attribute wins, preset map fills\n  // holes. Lets preset elements participate in the fade-fallback pass.\n  const getAttr = (element: Element, name: string): string | null => {\n    const real = element.getAttribute(name)\n    if (real !== null) return real\n    return presetMap.get(element)?.get(name) ?? null\n  }\n\n  // gsap.context() captures every tween + ScrollTrigger created inside it,\n  // so a single ctx.revert() at destroy time cleans up the whole pass.\n  // Custom event listeners (aa-trigger=\"event:...\") are tracked separately.\n  const gsapCtx = gsapHandle.gsap.context(() => {\n    for (const element of elements) {\n      const animateValue = resolveAnimateValue(element, presetMap)\n      if (!animateValue) continue\n      const classified = classifyAnimateValue(animateValue)\n      if (!fadeFor.has(classified)) continue\n\n      const delay = parseNum(getAttr(element, 'aa-delay'), 0)\n      const scrollEnd = getAttr(element, 'aa-scroll-end') ?? options.scrollEnd\n      const scrub = parseScrub(getAttr(element, 'aa-scrub'))\n      const scrollStart = resolveScrollStart(\n        getAttr(element, 'aa-scroll-start') ?? undefined,\n        options,\n        scrub,\n      )\n      const triggers = resolveTriggers(\n        element,\n        getAttr(element, 'aa-trigger') ?? undefined,\n        options.breakpoints,\n      )\n      const hasLoadOnce = triggers.some((t) => t.kind === 'load-once')\n      const hasLoad = triggers.some((t) => isLoadKind(t.kind))\n\n      if ((hasLoadOnce && firstInit) || hasLoad) {\n        // aa-fallback signals the inline-snippet timeout already faded the\n        // element in via CSS; running our tween now would rewind it through\n        // the from-state and flash. The end-of-init aa-ready flip still\n        // happens, keeping DOM consistent.\n        if (document.documentElement.hasAttribute('aa-fallback')) continue\n        // Built `paused` and handed to the load gate (same rationale as the\n        // main triggered path) — released after first paint so the fade\n        // doesn't advance during the post-init paint block.\n        const tween = gsapHandle.gsap.fromTo(element, fromState, {\n          ...toState,\n          duration,\n          ease,\n          delay: delay + options.loadDelay,\n          paused: true,\n        })\n        deferLoadStart(tween)\n        continue\n      }\n\n      const trigger = triggers.find((t) => t.kind !== 'load-once' && !isLoadKind(t.kind))\n      if (!trigger) continue\n\n      if (trigger.kind === 'event' && trigger.eventName) {\n        gsapHandle.gsap.set(element, fromState)\n        const eventName = trigger.eventName\n        const off = onCustomTrigger((target, name) => {\n          if (name !== eventName) return\n          if (target !== element && !target.contains(element)) return\n          gsapHandle.gsap.to(element, { ...toState, duration, ease, delay })\n        })\n        listenerDisposers.push(off)\n        continue\n      }\n\n      if (scrub !== undefined) {\n        gsapHandle.gsap.fromTo(element, fromState, {\n          ...toState,\n          duration,\n          ease,\n          delay,\n          scrollTrigger: {\n            trigger: element,\n            start: scrollStart,\n            end: scrollEnd,\n            scrub,\n          },\n        })\n        continue\n      }\n\n      gsapHandle.gsap.fromTo(element, fromState, {\n        ...toState,\n        duration,\n        ease,\n        delay,\n        scrollTrigger: {\n          trigger: element,\n          start: scrollStart,\n          // No end / again handling — fade-fallback already minimises motion;\n          // a single play on enter is the calmest read.\n          toggleActions: 'play none none none',\n        },\n      })\n    }\n  })\n\n  return () => {\n    for (const off of listenerDisposers) {\n      try {\n        off()\n      } catch {\n        // ignore\n      }\n    }\n    try {\n      gsapCtx.revert()\n    } catch {\n      // ignore — pre-destroyed or partial init\n    }\n  }\n}\n\n/**\n * Decorative feature modules that `reducedMotion: true` replaces with the\n * unified fade pass when the OS reports `(prefers-reduced-motion: reduce)`.\n */\nexport const REDUCED_MOTION_REPLACED_FEATURES: ReadonlySet<FeatureName> = new Set([\n  'appear',\n  'text',\n  'reveal',\n  'parallax',\n  'hover',\n])\n\n/**\n * Subset of `REDUCED_MOTION_REPLACED_FEATURES` whose elements still get a\n * fade. Hover and parallax are no-ops under reduced motion (no fade — they\n * just don't animate).\n */\nexport const REDUCED_MOTION_FADE_FEATURES: ReadonlySet<FeatureName> = new Set([\n  'appear',\n  'text',\n  'reveal',\n])\n\n/**\n * The heaviest features for mobile: SplitText-driven text animations,\n * continuously-repainting parallax, and the standalone aa-split utility\n * (which also pulls in SplitText). Triggered by `optimizeMobile: true` when\n * the viewport is below `breakpoints.md`.\n */\nexport const OPTIMIZE_MOBILE_REPLACED_FEATURES: ReadonlySet<FeatureName> = new Set([\n  'text',\n  'parallax',\n  'split',\n])\n\n/**\n * Subset of `OPTIMIZE_MOBILE_REPLACED_FEATURES` whose elements still get a\n * fade — but only under `optimizeMobile: 'fade'`. Under `optimizeMobile: true`\n * the selector in `core/index.ts` treats the fade set as empty, so text is\n * simply made visible. Parallax stays still (no transform); aa-split is a\n * utility, not an animation, so its elements get nothing.\n */\nexport const OPTIMIZE_MOBILE_FADE_FEATURES: ReadonlySet<FeatureName> = new Set([\n  'text',\n])\n","import type {\n  ReducedMotionOptions,\n  ResizeCallback,\n  ResizeUnsubscribe,\n  ResolvedOptions,\n} from '../types/index'\nimport type { GsapHandle, GsapTween } from './gsap-detect'\nimport type { ResponsiveController } from './match-media'\nimport type { ResolvedPreset } from './presets'\nimport type { FeatureName } from './scanner'\nimport { readAttrs, type Config, type ResolvedAttrs } from './settings'\n\nexport interface FeatureContext {\n  gsap: GsapHandle\n  responsive: ResponsiveController\n  elements: Element[]\n  options: ResolvedOptions\n  debug: boolean\n  /**\n   * True iff this is the *first* init() call in the page session. Reset only\n   * by a hard reload — survives every destroy() / re-init cycle. Features use\n   * it to decide whether `aa-trigger=\"load-once\"` should fire (first init only)\n   * or fall through to the element's other triggers.\n   */\n  firstInit: boolean\n  /**\n   * Snapshot of `(prefers-reduced-motion: reduce)` taken at init time, gated by\n   * `options.reducedMotion`. `null` means \"no reduced-motion fallback applies\"\n   * (either the user opted out via `reducedMotion: false` or the OS preference\n   * is off). When non-null, appear/text/reveal features collapse to a simple\n   * opacity fade with these timing values; hover and parallax skip entirely.\n   */\n  reducedMotion: ReducedMotionOptions | null\n  /**\n   * Class → animation preset resolution for this init. Elements only appear\n   * here when (a) their class matched an `init({ presets })` entry and (b)\n   * they have no `aa-*` attribute (the element's own attribute always wins).\n   * Features pass `presetMap.get(el)` into `readAttrs()` as a fallback\n   * attribute source and use `matchAnimateValue()` in their element matchers.\n   */\n  presetMap: Map<Element, ResolvedPreset>\n  onResize: (fn: ResizeCallback, debounce?: number) => ResizeUnsubscribe\n  /**\n   * Register a `load` / `load-once` entrance tween to start *after* the\n   * browser's first paint of the revealed (from-state) element, rather than\n   * autoplaying during init(). The feature builds the tween `paused` and hands\n   * it here; init() releases all registered tweens (via `restart(true)`, which\n   * replays from time 0 including the full delay) one paint after the aa-ready\n   * reveal. This stops a wall-clock tween from advancing during the heavy\n   * post-init layout/paint block and \"popping in\" already mid-fade.\n   * Registration is a no-op once destroy() has cancelled the gate.\n   */\n  deferLoadStart: (tween: GsapTween) => void\n}\n\nexport interface FeatureModule {\n  name: FeatureName\n  init: (ctx: FeatureContext) => () => void\n}\n\ntype Loader = () => Promise<{ default: FeatureModule }>\n\nconst loaders: Record<FeatureName, Loader> = {\n  appear: () => import('../features/appear/index'),\n  text: () => import('../features/text/index'),\n  reveal: () => import('../features/appear/reveal'),\n  slices: () => import('../features/appear/slices'),\n  parallax: () => import('../features/parallax/index'),\n  tabs: () => import('../features/tabs/index'),\n  marquee: () => import('../features/marquee/index'),\n  nav: () => import('../features/nav/index'),\n  slider: () => import('../features/slider/index'),\n  modal: () => import('../features/modal/index'),\n  hover: () => import('../features/hover/index'),\n  cursor: () => import('../features/cursor/index'),\n  stack: () => import('../features/stack/index'),\n  split: () => import('../split/index'),\n}\n\nexport async function loadFeature(name: FeatureName): Promise<FeatureModule | null> {\n  const loader = loaders[name]\n  if (!loader) return null\n  try {\n    const mod = await loader()\n    return mod.default\n  } catch (err) {\n    console.error(`[alrdy-animate] failed to load feature: ${name}`, err)\n    return null\n  }\n}\n\nexport async function loadFeatures(names: Iterable<FeatureName>): Promise<FeatureModule[]> {\n  const modules = await Promise.all([...names].map(loadFeature))\n  return modules.filter((m): m is FeatureModule => m !== null)\n}\n\n/**\n * Standard feature init shape: filter `ctx.elements` to those this feature\n * owns, then bind each through `ctx.responsive` so per-breakpoint configs are\n * routed correctly and matchMedia teardown is automatic.\n *\n * It exists for the per-element appearance features (appear, text, reveal,\n * parallax) whose init bodies were byte-for-byte identical. Whole-root\n * features (tabs, slider, marquee, stack, modal) use `bindRootFeature` below.\n */\nexport function bindFeature(\n  ctx: FeatureContext,\n  matches: (el: Element, presetMap: Map<Element, ResolvedPreset>) => boolean,\n  setupOne: (ctx: FeatureContext, element: Element, config: Config) => (() => void) | undefined,\n): void {\n  const subjects = ctx.elements.filter((el) => matches(el, ctx.presetMap))\n  for (const element of subjects) {\n    const attrs = readAttrs(element, ctx.presetMap.get(element))\n    ctx.responsive.bind(element, attrs, ({ config }) => setupOne(ctx, element, config))\n  }\n}\n\n/**\n * Whole-root feature init shape: filter `ctx.elements` to the HTMLElements\n * carrying `attr`, then bind each root through `ctx.responsive` so\n * per-breakpoint configs route correctly and matchMedia teardown is automatic.\n *\n * Mirrors `bindFeature` for the per-root features (tabs, slider, marquee,\n * stack, modal) whose init wrappers were byte-for-byte identical. Roots are\n * never preset-resolved, so attrs are read without a preset. Features needing\n * a feature-level teardown (e.g. modal's scroll-lock reset) add their own\n * `return` after calling this. `nav` keeps a bespoke init (multiple setups).\n *\n * `resolveAttrs` defaults to the root-only `readAttrs`; a feature can pass its\n * own reader to fold in attributes that live on descendants (e.g. marquee\n * merges the `aa-marquee-scroller` child's per-breakpoint buckets into the\n * root config) while keeping the shared filter + bind + teardown wiring.\n */\nexport function bindRootFeature(\n  ctx: FeatureContext,\n  attr: string,\n  setupOne: (ctx: FeatureContext, root: HTMLElement, config: Config) => (() => void) | undefined,\n  resolveAttrs: (root: HTMLElement) => ResolvedAttrs = readAttrs,\n): void {\n  const subjects = ctx.elements.filter(\n    (el): el is HTMLElement => el instanceof HTMLElement && el.hasAttribute(attr),\n  )\n  for (const root of subjects) {\n    const attrs = resolveAttrs(root)\n    ctx.responsive.bind(root, attrs, ({ config }) => setupOne(ctx, root, config))\n  }\n}\n","import type { ResizeCallback, ResizeUnsubscribe } from '../types/index'\n\ninterface Subscriber {\n  fn: ResizeCallback\n  debounce: number\n  timer: ReturnType<typeof setTimeout> | undefined\n}\n\nconst subscribers = new Set<Subscriber>()\nlet attached = false\n\nfunction dispatch(): void {\n  for (const sub of subscribers) {\n    if (sub.timer) clearTimeout(sub.timer)\n    sub.timer = setTimeout(sub.fn, sub.debounce)\n  }\n}\n\nfunction attach(): void {\n  if (attached) return\n  if (typeof window === 'undefined') return\n  window.addEventListener('resize', dispatch, { passive: true })\n  attached = true\n}\n\nfunction detachIfEmpty(): void {\n  if (subscribers.size === 0 && attached) {\n    window.removeEventListener('resize', dispatch)\n    attached = false\n  }\n}\n\nexport function subscribe(fn: ResizeCallback, debounce = 150): ResizeUnsubscribe {\n  const sub: Subscriber = { fn, debounce, timer: undefined }\n  subscribers.add(sub)\n  attach()\n  return () => {\n    if (sub.timer) clearTimeout(sub.timer)\n    subscribers.delete(sub)\n    detachIfEmpty()\n  }\n}\n\nexport function clearAll(): void {\n  for (const sub of subscribers) {\n    if (sub.timer) clearTimeout(sub.timer)\n  }\n  subscribers.clear()\n  detachIfEmpty()\n}\n","/**\n * Always-on scroll-state utilities.\n *\n * 1. Body attributes:\n *    - `aa-scroll-direction=\"up\" | \"down\"` (5px movement threshold)\n *    - `aa-scroll-started=\"true\" | \"false\"` (50px scrollY threshold)\n *\n *    Driven by a single passive scroll listener with rAF throttling. Powers\n *    the CSS-driven nav-hide rule and any user CSS that wants to react to\n *    scroll direction without writing JS.\n *\n * 2. `[aa-toggle-playstate]` IntersectionObserver:\n *    Pauses/plays each child element's Web Animations API animations when\n *    the container scrolls in or out of the viewport. Useful for stopping\n *    background CSS keyframe loops while they're off-screen.\n *\n * Both behaviors are gated together by `init({ scrollState: false })`.\n */\n\nconst DIRECTION_THRESHOLD = 5\nconst STARTED_THRESHOLD = 50\n\nfunction initScrollDirection(): () => void {\n  const body = document.body\n  let lastScrollTop = 0\n  let lastDirection: 'up' | 'down' | null = null\n  let lastStarted: 'true' | 'false' | null = null\n  let ticking = false\n\n  const apply = (): void => {\n    const currentScrollTop = window.scrollY\n    const delta = Math.abs(currentScrollTop - lastScrollTop)\n    if (delta >= DIRECTION_THRESHOLD) {\n      const direction: 'up' | 'down' = currentScrollTop > lastScrollTop ? 'down' : 'up'\n      const started: 'true' | 'false' = currentScrollTop > STARTED_THRESHOLD ? 'true' : 'false'\n      if (direction !== lastDirection) {\n        body.setAttribute('aa-scroll-direction', direction)\n        lastDirection = direction\n      }\n      if (started !== lastStarted) {\n        body.setAttribute('aa-scroll-started', started)\n        lastStarted = started\n      }\n      lastScrollTop = currentScrollTop\n    }\n    ticking = false\n  }\n\n  const onScroll = (): void => {\n    if (ticking) return\n    ticking = true\n    requestAnimationFrame(apply)\n  }\n\n  // Seed initial values so CSS rules have something to read on first paint.\n  requestAnimationFrame(() => {\n    if (!body.hasAttribute('aa-scroll-direction')) {\n      body.setAttribute('aa-scroll-direction', 'down')\n      lastDirection = 'down'\n    } else {\n      lastDirection = body.getAttribute('aa-scroll-direction') as 'up' | 'down'\n    }\n    const started: 'true' | 'false' = window.scrollY > STARTED_THRESHOLD ? 'true' : 'false'\n    body.setAttribute('aa-scroll-started', started)\n    lastStarted = started\n    lastScrollTop = window.scrollY\n  })\n\n  window.addEventListener('scroll', onScroll, { passive: true })\n\n  return () => {\n    window.removeEventListener('scroll', onScroll)\n    body.removeAttribute('aa-scroll-direction')\n    body.removeAttribute('aa-scroll-started')\n  }\n}\n\nfunction initPlayStateObserver(): () => void {\n  const elements = document.querySelectorAll<HTMLElement>('[aa-toggle-playstate]')\n  if (elements.length === 0) return () => {}\n\n  const observer = new IntersectionObserver((entries) => {\n    for (const entry of entries) {\n      const children = (entry.target as HTMLElement).children\n      for (const child of Array.from(children)) {\n        const animations = (child as HTMLElement).getAnimations?.() ?? []\n        for (const animation of animations) {\n          if (entry.isIntersecting) animation.play()\n          else animation.pause()\n        }\n      }\n    }\n  })\n\n  for (const el of elements) observer.observe(el)\n\n  return () => observer.disconnect()\n}\n\nexport function initScrollState(): () => void {\n  if (typeof window === 'undefined') return () => {}\n  const directionDispose = initScrollDirection()\n  const playStateDispose = initPlayStateObserver()\n  return () => {\n    directionDispose()\n    playStateDispose()\n  }\n}\n","/**\n * Click-to-scroll handler for `[aa-scroll-target]` elements.\n *\n * Always installed at init() time, regardless of smoothScroll setting:\n *\n * - If `window.lenis` exists at click time, scroll via Lenis with the v7\n *   quartic easing for parity with existing alrdy projects.\n * - Otherwise fall back to native `window.scrollTo({ behavior: 'smooth' })`,\n *   which still honours the `aa-scroll-offset` offset.\n *\n * Per-element listeners (not delegated) so we can `preventDefault()` the\n * anchor click cleanly and remove them all on destroy.\n */\n\nimport { parseNum } from './parse'\n\nconst QUART_EASE = (x: number): number =>\n  x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2\n\nconst DEFAULT_DURATION = 1.2\n\nexport function initScrollTarget(): () => void {\n  if (typeof window === 'undefined') return () => {}\n\n  const elements = document.querySelectorAll<HTMLElement>('[aa-scroll-target]')\n  if (elements.length === 0) return () => {}\n\n  const listeners: Array<{ el: HTMLElement; fn: (e: Event) => void }> = []\n\n  for (const el of elements) {\n    const fn = (e: Event): void => {\n      const targetSelector = el.getAttribute('aa-scroll-target')\n      if (!targetSelector) return\n      const target = document.querySelector(targetSelector)\n      if (!target) return\n      e.preventDefault()\n      const duration = parseNum(el.getAttribute('aa-duration'), DEFAULT_DURATION)\n      const offset = parseNum(el.getAttribute('aa-scroll-offset'), 0)\n      const lenis = window.lenis\n      if (lenis) {\n        lenis.scrollTo(targetSelector, { offset, duration, easing: QUART_EASE })\n        return\n      }\n      const top = (target as HTMLElement).getBoundingClientRect().top + window.scrollY + offset\n      window.scrollTo({ top, behavior: 'smooth' })\n    }\n    el.addEventListener('click', fn)\n    listeners.push({ el, fn })\n  }\n\n  return () => {\n    for (const { el, fn } of listeners) el.removeEventListener('click', fn)\n  }\n}\n","import type {\n  AutoplayOptions,\n  Breakpoints,\n  InitOptions,\n  ReducedMotionOptions,\n  ResolvedOptions,\n  StaggerOptions,\n} from '../types/index'\nimport type { ResolvedPreset } from './presets'\nimport type { SmoothScrollHandle } from '../smooth-scroll/index'\n\nexport const DEFAULT_BREAKPOINTS: Breakpoints = {\n  sm: 480,\n  md: 768,\n  lg: 992,\n  xl: 1280,\n}\n\nconst DEFAULT_STAGGER: StaggerOptions = {\n  chars: 0.02,\n  words: 0.05,\n  lines: 0.1,\n  default: 0.1,\n}\n\nconst DEFAULT_AUTOPLAY: AutoplayOptions = {\n  interval: 4,\n  hoverPause: false,\n}\n\nexport const DEFAULT_REDUCED_MOTION: ReducedMotionOptions = {\n  duration: 0.4,\n  ease: 'power1.out',\n}\n\n/**\n * Timing for `optimizeMobile: 'fade'`. Softer/slower than the reduced-motion\n * fallback so a mobile text fade doesn't look abrupt next to already-static\n * content. (`optimizeMobile: true` skips the fade entirely.)\n */\nexport const DEFAULT_OPTIMIZE_MOBILE_FADE: ReducedMotionOptions = {\n  duration: 0.8,\n  ease: 'power2.out',\n}\n\n/**\n * Single source of truth for init-time defaults. Features must NOT carry\n * their own per-animation duration / ease / stagger fallbacks — they always\n * pull from `ctx.options`, which is `ResolvedOptions` (every field populated\n * after resolveOptions has merged these defaults).\n */\nexport const DEFAULT_OPTIONS: ResolvedOptions = {\n  duration: 0.6,\n  ease: 'power4.out',\n  intensity: 1,\n  loadDelay: 0,\n  scrollStart: 'top 85%',\n  scrollEnd: 'bottom 60%',\n  again: true,\n  stagger: DEFAULT_STAGGER,\n  autoplay: DEFAULT_AUTOPLAY,\n  breakpoints: DEFAULT_BREAKPOINTS,\n  smoothScroll: true,\n  scrollState: true,\n  reducedMotion: true,\n  optimizeMobile: false,\n}\n\nfunction resolveReducedMotion(\n  input: InitOptions['reducedMotion'],\n): boolean | ReducedMotionOptions {\n  if (input === false) return false\n  if (input === undefined || input === true) return true\n  return { ...DEFAULT_REDUCED_MOTION, ...input }\n}\n\nexport function resolveOptions(opts: InitOptions): ResolvedOptions {\n  return {\n    ...DEFAULT_OPTIONS,\n    ...opts,\n    stagger: { ...DEFAULT_STAGGER, ...opts.stagger },\n    autoplay: { ...DEFAULT_AUTOPLAY, ...opts.autoplay },\n    breakpoints: { ...DEFAULT_BREAKPOINTS, ...opts.breakpoints },\n    reducedMotion: resolveReducedMotion(opts.reducedMotion),\n  }\n}\n\nexport interface InternalState {\n  initialized: boolean\n  options: ResolvedOptions\n  breakpoints: Breakpoints\n  /**\n   * Per-init feature disposers — torn down on every destroy() call. Anything\n   * scoped to the current page's content (matchMedia revert, ScrollTrigger\n   * cleanup, individual feature inits) goes here.\n   */\n  disposers: Array<() => void>\n  /**\n   * App-global handles that can survive `destroy({ keepGlobals: true })`.\n   * Lenis, scroll-state, and scroll-target are all bound to elements that\n   * persist across page transitions (`document.documentElement`, `<body>`),\n   * so re-creating them on every Barba/Next.js route change is wasteful and\n   * costs scroll-position state.\n   */\n  smoothScroll: SmoothScrollHandle | null\n  scrollStateDispose: (() => void) | null\n  scrollTargetDispose: (() => void) | null\n  /**\n   * Set true at the END of the very first successful init() call in this\n   * page session. Survives `destroy()` (any flavour) and subsequent inits.\n   * Drives `aa-trigger=\"load-once\"` semantics: load-once fires only on the\n   * first init cycle so subsequent Barba navigations don't replay the\n   * animation while the new container is hidden behind the transition wrapper.\n   */\n  firstInitComplete: boolean\n  /**\n   * Class-name → animation preset resolution from the last `init()` call.\n   * Populated by `resolvePresets()` before scan; consumed by scanner +\n   * `readAttrs()` as a fallback attribute source. Empty when no `presets`\n   * option was passed. Reset on every destroy() so the next init starts\n   * fresh.\n   */\n  presetMap: Map<Element, ResolvedPreset>\n}\n\nconst initial = (): InternalState => ({\n  initialized: false,\n  options: { ...DEFAULT_OPTIONS },\n  breakpoints: { ...DEFAULT_BREAKPOINTS },\n  disposers: [],\n  smoothScroll: null,\n  scrollStateDispose: null,\n  scrollTargetDispose: null,\n  firstInitComplete: false,\n  presetMap: new Map(),\n})\n\nexport const state: InternalState = initial()\n\nexport function resolveBreakpoints(opts: InitOptions['breakpoints']): Breakpoints {\n  return { ...DEFAULT_BREAKPOINTS, ...opts }\n}\n\nexport function reset(): void {\n  Object.assign(state, initial())\n}\n\nlet readyDeferred: { promise: Promise<void>; resolve: () => void } | null = null\n\nexport function newReadyDeferred(): void {\n  let resolve!: () => void\n  const promise = new Promise<void>((r) => {\n    resolve = r\n  })\n  readyDeferred = { promise, resolve }\n}\n\nexport function getReadyPromise(): Promise<void> {\n  return readyDeferred ? readyDeferred.promise : Promise.resolve()\n}\n\nexport function resolveReady(): void {\n  readyDeferred?.resolve()\n}\n\nexport function addDisposer(fn: () => void): void {\n  state.disposers.push(fn)\n}\n\nexport function runAllDisposers(): void {\n  while (state.disposers.length > 0) {\n    const fn = state.disposers.pop()\n    if (!fn) continue\n    try {\n      fn()\n    } catch (err) {\n      console.error('[alrdy-animate] disposer threw', err)\n    }\n  }\n}\n","import type { SmoothScrollOptions } from '../types/index'\nimport type { GsapHandle } from '../core/gsap-detect'\n\ninterface LenisInstance {\n  raf: (time: number) => void\n  on: (event: 'scroll', cb: () => void) => void\n  destroy: () => void\n  scrollTo: (\n    target: string | number | HTMLElement,\n    options?: { offset?: number; duration?: number; easing?: (t: number) => number },\n  ) => void\n  start: () => void\n  stop: () => void\n}\n\ninterface LenisCtor {\n  new (options?: Record<string, unknown>): LenisInstance\n}\n\ninterface ScrollTriggerLike {\n  update: () => void\n}\n\ndeclare global {\n  interface Window {\n    Lenis?: LenisCtor\n    lenis?: LenisInstance\n  }\n}\n\nconst DEFAULT_OPTIONS: Required<SmoothScrollOptions> = {\n  lerp: 0.12,\n  wheelMultiplier: 1,\n  touchMultiplier: 2,\n  smoothWheel: true,\n  syncTouch: false,\n}\n\nexport interface SmoothScrollHandle {\n  lenis: LenisInstance\n  dispose: () => void\n}\n\nexport function initSmoothScroll(\n  gsapHandle: GsapHandle,\n  options: SmoothScrollOptions | true,\n  debug: boolean,\n): SmoothScrollHandle | null {\n  const Lenis = typeof window !== 'undefined' ? window.Lenis : undefined\n  if (!Lenis) {\n    if (debug) {\n      console.warn(\n        '[alrdy-animate] window.Lenis not found — smooth scroll disabled. Add <script src=\"https://cdn.jsdelivr.net/npm/lenis@1/dist/lenis.min.js\"></script> before alrdy-animate, or pass smoothScroll: false to silence this warning.',\n      )\n    }\n    return null\n  }\n\n  const userOpts = options === true ? {} : options\n  const merged = { ...DEFAULT_OPTIONS, ...userOpts }\n  const lenis = new Lenis(merged as unknown as Record<string, unknown>)\n\n  const ScrollTrigger = (gsapHandle.plugins.ScrollTrigger as ScrollTriggerLike | undefined)\n  const updateScrollTrigger = ScrollTrigger ? () => ScrollTrigger.update() : null\n  if (updateScrollTrigger) lenis.on('scroll', updateScrollTrigger)\n\n  const tickerFn = (time: number): void => {\n    lenis.raf(time * 1000)\n  }\n  gsapHandle.gsap.ticker.add(tickerFn)\n  // Lenis manages its own time; lag smoothing causes jumps at frame drops.\n  gsapHandle.gsap.ticker.lagSmoothing(0)\n\n  window.lenis = lenis\n\n  const dispose = (): void => {\n    gsapHandle.gsap.ticker.remove(tickerFn)\n    try {\n      lenis.destroy()\n    } catch (err) {\n      if (debug) console.warn('[alrdy-animate] lenis.destroy() threw', err)\n    }\n    if (window.lenis === lenis) delete window.lenis\n  }\n\n  return { lenis, dispose }\n}\n","import '../css/alrdy-animate.css'\nimport type {\n  DestroyApiOptions,\n  InitOptions,\n  OnResizeOptions,\n  PublicApi,\n  ResizeCallback,\n  ResizeUnsubscribe,\n} from '../types/index'\nimport { detectGsap, type GsapHandle, type GsapTween } from './gsap-detect'\nimport { createResponsiveController, type ResponsiveController } from './match-media'\nimport { NAMED_EASES } from './named-eases'\nimport { resolvePresets } from './presets'\nimport {\n  OPTIMIZE_MOBILE_FADE_FEATURES,\n  OPTIMIZE_MOBILE_REPLACED_FEATURES,\n  REDUCED_MOTION_FADE_FEATURES,\n  REDUCED_MOTION_REPLACED_FEATURES,\n  runFadeFallbackPass,\n} from './reduced-motion'\nimport { loadFeatures, type FeatureContext } from './registry'\nimport { clearAll as clearResize, subscribe as subscribeResize } from './resize'\nimport { scan, type FeatureName } from './scanner'\nimport { initScrollState } from './scroll-state'\nimport { initScrollTarget } from './scroll-target'\nimport {\n  DEFAULT_OPTIMIZE_MOBILE_FADE,\n  DEFAULT_OPTIONS,\n  DEFAULT_REDUCED_MOTION,\n  addDisposer,\n  getReadyPromise,\n  newReadyDeferred,\n  resolveBreakpoints,\n  resolveOptions,\n  resolveReady,\n  runAllDisposers,\n  state,\n} from './state'\nimport { initSmoothScroll } from '../smooth-scroll/index'\nimport type { ReducedMotionOptions } from '../types/index'\n\nlet activeHandles: { gsap: GsapHandle; responsive: ResponsiveController } | null = null\n\n// Upper bound on how long init() will wait for `document.fonts.ready` before a\n// line-split text entrance (see the gated await below). Caps the worst case\n// (a slow/blocked webfont) so init can't hang for seconds; preloading the hero\n// font keeps fonts.ready well under this.\nconst FONT_METRICS_TIMEOUT_MS = 3000\n\nfunction detectReducedMotion(\n  setting: boolean | ReducedMotionOptions,\n): ReducedMotionOptions | null {\n  if (setting === false) return null\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return null\n  if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) return null\n  return setting === true ? DEFAULT_REDUCED_MOTION : setting\n}\n\nfunction detectOptimizeMobile(\n  setting: boolean | 'fade',\n  mdBreakpoint: number,\n): false | true | 'fade' {\n  if (setting !== true && setting !== 'fade') return false\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false\n  // Match the same exclusive width arithmetic the responsive system uses\n  // (see core/settings.ts `buildRangeQuery`) so the cutoff is consistent\n  // with `aa-foo-md`/the `|` shorthand split point.\n  if (!window.matchMedia(`(max-width: ${mdBreakpoint - 0.02}px)`).matches) return false\n  // Preserve the mode so the caller can choose \"just visible\" (true) vs the\n  // soft fade ('fade').\n  return setting\n}\n\n/**\n * Touch-only devices can't fire hover events, so loading the hover module just\n * to have its init() return a no-op is pure waste (~3KB gzipped + parse).\n * Gate on pointer capability, not viewport — a hybrid laptop with a narrow\n * window still has a mouse, and we want hover to keep working there.\n *\n * Independent of `optimizeMobile`: this is correctness, not a perf knob.\n */\nfunction deviceHasHover(): boolean {\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return true\n  return window.matchMedia('(hover: hover)').matches\n}\n\nfunction registerCustomEases(handle: GsapHandle, debug: boolean): void {\n  const w = window as unknown as Record<string, unknown>\n  const CustomEase = w.CustomEase as\n    | { create: (id: string, value: string) => unknown }\n    | undefined\n  if (!CustomEase) {\n    if (debug) {\n      console.warn(\n        `[alrdy-animate] CustomEase not loaded — named eases (${Object.keys(NAMED_EASES).join(', ')}) are unavailable. Add <script src=\"https://cdn.jsdelivr.net/npm/gsap@3/dist/CustomEase.min.js\"></script> before alrdy-animate.`,\n      )\n    }\n    return\n  }\n  try {\n    handle.gsap.registerPlugin(CustomEase)\n  } catch {\n    // already registered; ignore\n  }\n  for (const [name, path] of Object.entries(NAMED_EASES)) {\n    try {\n      CustomEase.create(name, path)\n    } catch (err) {\n      if (debug) console.warn(`[alrdy-animate] failed to register named ease \"${name}\"`, err)\n    }\n  }\n}\n\nexport async function init(options: InitOptions = {}): Promise<void> {\n  if (state.initialized) return\n  newReadyDeferred()\n  // Marker for the optional slow-network fallback recipe (docs/recipes/load-fallback).\n  // The inline <head> snippet checks for this attribute after a tunable timeout;\n  // setting it as the very first synchronous step in init means the snippet only\n  // fires its CSS fallback if init hasn't even *started* by the deadline.\n  if (typeof document !== 'undefined') {\n    document.documentElement.setAttribute('aa-loaded', '')\n  }\n  state.options = resolveOptions(options)\n  state.breakpoints = resolveBreakpoints(options.breakpoints)\n  state.initialized = true\n\n  const debug = options.debug ?? false\n  const root = options.root ?? document\n\n  // Resolve class → animation presets BEFORE scan so the scanner can fold in\n  // preset-only elements (those with no `aa-*` attrs) and classify them by\n  // their virtual `aa-animate` value. The map is in-memory only — we never\n  // mutate the DOM. Elements with any explicit `aa-*` attribute are skipped\n  // by `resolvePresets()`, honouring the \"attribute wins over preset\" rule.\n  const presetMap = resolvePresets(root, options.presets, debug)\n  state.presetMap = presetMap\n\n  // Detect reduced motion + mobile-optimization eagerly so that:\n  //  (1) we can drop decorative feature modules from the load set entirely,\n  //  (2) outside scripts reading `AlrdyAnimate.options.reducedMotion` /\n  //      `.optimizeMobile` after `await ready()` see the collapsed boolean\n  //      reflecting actual runtime state, not the user-passed setting shape.\n  // Both conditions route the same fade-fallback pass:\n  //   reducedMotion = OS-level preference (broad set, includes appear)\n  //   optimizeMobile = small-viewport perf gate (heavy features only)\n  // When both fire, reduced motion's superset wins.\n  const reducedMotion = detectReducedMotion(state.options.reducedMotion)\n  const optimizeMobile = !reducedMotion && detectOptimizeMobile(\n    state.options.optimizeMobile,\n    state.breakpoints.md,\n  )\n  // Collapse the public snapshot: reducedMotion → plain boolean (its timing\n  // object lives in the local `reducedMotion` variable and is threaded into\n  // `featureCtx.reducedMotion` / `runFadeFallbackPass` below); optimizeMobile →\n  // the active mode (`true` / `'fade'`) or `false` when inactive.\n  state.options.reducedMotion = !!reducedMotion\n  state.options.optimizeMobile = optimizeMobile\n\n  const { elements, features, needsHoverSplit, needsFontMetrics } = scan(root, presetMap)\n  if (elements.length === 0) {\n    resolveReady()\n    return\n  }\n\n  let replacedFeatures: ReadonlySet<FeatureName>\n  let fadeFeatures: ReadonlySet<FeatureName>\n  if (reducedMotion) {\n    replacedFeatures = REDUCED_MOTION_REPLACED_FEATURES\n    fadeFeatures = REDUCED_MOTION_FADE_FEATURES\n  } else if (optimizeMobile) {\n    // text/parallax/split are dropped in both modes (identical perf win); only\n    // the fade set differs — `'fade'` fades text, `true` leaves it static.\n    replacedFeatures = OPTIMIZE_MOBILE_REPLACED_FEATURES\n    fadeFeatures = optimizeMobile === 'fade' ? OPTIMIZE_MOBILE_FADE_FEATURES : new Set()\n  } else {\n    replacedFeatures = new Set()\n    fadeFeatures = new Set()\n  }\n\n  const effectiveFeatures = new Set(features)\n  let needsFadePass = false\n  for (const f of replacedFeatures) {\n    if (!effectiveFeatures.has(f)) continue\n    effectiveFeatures.delete(f)\n    if (fadeFeatures.has(f)) needsFadePass = true\n  }\n\n  // Init-timeout bypass: the inline-snippet's universal safety net fired before\n  // we got here (`html[aa-timeout]` set after a tunable deadline, default 4s).\n  // Elements are already visible at their natural state; rewinding them through\n  // a from-state now would flash. Drop the appearance features that own those\n  // entrances — interactive components still run normally so the page is fully\n  // functional. The end-of-init aa-ready flip and aa-timeout clear still fire.\n  const timedOut =\n    typeof document !== 'undefined' &&\n    document.documentElement.hasAttribute('aa-timeout')\n  if (timedOut) {\n    effectiveFeatures.delete('appear')\n    effectiveFeatures.delete('text')\n    effectiveFeatures.delete('reveal')\n    effectiveFeatures.delete('parallax')\n    needsFadePass = false\n  }\n\n  // Drop hover on touch-only devices — the module's own init() also self-skips\n  // there (belt-and-braces), but gating here saves the dynamic import.\n  if (effectiveFeatures.has('hover') && !deviceHasHover()) {\n    effectiveFeatures.delete('hover')\n  }\n\n  const requiredPlugins = new Set<string>()\n  for (const f of effectiveFeatures) {\n    if (\n      f === 'appear' ||\n      f === 'text' ||\n      f === 'reveal' ||\n      f === 'slices' ||\n      f === 'parallax' ||\n      f === 'nav' ||\n      f === 'marquee'\n    ) {\n      requiredPlugins.add('ScrollTrigger')\n    }\n    if (f === 'text' || f === 'split') requiredPlugins.add('SplitText')\n    // hover='text' (char/word lift) is the only hover head that needs\n    // SplitText; the scanner flags it during its single DOM pass. Reaching here\n    // with f==='hover' implies the device has hover — touch-only devices drop\n    // `hover` from effectiveFeatures above, so no matchMedia check is needed.\n    if (f === 'hover' && needsHoverSplit) requiredPlugins.add('SplitText')\n    if (f === 'slider' || f === 'marquee') {\n      requiredPlugins.add('Draggable')\n      requiredPlugins.add('InertiaPlugin')\n    }\n    if (f === 'nav') requiredPlugins.add('Flip')\n  }\n  if (needsFadePass) requiredPlugins.add('ScrollTrigger')\n\n  const gsapHandle = detectGsap([...requiredPlugins], debug)\n  if (!gsapHandle) {\n    resolveReady()\n    return\n  }\n\n  registerCustomEases(gsapHandle, debug)\n  try {\n    gsapHandle.gsap.defaults({ ease: state.options.ease })\n  } catch {\n    // ignore\n  }\n\n  // Lenis is genuinely global: it owns the page-level scroll behaviour and\n  // its instance is keyed to `document.documentElement`, which doesn't change\n  // across route swaps. Preserving it across `destroy({ keepGlobals: true })`\n  // keeps the scroll position smooth through a page transition and avoids\n  // re-instantiating the RAF/ticker every navigation.\n  const smoothScrollOpt = state.options.smoothScroll\n  if (smoothScrollOpt && !state.smoothScroll) {\n    state.smoothScroll = initSmoothScroll(gsapHandle, smoothScrollOpt, debug)\n  }\n\n  // Scroll-state and scroll-target listeners are bound to elements that DO\n  // change across SPA navigations (Next.js App Router, Barba container swap):\n  // `[aa-toggle-playstate]` IntersectionObserver targets and\n  // `[aa-scroll-target]` click listeners. If we skipped re-attaching when\n  // dispose still exists (from `keepGlobals: true`), the new route's DOM\n  // would never get listeners. So always tear down and re-attach — the\n  // dispose calls remove listeners cleanly, and the re-init scans current\n  // DOM. One `querySelectorAll` per init, negligible cost.\n  if (state.options.scrollState) {\n    state.scrollStateDispose?.()\n    state.scrollStateDispose = initScrollState()\n  }\n  state.scrollTargetDispose?.()\n  state.scrollTargetDispose = initScrollTarget()\n\n  const responsive = createResponsiveController(gsapHandle, state.breakpoints)\n  activeHandles = { gsap: gsapHandle, responsive }\n\n  // Load gate: `load` / `load-once` entrances build `paused` and register the\n  // tween here instead of autoplaying. We release them one paint AFTER the\n  // aa-ready reveal (below) so a wall-clock tween can't advance during the\n  // heavy post-init layout/paint block and surface already mid-fade. Lives as\n  // a closure local (auto-GC'd per init, no global state); a disposer flips\n  // `gateCancelled` so a pending flush after destroy() is a no-op. Created\n  // before the fade pass so both it and the feature context share the hook.\n  const loadGate: GsapTween[] = []\n  let gateCancelled = false\n  const deferLoadStart = (tween: GsapTween): void => {\n    if (!gateCancelled) loadGate.push(tween)\n  }\n  addDisposer(() => {\n    gateCancelled = true\n  })\n\n  // Run the unified fade-fallback pass BEFORE feature inits so its\n  // ScrollTriggers register first. Component features that run after still\n  // see their elements at the correct positions (no transform conflicts).\n  if (needsFadePass) {\n    // reducedMotion's own timing wins when it's active; otherwise this pass was\n    // scheduled by `optimizeMobile: 'fade'`, which uses a softer/slower fade.\n    const fadeTiming = reducedMotion ?? DEFAULT_OPTIMIZE_MOBILE_FADE\n    const disposeFade = runFadeFallbackPass(elements, {\n      gsap: gsapHandle,\n      options: state.options,\n      reducedMotion: fadeTiming,\n      firstInit: !state.firstInitComplete,\n      fadeFor: fadeFeatures,\n      presetMap,\n      deferLoadStart,\n    })\n    addDisposer(disposeFade)\n  }\n\n  // SplitText (used by the text feature) is created with `autoSplit: true`,\n  // which re-splits when `document.fonts.ready` resolves to pick up real-font\n  // line metrics. If init runs before fonts are ready, the entry tween starts\n  // playing against fallback-font chars, then the font-load resplit replaces\n  // those chars and `handle.rebuild()` snaps the new timeline to progress(1)\n  // because `triggerPlayed` is true — visible as a brief flash followed by a\n  // jump to the end state. Awaiting fonts up front makes SplitText split once\n  // with correct metrics.\n  //\n  // Gated on `needsFontMetrics` (a **line** split is present) rather than the\n  // whole text feature: only line wrapping shifts when the webfont swaps, so\n  // char/word-only text pages (and non-text pages) skip the wait and init\n  // sooner — char/word splits self-correct via the resplit-rebuild path. Capped\n  // with a race so a slow/blocked font can't hang init for seconds; past the\n  // cap we proceed and accept a possible one-off resplit (preloading the hero\n  // font keeps fonts.ready well under the cap). FOUC guard hides animated\n  // elements during the wait.\n  if (\n    needsFontMetrics &&\n    typeof document !== 'undefined' &&\n    document.fonts?.ready\n  ) {\n    try {\n      await Promise.race([\n        document.fonts.ready,\n        new Promise<void>((resolve) => setTimeout(resolve, FONT_METRICS_TIMEOUT_MS)),\n      ])\n    } catch {\n      // fonts.ready can reject in edge cases (e.g. font load errors); proceed.\n    }\n  }\n\n  const featureModules = await loadFeatures(effectiveFeatures)\n  const featureCtx: FeatureContext = {\n    gsap: gsapHandle,\n    responsive,\n    elements,\n    options: state.options,\n    debug,\n    firstInit: !state.firstInitComplete,\n    reducedMotion,\n    presetMap,\n    onResize: (fn, debounce = 150) => subscribeResize(fn, debounce),\n    deferLoadStart,\n  }\n  for (const mod of featureModules) {\n    try {\n      const dispose = mod.init(featureCtx)\n      addDisposer(dispose)\n    } catch (err) {\n      console.error(`[alrdy-animate] feature \"${mod.name}\" failed to init`, err)\n    }\n  }\n\n  // Reveal everything in one pass. Features have already applied their\n  // from-states inside matchMedia callbacks (which fire synchronously), so\n  // flipping aa-ready here only changes `visibility: hidden` → `visible`\n  // without exposing pre-animation content. Elements that never matched any\n  // breakpoint still get revealed so the page isn't stuck blank.\n  // Preset elements have no `aa-animate` attribute (the preset map fills\n  // that in virtually) and weren't FOUC-hidden in the first place — skip them.\n  for (const el of elements) {\n    if (el.hasAttribute('aa-animate')) el.setAttribute('aa-ready', '')\n  }\n\n  // Mark first-init done. Survives every destroy() so subsequent inits (e.g.\n  // Barba navigations) know `aa-trigger=\"load-once\"` already played. Reset only by\n  // a hard page reload, which reloads this module too.\n  state.firstInitComplete = true\n\n  // Clear the slow-network fallback markers now that init has run. If the\n  // inline-snippet timeouts fired (set aa-fallback / aa-timeout on first\n  // load), we no longer need them — the bundle is here. Leaving them set\n  // would re-trigger the CSS rules on every Barba navigation, since each new\n  // container renders its elements without aa-ready until init catches up.\n  if (typeof document !== 'undefined') {\n    document.documentElement.removeAttribute('aa-fallback')\n    document.documentElement.removeAttribute('aa-timeout')\n  }\n\n  if (debug) {\n    const lenisActive = typeof window !== 'undefined' && !!window.lenis\n    const loadedFeatures = [...effectiveFeatures]\n    const droppedFeatures = [...features].filter((f) => !effectiveFeatures.has(f))\n    const replacedBy = timedOut\n      ? 'aa-timeout bypass'\n      : reducedMotion\n        ? 'reduced-motion'\n        : optimizeMobile\n          ? `optimize-mobile (${optimizeMobile === 'fade' ? 'fade' : 'visible'})`\n          : null\n    const featuresLabel =\n      replacedBy && droppedFeatures.length\n        ? `${loadedFeatures.join(', ') || '(none)'} (${replacedBy} dropped: ${droppedFeatures.join(', ')})`\n        : loadedFeatures.join(', ') || '(none)'\n    console.log(\n      `[alrdy-animate] initialized. Features: ${featuresLabel}; ` +\n        `Plugins: ${[...requiredPlugins].join(', ') || '(none)'}; ` +\n        `Elements: ${elements.length}; ` +\n        `SmoothScroll: ${lenisActive ? 'lenis' : 'off'}; ` +\n        `ReducedMotion: ${reducedMotion ? 'active' : 'off'}; ` +\n        `OptimizeMobile: ${optimizeMobile ? optimizeMobile : 'off'}`,\n    )\n  }\n\n  resolveReady()\n\n  // Release paint-gated load entrances (registered via `deferLoadStart`) one\n  // paint AFTER the aa-ready reveal, so they start visibly at frame 0 instead\n  // of a wall-clock tween advancing during the post-init layout/paint block.\n  // `flush` is guarded by `gateCancelled` (so destroy() before release is a\n  // no-op) and empties the gate (so it's harmless if somehow run twice).\n  // Scheduled after resolveReady() so `await ready()` observers see the\n  // from-state, not a half-played frame.\n  //\n  // Double-rAF, NOT a timer: GSAP's own ticker rAF (registered at load, before\n  // ours) runs first in each rendering step, so by the time our flush calls\n  // restart() the ticker clock is already advanced to \"now\" and the tween\n  // anchors at 0. A `setTimeout` flush would instead run as a task BEFORE the\n  // rendering step — on a page blocked past the timer it would release while\n  // the ticker clock is stale, then the next tick jumps the tween forward:\n  // the exact mid-fade pop-in this gate prevents. No timer is needed for\n  // safety either: a tab hidden now takes the synchronous branch; a tab\n  // backgrounded after scheduling has rAF suspended but resumes (and flushes)\n  // on return to the foreground, so the entrance is never stuck invisible.\n  if (loadGate.length > 0) {\n    const flush = (): void => {\n      if (gateCancelled) return\n      for (const tween of loadGate.splice(0)) {\n        try {\n          tween.restart(true)\n        } catch (err) {\n          console.error('[alrdy-animate] load release threw', err)\n        }\n      }\n    }\n    if (\n      typeof requestAnimationFrame !== 'function' ||\n      (typeof document !== 'undefined' && document.visibilityState === 'hidden')\n    ) {\n      // SSR or a tab hidden right now — no paint is coming to gate against.\n      flush()\n    } else {\n      requestAnimationFrame(() => requestAnimationFrame(flush))\n    }\n  }\n}\n\nexport function destroy(options: DestroyApiOptions = {}): void {\n  if (activeHandles?.responsive) {\n    try {\n      if (options.keepFromStates) activeHandles.responsive.killAll()\n      else activeHandles.responsive.revertAll()\n    } catch (err) {\n      console.error('[alrdy-animate] responsive controller cleanup threw', err)\n    }\n  }\n  runAllDisposers()\n  clearResize()\n  activeHandles = null\n  state.initialized = false\n  state.presetMap = new Map()\n\n  if (!options.keepGlobals) {\n    state.smoothScroll?.dispose()\n    state.smoothScroll = null\n    state.scrollStateDispose?.()\n    state.scrollStateDispose = null\n    state.scrollTargetDispose?.()\n    state.scrollTargetDispose = null\n  }\n\n  state.options = { ...DEFAULT_OPTIONS }\n}\n\nexport async function refresh(): Promise<void> {\n  destroy()\n  await init(state.options)\n}\n\nexport function onResize(fn: ResizeCallback, opts: OnResizeOptions = {}): ResizeUnsubscribe {\n  return subscribeResize(fn, opts.debounce ?? 150)\n}\n\nexport { getReadyPromise as ready } from './state'\n\nconst api: PublicApi = {\n  init,\n  destroy,\n  refresh,\n  onResize,\n  ready: getReadyPromise,\n  // Live getter — always reflects the latest init() snapshot without\n  // consumers needing to re-grab the api object after refresh().\n  get options() {\n    return state.options\n  },\n}\n\ndeclare global {\n  interface Window {\n    AlrdyAnimate: PublicApi\n  }\n}\n\nif (typeof window !== 'undefined') {\n  window.AlrdyAnimate = api\n}\n\nexport { api }\n","import type { ResolvedOptions } from '../types/index'\nimport type { Config } from './settings'\n\ntype StaggerFrom = 'start' | 'end' | 'center' | 'edges'\n\n/**\n * Resolve the default stagger for a given split mode. Stagger is the lone\n * timing default that varies per mode — chars cascade fast, lines cascade\n * slow. `undefined` covers aa-children without a split (e.g. scroll feature\n * staggering a card grid) and falls back to the `default` slot.\n */\nexport function defaultStaggerFor(\n  splitMode: 'chars' | 'words' | 'lines' | undefined,\n  options: ResolvedOptions,\n): number {\n  if (splitMode === 'chars') return options.stagger.chars\n  if (splitMode === 'words') return options.stagger.words\n  if (splitMode === 'lines') return options.stagger.lines\n  return options.stagger.default\n}\n\nexport interface StaggerFlags {\n  from: StaggerFrom\n  random: boolean\n  groupSize: number\n  grid: boolean\n}\n\nexport interface StaggerSpec {\n  unit: number\n  line: number\n  flags: StaggerFlags\n}\n\nexport type StaggerValue =\n  | number\n  | Record<string, unknown>\n  | ((index: number, target: Element, list: Element[]) => number)\n\nconst VALID_FROM = new Set<StaggerFrom>(['start', 'center', 'end', 'edges'])\n\nconst defaultFlags = (): StaggerFlags => ({\n  from: 'start',\n  random: false,\n  groupSize: 1,\n  grid: false,\n})\n\n/**\n * `aa-stagger` value grammar:\n *   - First numeric token = unit stagger (per element)\n *   - Second numeric token = line stagger (used by line-grouped text modes\n *     only). When omitted it falls back to `lineFallback` (the caller passes\n *     the `lines` default), independent of the unit stagger.\n *   - Non-numeric tokens are flags applied to the unit stagger:\n *       start | center | end | edges        — origin (default: start)\n *       random | random:N                   — random; optional batch size N\n *       grid                                — auto-detect 2D layout\n *   - `random:N` shuffles every element to a random rank, then groups them in\n *     batches of N — so each batch is N elements scattered across the set,\n *     not N consecutive ones.\n *   - random + grid/origin is meaningless: random wins.\n */\nexport function parseStaggerSpec(\n  value: string | undefined,\n  fallback: number,\n  lineFallback: number = fallback,\n): StaggerSpec {\n  const flags = defaultFlags()\n  if (!value) {\n    return { unit: fallback, line: lineFallback, flags }\n  }\n  const tokens = value.trim().split(/\\s+/)\n  const numerics: number[] = []\n  for (const token of tokens) {\n    if (/^-?\\d/.test(token)) {\n      const n = parseFloat(token)\n      if (Number.isFinite(n)) numerics.push(n)\n      continue\n    }\n    if (VALID_FROM.has(token as StaggerFrom)) {\n      flags.from = token as StaggerFrom\n    } else if (token === 'random') {\n      flags.random = true\n    } else if (token.startsWith('random:')) {\n      flags.random = true\n      const n = parseInt(token.slice('random:'.length), 10)\n      if (Number.isFinite(n) && n > 0) flags.groupSize = n\n    } else if (token === 'grid') {\n      flags.grid = true\n    }\n  }\n  const unit = numerics[0] ?? fallback\n  const line = numerics[1] ?? lineFallback\n  return { unit, line, flags }\n}\n\nexport function buildStagger(unit: number, flags: StaggerFlags): StaggerValue {\n  if (flags.random) {\n    // groupSize ≤ 1: GSAP's native random distribution gives the same result.\n    if (flags.groupSize <= 1) {\n      return { each: unit, from: 'random' }\n    }\n    // Scattered random batches: shuffle every element to a random rank, then\n    // group by `floor(rank / groupSize)`. Each batch is N random elements\n    // (not N adjacent ones) and batches fire in time order. Ranks are cached\n    // on first invocation so every element keeps a stable assignment.\n    const groupSize = flags.groupSize\n    let ranks: number[] | null = null\n    return (index: number, _target: Element, list: Element[]) => {\n      if (!ranks) {\n        const r = Array.from({ length: list.length }, (_, i) => i)\n        for (let k = r.length - 1; k > 0; k--) {\n          const j = Math.floor(Math.random() * (k + 1))\n          ;[r[k], r[j]] = [r[j], r[k]]\n        }\n        ranks = r\n      }\n      return Math.floor((ranks[index] ?? 0) / groupSize) * unit\n    }\n  }\n  if (flags.grid || flags.from !== 'start') {\n    const out: Record<string, unknown> = { each: unit, from: flags.from }\n    if (flags.grid) out.grid = 'auto'\n    return out\n  }\n  return unit\n}\n\n/**\n * Resolve the animation targets + stagger for an entrance feature (appear,\n * reveal): with `aa-stagger` and element children present, stagger the\n * children; otherwise animate the element itself with no stagger. Returns the\n * element in a single-item array in the no-children case (GSAP treats a\n * one-element array and a bare element identically).\n */\nexport function collectStaggerTargets(\n  element: Element,\n  config: Config,\n  options: ResolvedOptions,\n): { targets: Element[]; stagger: StaggerValue } {\n  const wantsStagger = config['aa-stagger'] !== undefined\n  const children = wantsStagger\n    ? Array.from(element.children).filter((c): c is Element => c.nodeType === 1)\n    : []\n  const targets: Element[] = children.length > 0 ? children : [element]\n  const staggerSpec = parseStaggerSpec(config['aa-stagger'], defaultStaggerFor(undefined, options))\n  const stagger: StaggerValue =\n    children.length > 0 ? buildStagger(staggerSpec.unit, staggerSpec.flags) : 0\n  return { targets, stagger }\n}\n","import type { GsapTween } from './gsap-detect'\nimport type { FeatureContext } from './registry'\nimport { bindAgainTrigger } from './scroll-trigger'\nimport {\n  isLoadKind,\n  type ParsedTrigger,\n  REVERSE_EASE,\n  REVERSE_TIME_SCALE,\n  subscribeWithPair,\n} from './trigger'\n\n/**\n * Vars the orchestrator hands to the feature's `buildAnimation` callback.\n * The shape encodes the trigger classification — the feature just plugs the\n * vars into its `gsap.from(...)` / `gsap.fromTo(...)` / `gsap.timeline(...)`\n * call and the right trigger semantics fall out.\n *\n *   load-once / load             { delay }                            — plays immediately\n *   event                        { paused: true, delay, easeReverse } — paused, controlled by event pair\n *   scrub                        { delay, scrollTrigger }             — bound to scroll position\n *   scroll-again (the default)   { paused: true, delay }              — paused, controlled by enter/reset triggers\n *\n * `easeReverse` is a tween-level GSAP prop — spreading it into `gsap.from/to/fromTo`\n * works directly; timeline-based features must lift it into `defaults` so child\n * tweens inherit it (a top-level `easeReverse` on a timeline does not cascade).\n */\nexport interface TriggerVars {\n  paused?: boolean\n  delay: number\n  easeReverse?: number | string\n  scrollTrigger?: {\n    trigger: Element\n    start: string\n    end: string | undefined\n    scrub: number | true\n  }\n}\n\nexport interface BuiltAnimation {\n  animation: GsapTween\n  /** Optional cleanup for feature-specific DOM mutations (line wrappers etc.) — runs before rebuild and on dispose. */\n  cleanup?: () => void\n}\n\n/**\n * Reshape TriggerVars for `gsap.timeline(...)`: lifts `easeReverse` into\n * `defaults` so child fromTo tweens inherit it (a top-level `easeReverse` on a\n * timeline does not cascade). Tween features can spread vars directly.\n */\nexport function toTimelineVars(vars: TriggerVars): Record<string, unknown> {\n  const { easeReverse, ...rest } = vars\n  if (easeReverse === undefined) return rest\n  return { ...rest, defaults: { easeReverse } }\n}\n\nconst WILL_CHANGE_TRANSFORM_KEYS = new Set([\n  'x', 'y', 'z', 'xPercent', 'yPercent', 'scale', 'scaleX', 'scaleY',\n  'rotation', 'rotate', 'rotationX', 'rotationY', 'rotationZ', 'skewX', 'skewY',\n  'transform', 'transformPerspective',\n])\n\n/**\n * Derive a `will-change` value from a set of GSAP from/to vars — used by\n * entrance features so the orchestrator can hint the compositor for the exact\n * properties being animated (and nothing more). Returns '' when nothing maps,\n * which disables will-change management for that animation.\n */\nexport function cssWillChange(vars: Record<string, unknown>): string {\n  const props: string[] = []\n  let hasTransform = false\n  for (const key of Object.keys(vars)) {\n    if (key === 'opacity' || key === 'autoAlpha') {\n      if (!props.includes('opacity')) props.push('opacity')\n    } else if (key === 'filter') {\n      if (!props.includes('filter')) props.push('filter')\n    } else if (key === 'clipPath') {\n      if (!props.includes('clip-path')) props.push('clip-path')\n    } else if (WILL_CHANGE_TRANSFORM_KEYS.has(key)) {\n      hasTransform = true\n    }\n  }\n  if (hasTransform) props.unshift('transform')\n  return props.join(', ')\n}\n\nexport interface TriggeredAnimationOptions {\n  /**\n   * Pre-parsed triggers — the feature decides whether to use\n   * `resolveTriggers` (with container inference for slider/tabs/modal) or\n   * the bare `parseTriggers`. Passing the result keeps the helper agnostic.\n   */\n  triggers: ParsedTrigger[]\n  /**\n   * CSS `will-change` value to apply to the animated targets only while the\n   * tween is actually playing — set on play/load, cleared on complete/reset.\n   * Avoids leaving a permanent compositor layer (which also breaks descendant\n   * `backdrop-filter`). Omit/empty to skip will-change management.\n   */\n  willChange?: string\n  delay: number\n  scrollStart: string\n  scrollEnd: string | undefined\n  /** When set, the helper builds a scrub-mode animation regardless of trigger kind. */\n  scrub: number | true | undefined\n  /** Scroll-again behaviour from `init({ again })`. */\n  again: boolean\n  /** ScrollTrigger anchor override (e.g. `aa-anchor`). Defaults to the animated element. */\n  triggerEl?: Element\n  /**\n   * Build the GSAP tween / timeline given the trigger-determined vars.\n   *\n   * Called once at setup and again on every `handle.rebuild()` — text\n   * features call this after SplitText resplits to retarget the new\n   * `.aa-char` / `.aa-line` nodes. Return null to skip (empty inputs,\n   * unsupported config).\n   */\n  buildAnimation: (vars: TriggerVars) => BuiltAnimation | null\n}\n\nexport interface TriggeredAnimationHandle {\n  /**\n   * Recreate the animation against the current state. Trigger machinery\n   * stays attached; rebuilt animations are wired up via closures.\n   *\n   * No-op for load-once / load after the first fire — their \"play once on\n   * this init cycle\" semantic shouldn't re-fire on resize-driven rebuilds.\n   *\n   * When the trigger pair is currently in its played state (event forward\n   * fired, no reverse since; or scroll-again past start, no full leave-back\n   * since), the new animation is snapped to `progress(1).pause()` so\n   * already-visible content doesn't flash back through the from-state.\n   */\n  rebuild: () => void\n  /** Tear down triggers, animation, and any feature cleanup. */\n  dispose: () => void\n}\n\n/**\n * Lifts trigger orchestration out of animation features. The feature\n * declares what to animate (in `buildAnimation`); this helper decides when\n * and how to play it based on the parsed `aa-trigger`.\n *\n * Returns `null` when nothing should run (e.g. `aa-trigger=\"load-once\"` on a\n * subsequent init cycle — load already fired). Returns a handle with\n * `rebuild()` for features that need to re-target their animation against\n * fresh DOM (SplitText auto-resplit on resize is the canonical case).\n */\nexport function setupTriggeredAnimation(\n  ctx: FeatureContext,\n  element: Element,\n  opts: TriggeredAnimationOptions,\n): TriggeredAnimationHandle | null {\n  const hasLoadOnce = opts.triggers.some((t) => t.kind === 'load-once')\n  const hasLoad = opts.triggers.some((t) => isLoadKind(t.kind))\n  const isLoadOneShot = (hasLoadOnce && ctx.firstInit) || hasLoad\n  let persistentTrigger: ParsedTrigger | undefined\n  if (!isLoadOneShot) {\n    persistentTrigger = opts.triggers.find(\n      (t) => t.kind !== 'load-once' && !isLoadKind(t.kind),\n    )\n  }\n  // No firing trigger at all (e.g. `aa-trigger=\"load-once\"` on a subsequent\n  // init, after the load already played). The end-of-init aa-ready flip will\n  // reveal the element in its natural state.\n  if (!isLoadOneShot && !persistentTrigger) return null\n\n  const triggerEl = opts.triggerEl ?? element\n\n  // Stagger load-triggered entrances after init() settles so the first frame\n  // isn't a hard jump from the from-state. Per-element `aa-delay` still\n  // composes on top — set both and they add. The `aa-fallback` skip above\n  // already short-circuits the load branch on slow-load revisits, so we don't\n  // need to gate the addition itself on that attribute.\n  const loadDelay = isLoadOneShot ? opts.delay + ctx.options.loadDelay : opts.delay\n\n  let currentAnim: GsapTween | null = null\n  let currentExtraCleanup: (() => void) | undefined\n  let triggerPlayed = false\n  let loadFired = false\n  let loadCompleted = false\n\n  // will-change is applied to the animated targets only while a tween is\n  // playing, then cleared — so it never lingers as a permanent compositor\n  // layer (which wastes memory and, on a nav, neutralises a descendant's\n  // backdrop-filter). `wcEls` snapshots the targets we set so we can clear\n  // exactly those even after the tween's own targets list changes on rebuild.\n  const wc = opts.willChange\n  let wcEls: HTMLElement[] = []\n  // Gather the animated elements for will-change. Tweens expose `targets()`;\n  // timelines (e.g. the text feature's per-line builds) have no runtime\n  // `targets()` despite the typed inheritance — walk their child tweens via\n  // `getChildren()` instead. Calling the missing method would throw and abort\n  // the play callback, leaving the animation stuck at its from-state.\n  const collectTargets = (anim: GsapTween): Element[] => {\n    const loose = anim as unknown as {\n      targets?: () => unknown[]\n      getChildren?: (nested?: boolean, tweens?: boolean, timelines?: boolean) => unknown[]\n    }\n    if (typeof loose.getChildren === 'function') {\n      return loose.getChildren(true, true, false).flatMap((child) => {\n        const c = child as { targets?: () => unknown[] }\n        return typeof c.targets === 'function' ? (c.targets() as Element[]) : []\n      })\n    }\n    return typeof loose.targets === 'function' ? (loose.targets() as Element[]) : []\n  }\n  const setWillChange = (): void => {\n    if (!wc || !currentAnim) return\n    wcEls = collectTargets(currentAnim).filter((t): t is HTMLElement => t instanceof HTMLElement)\n    for (const el of wcEls) el.style.willChange = wc\n  }\n  const clearWillChange = (): void => {\n    for (const el of wcEls) el.style.willChange = ''\n    wcEls = []\n  }\n\n  const killCurrent = (): void => {\n    clearWillChange()\n    if (currentExtraCleanup) {\n      try {\n        currentExtraCleanup()\n      } catch {\n        // ignore\n      }\n      currentExtraCleanup = undefined\n    }\n    if (currentAnim) {\n      // For animations carrying their own scrollTrigger (scrub) this also\n      // kills the attached ScrollTrigger — no separate cleanup needed.\n      currentAnim.kill()\n      currentAnim = null\n    }\n  }\n\n  const buildVars = (): TriggerVars => {\n    // Built `paused` so the wall-clock tween doesn't advance during the heavy\n    // post-init layout/paint block (which would surface the entrance already\n    // mid-fade). The orchestrator registers a paint-gated `restart(true)` via\n    // `ctx.deferLoadStart` below; `from()`'s immediateRender writes the\n    // from-state now so the revealed element shows true frame 0 while paused.\n    if (isLoadOneShot) return { paused: true, delay: loadDelay }\n    if (persistentTrigger?.kind === 'event') {\n      return {\n        paused: true,\n        delay: opts.delay,\n        easeReverse: REVERSE_EASE,\n      }\n    }\n    if (opts.scrub !== undefined) {\n      return {\n        delay: opts.delay,\n        scrollTrigger: {\n          trigger: triggerEl,\n          start: opts.scrollStart,\n          end: opts.scrollEnd,\n          scrub: opts.scrub,\n        },\n      }\n    }\n    return { paused: true, delay: opts.delay }\n  }\n\n  const rebuild = (): void => {\n    // Once the load entrance has fully PLAYED, a later rebuild() (e.g. a\n    // resize-driven SplitText auto-resplit) must NOT re-fire it — the fresh\n    // chars settle at their natural visible (end) state, which is the correct\n    // post-load result. We gate on completion, not registration: SplitText's\n    // `autoSplit` fires an initial ResizeObserver callback ~one frame after\n    // construction, which resplits and replaces the `.aa-char` nodes *before*\n    // the gated entrance has played. That early resplit must rebuild the tween\n    // against the new nodes (handled below via `loadFired && !loadCompleted`),\n    // or the entrance is stranded on the orphaned originals — visible as the\n    // text snapping straight to its end state with no animation (Firefox loses\n    // this race more often than Chromium, but it's timing, not browser-bound).\n    if (isLoadOneShot && loadCompleted) return\n\n    const wasFired = loadFired\n\n    // Snapshot the outgoing tween's forward progress before we kill it, so a\n    // rebuild that lands while a *played* entrance hasn't finished yet can\n    // resume from where it was instead of snapping to the end (see the block at\n    // the end of rebuild). Scrub tweens sync from scroll and are excluded there.\n    const prevProgress =\n      currentAnim && opts.scrub === undefined ? currentAnim.progress() : null\n\n    killCurrent()\n\n    // aa-fallback signals the inline-snippet timeout already faded the\n    // element in via CSS. Running our load tween now would rewind through\n    // the from-state and flash. Mark load COMPLETE — not merely fired — so\n    // every later rebuild short-circuits at the `loadCompleted` guard above.\n    // `loadFired` alone isn't enough: init() clears `aa-fallback` at the end\n    // of init, and SplitText's autoSplit fires an initial resplit ~one frame\n    // later (see the loadCompleted comment above). That post-clear rebuild no\n    // longer sees the flag, so it would build the tween (immediateRender\n    // writes the from-state, hiding the already-revealed text) and, since\n    // `wasFired` is set, restart(true) it — replaying the entrance the CSS\n    // fallback already played. The fallback fulfilled the entrance; treat it\n    // as done.\n    if (isLoadOneShot && document.documentElement.hasAttribute('aa-fallback')) {\n      loadFired = true\n      loadCompleted = true\n      return\n    }\n\n    const built = opts.buildAnimation(buildVars())\n    if (!built) return\n    currentAnim = built.animation\n    currentExtraCleanup = built.cleanup\n\n    if (wc) {\n      // Clear when the tween settles in either direction. Scrub tweens never\n      // fire these (they're scroll-scrubbed) and never call setWillChange, so\n      // they opt out of will-change management entirely — force3D handles their\n      // compositing.\n      currentAnim.eventCallback('onComplete', clearWillChange)\n      currentAnim.eventCallback('onReverseComplete', clearWillChange)\n    }\n\n    if (isLoadOneShot) {\n      // Mark the entrance complete once it finishes so a later resize-resplit\n      // becomes a no-op (the early-return above). This replaces the wc onComplete\n      // set just above, so fold clearWillChange back in to keep that behaviour.\n      currentAnim.eventCallback('onComplete', () => {\n        loadCompleted = true\n        clearWillChange()\n      })\n      // Warm the layer now so it's ready before the (delayed) load tween plays.\n      setWillChange()\n      if (wasFired) {\n        // A pre-completion resplit replaced our targets (autoSplit's initial\n        // ResizeObserver fire). The load gate has already been built — and by\n        // now likely flushed — so re-deferring would strand this tween (the\n        // gate only flushes once). Play it directly: restart(true) replays from\n        // frame 0 including the delay. The spurious resplit lands within a\n        // frame of the gate flush, so the original entrance had barely begun;\n        // restarting from 0 is visually seamless.\n        currentAnim.restart(true)\n      } else {\n        // First build: hand the paused tween to the load gate; init() releases\n        // it after first paint via restart(true). Reached only past the\n        // aa-fallback early-return, so the slow-network CSS fallback still wins\n        // when it's set (nothing registers for this element).\n        if (currentAnim) ctx.deferLoadStart(currentAnim)\n      }\n      loadFired = true\n      return\n    }\n    // Restore the forward-played state onto the rebuilt tween. We reproduce the\n    // *actual* progress the outgoing tween had reached rather than forcing\n    // progress(1): a rebuild (SplitText auto-resplit) that lands while the\n    // entrance is still in flight — e.g. an unrelated `ScrollTrigger.refresh()`\n    // or reflow a beat after an `event:`-fire re-wraps the lines — then keeps\n    // playing to the end instead of snapping straight there (which read as \"the\n    // heading appears instantly, no animation\"). `progress < 1` is the test, not\n    // isActive(): it covers both the mid-fade case AND a resplit during the\n    // entrance's `aa-delay` (progress still 0, isActive() false) — both must\n    // play through, or the entrance would be left paused at its from-state,\n    // stuck invisible. A finished entrance had progress 1, so it stays paused at\n    // the end — refresh/resize re-measures of completed text are unchanged.\n    // Scrub auto-syncs from scroll position on creation, so it opts out.\n    if (triggerPlayed && opts.scrub === undefined) {\n      const resume = prevProgress ?? 1\n      currentAnim.progress(resume)\n      if (resume < 1) {\n        // Not finished (mid-fade, or still in its delay) — keep playing, and\n        // re-warm the compositor hint for the freshly split targets\n        // (killCurrent cleared the old ones).\n        setWillChange()\n        currentAnim.play()\n      } else {\n        currentAnim.pause()\n      }\n    }\n  }\n\n  rebuild()\n\n  // Persistent trigger machinery — registered once. Callbacks close over\n  // `currentAnim` (mutable `let`) so subsequent rebuilds are transparent.\n  let triggerCleanup: () => void = () => {}\n\n  if (persistentTrigger?.kind === 'event' && persistentTrigger.eventName) {\n    triggerCleanup = subscribeWithPair({\n      element,\n      forwardName: persistentTrigger.eventName,\n      onForward: () => {\n        triggerPlayed = true\n        setWillChange()\n        // Restart from the beginning *including the delay* so an interrupted\n        // reverse doesn't leak forward AND `aa-delay` is honored on every fire.\n        // `play(0)` would skip the delay — GSAP's `delay` is a start-offset on\n        // the parent timeline, and time 0 sits after it, so a paused tween's\n        // delay never replays via play(0). `restart(true)` rewinds past the\n        // delay. timeScale is reset to 1 in case a prior reverse accelerated it;\n        // suppressEvents (default) keeps the rewind from firing the\n        // onReverseComplete that would clear the will-change we just set.\n        currentAnim?.timeScale(1).restart(true)\n      },\n      onReverse: () => {\n        triggerPlayed = false\n        setWillChange()\n        currentAnim?.timeScale(REVERSE_TIME_SCALE).reverse()\n      },\n    })\n  } else if (!isLoadOneShot && opts.scrub === undefined && persistentTrigger) {\n    triggerCleanup = bindAgainTrigger({\n      gsap: ctx.gsap,\n      trigger: triggerEl,\n      start: opts.scrollStart,\n      again: opts.again,\n      onPlay: () => {\n        triggerPlayed = true\n        setWillChange()\n        currentAnim?.play()\n      },\n      onReset: () => {\n        triggerPlayed = false\n        clearWillChange()\n        currentAnim?.progress(0).pause()\n      },\n    })\n  }\n  // Scrub path: the ScrollTrigger is bound to the animation's own vars —\n  // killed/recreated by rebuild(). No separate machinery here.\n\n  return {\n    rebuild,\n    dispose: () => {\n      triggerCleanup()\n      killCurrent()\n    },\n  }\n}\n","import { bindFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { readAnimationConfig, resolveAnchor } from '../../core/parse'\nimport { matchAnimateValue, type ResolvedPreset } from '../../core/presets'\nimport type { Config } from '../../core/settings'\nimport { collectStaggerTargets } from '../../core/stagger'\nimport { cssWillChange, setupTriggeredAnimation } from '../../core/triggered-animation'\nimport { resolveTriggers } from '../../core/trigger'\n\ntype FromState = Record<string, number | string>\n\nconst FROM_FOR: Record<string, (intensity: number) => FromState> = {\n  fade: () => ({ opacity: 0 }),\n  'fade-up': (i) => ({ y: `${2 * i}rem`, opacity: 0 }),\n  'fade-down': (i) => ({ y: `${-2 * i}rem`, opacity: 0 }),\n  'fade-left': (i) => ({ x: `${2 * i}rem`, opacity: 0 }),\n  'fade-right': (i) => ({ x: `${-2 * i}rem`, opacity: 0 }),\n  'zoom-in': (i) => ({ scale: Math.max(0, 1 - 0.15 * i), opacity: 0 }),\n  'zoom-out': (i) => ({ scale: 1 + 0.15 * i, opacity: 0 }),\n  'slide-up': (i) => ({ yPercent: 100 * i }),\n  'slide-down': (i) => ({ yPercent: -100 * i }),\n  'slide-left': (i) => ({ xPercent: 100 * i }),\n  'slide-right': (i) => ({ xPercent: -100 * i }),\n  blur: () => ({ opacity: 0, filter: 'blur(20px)' }),\n}\n\nconst STATIC_SUPPORTED = new Set(Object.keys(FROM_FOR))\n\nconst ROTATE_PATTERN = /^rotate(?:-up)?(?:-(?:tl|tr|bl|br))?(?:-ccw)?$/\n\nconst CORNER_TO_ORIGIN: Record<string, string> = {\n  tl: 'left top',\n  tr: 'right top',\n  bl: 'left bottom',\n  br: 'right bottom',\n}\n\nfunction isRotateValue(value: string): boolean {\n  return ROTATE_PATTERN.test(value)\n}\n\nfunction buildRotateFromState(value: string, intensity: number): FromState {\n  const ccw = value.endsWith('-ccw')\n  const cornerMatch = value.match(/-(tl|tr|bl|br)(?:-|$)/)\n  const corner = cornerMatch ? cornerMatch[1] : null\n  const up = /^rotate-up(?:-|$)/.test(value)\n  // CSS rotation: positive = clockwise tilt. We start at the inverse of the\n  // intended motion direction and animate back to 0, so a clockwise (default)\n  // entrance starts from a negative tilt; -ccw starts positive.\n  const degrees = 5 * intensity * (ccw ? 1 : -1)\n  const state: FromState = { rotation: degrees, opacity: 0 }\n  if (up) state.y = `${2 * intensity}rem`\n  if (corner) state.transformOrigin = CORNER_TO_ORIGIN[corner]\n  return state\n}\n\nfunction buildFromState(animate: string, intensity: number): FromState | undefined {\n  const builder = FROM_FOR[animate]\n  if (builder) return builder(intensity)\n  if (isRotateValue(animate)) return buildRotateFromState(animate, intensity)\n  return undefined\n}\n\nfunction isSupportedValue(value: string): boolean {\n  return STATIC_SUPPORTED.has(value) || isRotateValue(value)\n}\n\nfunction elementMatches(el: Element, presetMap: Map<Element, ResolvedPreset>): boolean {\n  return matchAnimateValue(el, presetMap, isSupportedValue)\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  element: Element,\n  config: Config,\n): (() => void) | undefined {\n  const animate = config['aa-animate']\n  if (!animate) return\n\n  const opts = ctx.options\n  const { duration, delay, ease, intensity, scrollStart, scrollEnd, scrub, again } =\n    readAnimationConfig(config, opts)\n\n  const triggers = resolveTriggers(element, config['aa-trigger'], ctx.options.breakpoints)\n  // `aa-trigger=\"lcp\"`: the companion CSS paints this element at ~0.01 opacity\n  // before the bundle (an eligible Largest Contentful Paint candidate). Because\n  // that floor is the element's *current* opacity when the tween is created,\n  // gsap.from() would read 0.01 as the destination — so we pin opacity:1 first\n  // (see buildAnimation). Transforms still resolve from natural CSS.\n  const isLcp = triggers.some((t) => t.kind === 'lcp')\n\n  const fromState = buildFromState(animate, intensity)\n  if (!fromState) return\n  // Start the fade from the CSS first-paint value (0.01) rather than 0, so the\n  // hand-off from the CSS placeholder to the GSAP tween has zero opacity change.\n  if (isLcp && fromState.opacity === 0) fromState.opacity = 0.01\n\n  const { targets, stagger } = collectStaggerTargets(element, config, opts)\n\n  const triggerEl = resolveAnchor(element, config['aa-anchor'])\n\n  // We use gsap.from() (not fromTo) so the natural CSS state of each target —\n  // its existing rotation, opacity, transform — is the destination. Authors\n  // can pre-style elements (e.g. a card with permanent rotate(8deg)) and the\n  // entrance still resolves to that state instead of clobbering it to 0.\n  const handle = setupTriggeredAnimation(ctx, element, {\n    triggers,\n    delay,\n    scrollStart,\n    scrollEnd,\n    scrub,\n    again,\n    triggerEl,\n    willChange: cssWillChange(fromState),\n    buildAnimation: (vars) => {\n      // For lcp, establish opacity:1 as the .from() destination, overriding the\n      // CSS 0.01 floor. set + from run synchronously, so from's immediateRender\n      // overwrites the 1 with the from-value before any paint — no flash.\n      if (isLcp) ctx.gsap.gsap.set(targets, { opacity: 1 })\n      const animation = ctx.gsap.gsap.from(targets, {\n        ...fromState,\n        duration,\n        ease,\n        stagger,\n        ...vars,\n      })\n      return { animation }\n    },\n  })\n\n  return handle ? () => handle.dispose() : undefined\n}\n\nconst appearFeature: FeatureModule = {\n  name: 'appear',\n  init(ctx: FeatureContext): () => void {\n    bindFeature(ctx, elementMatches, setupOne)\n    return () => {}\n  },\n}\n\nexport default appearFeature\n","import type { GsapHandle } from '../core/gsap-detect'\n\nexport type SplitMode = 'words' | 'chars' | 'lines'\n\nexport interface SplitConfig {\n  mode: SplitMode\n  /** When set, animation tools should group units by line (e.g. \"lines-chars\"). */\n  groupBy?: 'lines'\n  mask: boolean\n  /** When set, each split unit gets an inline `--char` / `--word` / `--line` CSS variable (1-based) for CSS-driven stagger. */\n  index: boolean\n}\n\nexport interface SplitResult {\n  mode: SplitMode\n  words: HTMLElement[]\n  chars: HTMLElement[]\n  lines: HTMLElement[]\n  revert: () => void\n}\n\ninterface SplitTextOptions {\n  type: string\n  autoSplit?: boolean\n  tag?: string\n  linesClass?: string\n  wordsClass?: string\n  charsClass?: string\n  mask?: string\n  propIndex?: boolean\n  aria?: 'auto' | 'hidden' | 'none'\n  onSplit?: (instance: SplitTextInstance) => void\n}\n\n// Tags where aria-label is permitted by the ARIA-in-HTML spec. Anything not in\n// this set (p, div, span, blockquote, …) gets a sibling sr-only clone instead,\n// because aria-label on those tags is flagged by axe/Lighthouse.\nconst ARIA_LABEL_ALLOWED = new Set([\n  'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n  'a', 'button', 'label', 'summary',\n])\n\nfunction tagAllowsAriaLabel(el: Element): boolean {\n  return ARIA_LABEL_ALLOWED.has(el.tagName.toLowerCase())\n}\n\n// Interactive descendants whose presence rules out aria-hiding the split target:\n// hiding the element (or its split children) would orphan these from assistive\n// tech while they remain keyboard-focusable — axe's \"aria-hidden contains\n// focusable descendant\" — and a plain-text screen-reader clone silently drops\n// them from the accessibility tree entirely. `tabindex=\"-1\"` is excluded: it's\n// not in the tab order, so it isn't flagged.\nconst FOCUSABLE_DESCENDANT_SELECTOR =\n  'a[href], button, input, select, textarea, iframe, audio[controls], video[controls],' +\n  ' [contenteditable=\"\"], [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])'\n\nfunction hasFocusableDescendant(el: Element): boolean {\n  return el.querySelector(FOCUSABLE_DESCENDANT_SELECTOR) !== null\n}\n\ninterface SplitTextInstance {\n  words: HTMLElement[]\n  chars: HTMLElement[]\n  lines: HTMLElement[]\n  revert: () => void\n}\n\ntype SplitTextCtor = new (target: Element | string, opts: SplitTextOptions) => SplitTextInstance\n\nexport function parseSplit(value: string | undefined): SplitConfig | null {\n  if (!value) return null\n  const head = value.split('|')[0].trim().toLowerCase()\n  if (!head) return null\n  const tokens = head.split(/\\s+/)\n  const modeToken = tokens[0]\n  let mode: SplitMode | null = null\n  let groupBy: 'lines' | undefined\n  if (modeToken === 'words' || modeToken === 'word') mode = 'words'\n  else if (modeToken === 'chars' || modeToken === 'char') mode = 'chars'\n  else if (modeToken === 'lines' || modeToken === 'line') mode = 'lines'\n  else if (modeToken === 'lines-chars' || modeToken === 'line-chars') {\n    mode = 'chars'\n    groupBy = 'lines'\n  } else if (modeToken === 'lines-words' || modeToken === 'line-words') {\n    mode = 'words'\n    groupBy = 'lines'\n  }\n  if (!mode) return null\n  const flags = tokens.slice(1)\n  const mask = flags.includes('mask')\n  const index = flags.includes('index')\n  return groupBy ? { mode, groupBy, mask, index } : { mode, mask, index }\n}\n\ninterface ApplyOptions {\n  /** When true, wrap each line in an `overflow: clip` wrapper. Per-char/word masks aren't useful for slide animations — the wrapper would trap the moving unit. */\n  mask?: boolean\n  /** When true, expose 1-based `--char` / `--word` / `--line` CSS variables on each split unit for CSS-driven stagger. */\n  index?: boolean\n  /**\n   * Called when SplitText auto-re-splits (e.g. the viewport resizes within a\n   * breakpoint and line wrapping changes). The original `.aa-char`/`.aa-line`\n   * DOM nodes are replaced by fresh ones, so any GSAP tween still pointing at\n   * the old nodes silently animates orphaned elements. Callers should use\n   * this hook to tear down the previous tween/trigger and rebuild against\n   * the new SplitResult.\n   *\n   * NOT fired on the initial split — use the synchronous return value of\n   * `applySplit()` for first-time setup.\n   */\n  onResplit?: (split: SplitResult) => void\n}\n\nexport function applySplit(\n  element: Element,\n  mode: SplitMode,\n  gsapHandle: GsapHandle | null,\n  opts: ApplyOptions = {},\n): SplitResult {\n  const SplitTextCtor = gsapHandle?.plugins?.SplitText as SplitTextCtor | undefined\n  if (!SplitTextCtor) {\n    console.warn('[alrdy-animate] aa-split requires the GSAP SplitText plugin.')\n    return { mode, words: [], chars: [], lines: [element as HTMLElement], revert: () => {} }\n  }\n  // Chars mode keeps 'words' so each word stays an atomic inline-block box that\n  // can't break mid-word. Without it, SplitText's line measurement can assign\n  // part of a word to one `.aa-line` and the rest to the next (Safari-specific,\n  // worsened by mid-text inline-block sub-spans). Char tweens still hit `.aa-char`.\n  const type =\n    mode === 'lines'\n      ? 'lines'\n      : mode === 'words'\n        ? 'words,lines'\n        : 'words,chars,lines'\n  const splitOpts: SplitTextOptions = {\n    type,\n    // span wrappers keep the produced markup spec-valid in any context\n    // (`<span>` / `<a>` / `<button>` containers can't legally hold `<div>`).\n    // SplitText's default of `tag: \"div\"` would inline-inject `display:\n    // inline-block` / `block`, but we ship those rules in alrdy-animate.css\n    // for `.aa-char` / `.aa-word` / `.aa-line` so layout is preserved.\n    tag: 'span',\n    // autoSplit re-runs SplitText when line wrapping changes (typical case:\n    // user resizes the viewport within a breakpoint and the text re-wraps).\n    // Without this, lines stay frozen at their original measurements while\n    // the underlying text reflows — `text-slide-up`-style line masks would\n    // visibly clip or gap. The catch is that auto-resplit replaces the\n    // `.aa-char` / `.aa-line` DOM nodes, leaving previously-built GSAP tweens\n    // pointing at orphaned elements. The companion `onResplit` hook below\n    // wires a callback so the caller can rebuild its animation against the\n    // new nodes.\n    autoSplit: true,\n    linesClass: 'aa-line',\n    wordsClass: 'aa-word',\n    charsClass: 'aa-char',\n  }\n  // mask is always line-level: per-char/word masks would trap the moving unit.\n  if (opts.mask) splitOpts.mask = 'lines'\n  if (opts.index) splitOpts.propIndex = true\n\n  // SplitText's onSplit fires both for the initial split (synchronously inside\n  // the constructor) and for every resize-driven re-split. We skip the first\n  // call so the caller can keep its existing synchronous setup path using the\n  // return value of `applySplit()`. Subsequent calls deliver the new split to\n  // `onResplit` for rebuilds.\n  if (opts.onResplit) {\n    const onResplit = opts.onResplit\n    let initialFired = false\n    splitOpts.onSplit = (inst) => {\n      if (!initialFired) {\n        initialFired = true\n        return\n      }\n      onResplit({\n        mode,\n        words: inst.words ?? [],\n        chars: inst.chars ?? [],\n        lines: inst.lines ?? [],\n        // Re-splits replace the DOM via SplitText itself; the outer revert()\n        // captured below handles full teardown. Per-resplit revert is a no-op.\n        revert: () => {},\n      })\n    }\n  }\n\n  const allowAriaLabel = tagAllowsAriaLabel(element)\n  let srSpan: HTMLSpanElement | null = null\n  let priorAriaHidden: string | null = null\n  let didHide = false\n  if (hasFocusableDescendant(element)) {\n    // Element contains interactive content (e.g. a link inside an FAQ\n    // paragraph). Neither aria-hiding strategy is safe here — both would strand\n    // the focusable child outside the accessibility tree. Leave the element in\n    // the tree and split without aria changes; the descendants stay reachable\n    // and screen readers read the inline split spans fine.\n    splitOpts.aria = 'none'\n  } else if (allowAriaLabel) {\n    splitOpts.aria = 'auto'\n  } else {\n    splitOpts.aria = 'none'\n    priorAriaHidden = element.getAttribute('aria-hidden')\n    element.setAttribute('aria-hidden', 'true')\n    didHide = true\n    const text = element.textContent ?? ''\n    if (text.trim() && element.parentElement) {\n      srSpan = document.createElement('span')\n      srSpan.className = 'aa-sr-only'\n      srSpan.textContent = text\n      element.parentElement.insertBefore(srSpan, element)\n    }\n  }\n\n  const inst = new SplitTextCtor(element, splitOpts)\n  return {\n    mode,\n    words: inst.words ?? [],\n    chars: inst.chars ?? [],\n    lines: inst.lines ?? [],\n    revert: () => {\n      try {\n        inst.revert()\n      } catch {\n        /* already reverted */\n      }\n      if (srSpan) srSpan.remove()\n      if (didHide) {\n        if (priorAriaHidden === null) element.removeAttribute('aria-hidden')\n        else element.setAttribute('aria-hidden', priorAriaHidden)\n      }\n    },\n  }\n}\n","import type { GsapTimeline } from '../../core/gsap-detect'\nimport { bindFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { readAnimationConfig } from '../../core/parse'\nimport { matchAnimateValue, type ResolvedPreset } from '../../core/presets'\nimport type { Config } from '../../core/settings'\nimport {\n  buildStagger,\n  defaultStaggerFor,\n  parseStaggerSpec,\n  type StaggerValue,\n} from '../../core/stagger'\nimport {\n  setupTriggeredAnimation,\n  toTimelineVars,\n  type TriggerVars,\n} from '../../core/triggered-animation'\nimport { resolveTriggers } from '../../core/trigger'\nimport { applySplit, parseSplit, type SplitMode, type SplitResult } from '../../split/runtime'\n\ntype GsapTarget = Element | Element[] | NodeList\ntype State = Record<string, number | string>\n\ninterface SetupParams {\n  element: Element\n  split: SplitResult\n  intensity: number\n}\n\ninterface SetupResult {\n  targets: GsapTarget\n  fromState: State\n  toState: State\n  cleanup?: () => void\n}\n\ninterface TextAnim {\n  defaultSplit: SplitMode\n  maskLines?: boolean\n  /** Simple path: just animate the split parts from `buildFrom` to `to`. */\n  buildFrom?: (intensity: number) => State\n  to?: State\n  /** Complex path: wrap lines, set up custom targets/states. */\n  setup?: (params: SetupParams) => SetupResult\n}\n\nconst OVAL_LINE_STYLE = 'overflow: clip; display: block;'\nconst PERSPECTIVE_LINE_STYLE = 'transform-style: preserve-3d; display: block;'\n\nfunction wrapLines(\n  lines: HTMLElement[],\n  className: string,\n  inlineStyle: string,\n  perElement?: (wrapper: HTMLElement) => void,\n): HTMLElement[] {\n  const wrappers: HTMLElement[] = []\n  for (const line of lines) {\n    const wrapper = document.createElement('div')\n    wrapper.classList.add(className)\n    wrapper.setAttribute('style', inlineStyle)\n    if (perElement) perElement(wrapper)\n    line.parentNode?.insertBefore(wrapper, line)\n    wrapper.appendChild(line)\n    wrappers.push(wrapper)\n  }\n  return wrappers\n}\n\nfunction unwrapLines(wrappers: HTMLElement[]): void {\n  for (const w of wrappers) {\n    const child = w.firstElementChild\n    if (child && w.parentNode) {\n      w.parentNode.insertBefore(child, w)\n      w.remove()\n    }\n  }\n}\n\n// Direction → (axis, sign) lookup used by fade/blur/slide/tilt builders.\n// `Y` maps to `yPercent`, `X` maps to `xPercent`. `sign === 1` means the\n// element starts off-screen on the *opposite* axis (up → starts below).\ntype Direction = 'up' | 'down' | 'left' | 'right'\nconst DIR_AXIS: Record<Direction, { prop: 'yPercent' | 'xPercent'; sign: 1 | -1 }> = {\n  up: { prop: 'yPercent', sign: 1 },\n  down: { prop: 'yPercent', sign: -1 },\n  left: { prop: 'xPercent', sign: 1 },\n  right: { prop: 'xPercent', sign: -1 },\n}\n\nfunction fadeAnim(opacity: number, direction?: Direction): TextAnim {\n  if (!direction) {\n    return {\n      defaultSplit: 'chars',\n      buildFrom: () => ({ opacity }),\n      to: { opacity: 1 },\n    }\n  }\n  const { prop, sign } = DIR_AXIS[direction]\n  return {\n    defaultSplit: 'chars',\n    buildFrom: (i) => ({ opacity, [prop]: 60 * sign * i }),\n    to: { opacity: 1, [prop]: 0 },\n  }\n}\n\nfunction blurAnim(direction?: Direction): TextAnim {\n  if (!direction) {\n    return {\n      defaultSplit: 'chars',\n      buildFrom: () => ({ opacity: 0, filter: 'blur(20px)' }),\n      to: { opacity: 1, filter: 'blur(0px)' },\n    }\n  }\n  const { prop, sign } = DIR_AXIS[direction]\n  const offsetProp = prop === 'yPercent' ? 'y' : 'x'\n  return {\n    defaultSplit: 'chars',\n    buildFrom: (i) => ({ opacity: 0, filter: 'blur(10px)', [offsetProp]: `${2 * sign * i}rem` }),\n    to: { opacity: 1, filter: 'blur(0px)', [offsetProp]: 0 },\n  }\n}\n\nfunction scaleAnim(origin: '50% 50%' | '50% 100%' | '50% 0%'): TextAnim {\n  return {\n    defaultSplit: 'chars',\n    buildFrom: () => ({ scaleY: 0, transformOrigin: origin }),\n    to: { scaleY: 1 },\n  }\n}\n\nfunction slideAnim(direction: 'up' | 'down'): TextAnim {\n  const sign = direction === 'up' ? 1 : -1\n  return {\n    defaultSplit: 'lines',\n    maskLines: true,\n    buildFrom: () => ({ yPercent: 110 * sign }),\n    to: { yPercent: 0 },\n  }\n}\n\nfunction tiltAnim(direction: 'up' | 'down'): TextAnim {\n  const sign = direction === 'up' ? 1 : -1\n  return {\n    defaultSplit: 'lines',\n    maskLines: true,\n    buildFrom: () => ({\n      yPercent: 110 * sign,\n      opacity: 0,\n      rotation: 10 * sign,\n      transformOrigin: direction === 'up' ? 'bottom left' : 'top left',\n    }),\n    to: { yPercent: 0, opacity: 1, rotation: 0 },\n  }\n}\n\nfunction ovalAnim(origin: 'top' | 'bottom'): TextAnim {\n  const at = origin === 'bottom' ? '50% 100%' : '50% 0%'\n  return {\n    defaultSplit: 'lines',\n    setup: ({ split }) => {\n      const wrappers = wrapLines(split.lines, 'aa-oval-line', OVAL_LINE_STYLE)\n      return {\n        targets: wrappers,\n        fromState: { clipPath: `ellipse(20% 0% at ${at})` },\n        toState: { clipPath: `ellipse(100% 120% at ${at})` },\n        cleanup: () => unwrapLines(wrappers),\n      }\n    },\n  }\n}\n\n// Per-animation entries declare only structural defaults: which split mode the\n// animation expects and whether lines are masked. All timing — duration, ease,\n// stagger — flows from init({...}); stagger varies per split mode via\n// defaultStaggerFor().\nconst TEXT_ANIMS: Record<string, TextAnim> = {\n  'text-fade': fadeAnim(0),\n  'text-fade-30': fadeAnim(0.3),\n  'text-fade-10': fadeAnim(0.1),\n  'text-fade-up': fadeAnim(0, 'up'),\n  'text-fade-down': fadeAnim(0, 'down'),\n  'text-fade-left': fadeAnim(0, 'left'),\n  'text-fade-right': fadeAnim(0, 'right'),\n\n  'text-blur': blurAnim(),\n  'text-blur-up': blurAnim('up'),\n  'text-blur-down': blurAnim('down'),\n  'text-blur-left': blurAnim('left'),\n  'text-blur-right': blurAnim('right'),\n\n  'text-scale': scaleAnim('50% 50%'),\n  'text-scale-up': scaleAnim('50% 100%'),\n  'text-scale-down': scaleAnim('50% 0%'),\n\n  'text-slide-up': slideAnim('up'),\n  'text-slide-down': slideAnim('down'),\n\n  'text-tilt-up': tiltAnim('up'),\n  'text-tilt-down': tiltAnim('down'),\n\n  'text-oval-up': ovalAnim('bottom'),\n  'text-oval-down': ovalAnim('top'),\n\n  'text-rotate': {\n    defaultSplit: 'lines',\n    setup: ({ element, split }) => {\n      const fontSize = parseFloat(window.getComputedStyle(element).fontSize) || 16\n      const perspective = `${fontSize * 5}px`\n      const wrappers = wrapLines(\n        split.lines,\n        'aa-perspective-line',\n        PERSPECTIVE_LINE_STYLE,\n        (w) => {\n          w.style.perspective = perspective\n        },\n      )\n      for (const line of split.lines) {\n        line.style.transformOrigin = '50% 0%'\n      }\n      return {\n        targets: split.lines,\n        fromState: { autoAlpha: 0, rotateX: -90, yPercent: 100, scaleX: 0.75 },\n        toState: { autoAlpha: 1, rotateX: 0, yPercent: 0, scaleX: 1 },\n        cleanup: () => unwrapLines(wrappers),\n      }\n    },\n  },\n}\n\ntype AxisLetter = 'X' | 'Y'\n\ninterface BarDirection {\n  axis: AxisLetter\n  growOrigin: string\n  shrinkOrigin: string\n  textAxis: 'x' | 'y'\n  textOffset: string\n}\n\n// Direction names match v7: the named edge is where the bar exits to, so\n// \"right\" sweeps left → right, \"up\" sweeps bottom → top, etc.\nconst BAR_DIRECTIONS: Record<string, BarDirection> = {\n  right: {\n    axis: 'X',\n    growOrigin: 'left center',\n    shrinkOrigin: 'right center',\n    textAxis: 'x',\n    textOffset: '-0.6em',\n  },\n  left: {\n    axis: 'X',\n    growOrigin: 'right center',\n    shrinkOrigin: 'left center',\n    textAxis: 'x',\n    textOffset: '0.6em',\n  },\n  up: {\n    axis: 'Y',\n    growOrigin: 'bottom center',\n    shrinkOrigin: 'top center',\n    textAxis: 'y',\n    textOffset: '0.6em',\n  },\n  down: {\n    axis: 'Y',\n    growOrigin: 'top center',\n    shrinkOrigin: 'bottom center',\n    textAxis: 'y',\n    textOffset: '-0.6em',\n  },\n}\n\nconst BAR_NAMES = new Set<string>()\nfor (const dirName of Object.keys(BAR_DIRECTIONS)) {\n  BAR_NAMES.add(`text-block-${dirName}`)\n  BAR_NAMES.add(`text-marker-${dirName}`)\n}\n\nfunction parseBarName(name: string): { mode: 'block' | 'marker'; dir: BarDirection } | null {\n  const m = name.match(/^text-(block|marker)-(up|down|left|right)$/)\n  if (!m) return null\n  return { mode: m[1] as 'block' | 'marker', dir: BAR_DIRECTIONS[m[2]] }\n}\n\nfunction resolveBarColor(value: string | undefined, element: Element): string {\n  if (!value) return 'currentColor'\n  const trimmed = value.trim()\n  if (trimmed.startsWith('--')) {\n    const resolved = window.getComputedStyle(element).getPropertyValue(trimmed).trim()\n    return resolved || trimmed\n  }\n  return trimmed\n}\n\ninterface BarLineSetup {\n  bar: HTMLElement\n  text: HTMLElement | null\n}\n\nfunction buildBarLines(\n  lines: HTMLElement[],\n  color: string,\n  withTextWrapper: boolean,\n): BarLineSetup[] {\n  const setups: BarLineSetup[] = []\n  for (const line of lines) {\n    // Negative margin tightens line spacing so adjacent bars touch when\n    // line-height is around 1.0; the matching negative inset on the bar\n    // extends it slightly above/below the text bounds.\n    line.style.display = 'inline-block'\n    line.style.position = 'relative'\n    line.style.margin = '-0.055em 0'\n\n    let text: HTMLElement | null = null\n    if (withTextWrapper) {\n      text = document.createElement('span')\n      text.className = 'aa-block-text'\n      text.style.display = 'inline-block'\n      text.style.willChange = 'transform, opacity'\n      while (line.firstChild) text.appendChild(line.firstChild)\n      line.appendChild(text)\n    }\n\n    const bar = document.createElement('div')\n    bar.className = 'aa-bar'\n    bar.style.cssText =\n      'position:absolute;inset:-0.055em 0;pointer-events:none;z-index:1;will-change:transform;'\n    bar.style.backgroundColor = color\n    line.appendChild(bar)\n\n    setups.push({ bar, text })\n  }\n  return setups\n}\n\nconst SUPPORTED = new Set([...Object.keys(TEXT_ANIMS), ...BAR_NAMES])\n\nfunction elementMatches(el: Element, presetMap: Map<Element, ResolvedPreset>): boolean {\n  return matchAnimateValue(el, presetMap, (v) => SUPPORTED.has(v))\n}\n\nfunction pickSimpleTargets(\n  parts: { words: HTMLElement[]; chars: HTMLElement[]; lines: HTMLElement[] },\n  mode: SplitMode,\n): HTMLElement[] {\n  if (mode === 'chars') return parts.chars\n  if (mode === 'lines') return parts.lines\n  return parts.words\n}\n\nfunction setupBarReveal(\n  ctx: FeatureContext,\n  element: Element,\n  config: Config,\n  parsed: { mode: 'block' | 'marker'; dir: BarDirection },\n): (() => void) | undefined {\n  const { mode, dir } = parsed\n  const isBlock = mode === 'block'\n  const opts = ctx.options\n  const { duration, delay, ease, scrollStart, scrollEnd, scrub, again } =\n    readAnimationConfig(config, opts)\n  const { unit: stagger } = parseStaggerSpec(config['aa-stagger'], defaultStaggerFor('lines', opts))\n\n  const scaleProp = `scale${dir.axis}`\n\n  // Build the per-line phased timeline from the current bar/text setups.\n  // Two-phase for block mode (grow-in, then shrink-out + text fade-in);\n  // single-phase for marker (shrink-out reveals text underneath).\n  const buildTimelineFromSetups = (\n    setups: BarLineSetup[],\n    vars: TriggerVars,\n  ): GsapTimeline => {\n    const tl = ctx.gsap.gsap.timeline(toTimelineVars(vars))\n    setups.forEach(({ bar, text }, i) => {\n      const lineTl = ctx.gsap.gsap.timeline()\n      if (isBlock) {\n        const revealDur = duration * 0.4\n        const shrinkDur = duration * 0.6\n        const textDur = duration * 0.4\n        // Phase 1: bar grows in from the entry edge.\n        lineTl.fromTo(\n          bar,\n          { [scaleProp]: 0, transformOrigin: dir.growOrigin },\n          { [scaleProp]: 1, duration: revealDur, ease },\n        )\n        // Flip the origin between phases. Using `.set()` here (rather than\n        // a second fromTo) is the only pattern that survives the\n        // `tl.progress(0).pause()` reset used by the again-trigger:\n        // transformOrigin is non-tweenable, so a fromTo's from-state isn't\n        // restored on rewind, leaving the origin stuck at `growOrigin` for\n        // phase 2 of every subsequent play.\n        lineTl.set(bar, { transformOrigin: dir.shrinkOrigin })\n        // Phase 2: shrink toward the exit edge from the current scale.\n        lineTl.to(bar, { [scaleProp]: 0, duration: shrinkDur, ease })\n        if (text) {\n          // Anchor to the start of phase 2 (one tween + one set back from here).\n          lineTl.fromTo(\n            text,\n            { opacity: 0, [dir.textAxis]: dir.textOffset },\n            { opacity: 1, [dir.textAxis]: 0, duration: textDur, ease },\n            `<`,\n          )\n        }\n      } else {\n        lineTl.fromTo(\n          bar,\n          { [scaleProp]: 1, transformOrigin: dir.shrinkOrigin },\n          { [scaleProp]: 0, duration, ease },\n        )\n      }\n      tl.add(lineTl, i * stagger)\n    })\n    return tl\n  }\n\n  // Tracks the per-split bar/text wrappers so the buildAnimation callback\n  // (called once initially, then on every SplitText resplit) sees the\n  // latest DOM. Each rebuild also re-applies the initial state explicitly\n  // so the staggered timeline shows correct positions at time 0.\n  let setups: BarLineSetup[] = []\n\n  let split: SplitResult | undefined\n\n  const initialSplit = applySplit(element, 'lines', ctx.gsap, {\n    onResplit: (newSplit) => {\n      split = newSplit\n      handle?.rebuild()\n    },\n  })\n  if (initialSplit.lines.length === 0) {\n    initialSplit.revert()\n    return undefined\n  }\n  split = initialSplit\n\n  const handle = setupTriggeredAnimation(ctx, element, {\n    triggers: resolveTriggers(element, config['aa-trigger'], ctx.options.breakpoints),\n    delay,\n    scrollStart,\n    scrollEnd,\n    scrub,\n    again,\n    buildAnimation: (vars) => {\n      if (!split || split.lines.length === 0) return null\n      const color = resolveBarColor(config['aa-color'], element)\n      setups = buildBarLines(split.lines, color, isBlock)\n      // Lock initial states explicitly so the element looks correct at\n      // time 0 regardless of when each per-line tween starts.\n      for (const { bar, text } of setups) {\n        ctx.gsap.gsap.set(bar, {\n          [scaleProp]: isBlock ? 0 : 1,\n          transformOrigin: isBlock ? dir.growOrigin : dir.shrinkOrigin,\n        })\n        if (text) {\n          ctx.gsap.gsap.set(text, { opacity: 0, [dir.textAxis]: dir.textOffset })\n        }\n      }\n      const animation = buildTimelineFromSetups(setups, vars)\n      return { animation }\n    },\n  })\n\n  return () => {\n    handle?.dispose()\n    initialSplit.revert()\n  }\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  element: Element,\n  config: Config,\n): (() => void) | undefined {\n  const animate = config['aa-animate']\n  if (!animate || !SUPPORTED.has(animate)) return undefined\n  const bar = parseBarName(animate)\n  if (bar) return setupBarReveal(ctx, element, config, bar)\n  const anim = TEXT_ANIMS[animate]\n\n  const opts = ctx.options\n  const { duration, delay, ease, intensity, scrollStart, scrollEnd, scrub, again } =\n    readAnimationConfig(config, opts)\n\n  const userSplit = parseSplit(config['aa-split'])\n  const splitMode = userSplit?.mode ?? anim.defaultSplit\n  const staggerSpec = parseStaggerSpec(\n    config['aa-stagger'],\n    defaultStaggerFor(splitMode, opts),\n    defaultStaggerFor('lines', opts),\n  )\n  const stagger: StaggerValue = buildStagger(staggerSpec.unit, staggerSpec.flags)\n  const lineStagger = staggerSpec.line\n  const lineGrouped = userSplit?.groupBy === 'lines' && !anim.setup\n  // Absence of the `mask` flag in aa-split means \"I'm just naming the split\n  // mode\" — don't force-disable masks that the animation enables by default.\n  // Users who want masks off entirely simply pick an animation that has none.\n  const mask = userSplit?.mask || anim.maskLines || false\n\n  // Tracks the current split — reassigned on each SplitText auto-resplit\n  // (resize within a breakpoint changes line wrapping) so the buildAnimation\n  // callback below always reads the live `.aa-char` / `.aa-line` DOM.\n  let split: SplitResult | undefined\n\n  const initialSplit = applySplit(element, splitMode, ctx.gsap, {\n    mask,\n    ...(userSplit?.index ? { index: true } : {}),\n    onResplit: (newSplit) => {\n      split = newSplit\n      handle?.rebuild()\n    },\n  })\n  split = initialSplit\n\n  const handle = setupTriggeredAnimation(ctx, element, {\n    triggers: resolveTriggers(element, config['aa-trigger'], ctx.options.breakpoints),\n    delay,\n    scrollStart,\n    scrollEnd,\n    scrub,\n    again,\n    // Hint the compositor for the split units (chars/words/lines) only while\n    // the tween runs; the orchestrator clears it on settle. Covers the full\n    // text-animation footprint (transform + opacity, plus filter for blur).\n    // Replaces the old permanent will-change on the global .aa-char/.aa-word\n    // CSS rule, which left a never-reclaimed layer per split unit.\n    willChange: 'transform, opacity, filter',\n    buildAnimation: (vars) => {\n      if (!split) return null\n      let targets: GsapTarget\n      let fromState: State\n      let toState: State\n      let extraCleanup: (() => void) | undefined\n      let lineGroups: HTMLElement[][] | undefined\n      if (anim.setup) {\n        // anim.setup paths (oval, rotate) wrap lines in extra DOM and\n        // return a cleanup that unwraps them. The orchestrator runs this\n        // cleanup before the next rebuild and on dispose.\n        const result = anim.setup({ element, split, intensity })\n        targets = result.targets\n        fromState = result.fromState\n        toState = result.toState\n        if (result.cleanup) extraCleanup = result.cleanup\n      } else {\n        if (!anim.buildFrom || !anim.to) return null\n        const simple = pickSimpleTargets(split, splitMode)\n        if (simple.length === 0) return null\n        targets = simple\n        fromState = anim.buildFrom(intensity)\n        toState = anim.to\n        if (lineGrouped) {\n          const inner = splitMode === 'words' ? split.words : split.chars\n          lineGroups = split.lines.map((line) => inner.filter((u) => line.contains(u)))\n        }\n      }\n      const tl = ctx.gsap.gsap.timeline(toTimelineVars(vars))\n      // Lock the resting state explicitly so a paused-at-0 timeline shows\n      // the from-state visually, not whatever GSAP computes from a stale\n      // layout. Redundant for unpaused load tweens but harmless.\n      ctx.gsap.gsap.set(targets, fromState)\n      if (lineGroups) {\n        for (let i = 0; i < lineGroups.length; i++) {\n          const group = lineGroups[i]\n          if (group.length === 0) continue\n          tl.fromTo(group, fromState, { ...toState, duration, ease, stagger }, i * lineStagger)\n        }\n      } else {\n        tl.fromTo(targets, fromState, { ...toState, duration, ease, stagger })\n      }\n      const built: { animation: GsapTimeline; cleanup?: () => void } = { animation: tl }\n      if (extraCleanup) built.cleanup = extraCleanup\n      return built\n    },\n  })\n\n  return () => {\n    handle?.dispose()\n    initialSplit.revert()\n  }\n}\n\nconst textFeature: FeatureModule = {\n  name: 'text',\n  init(ctx: FeatureContext): () => void {\n    bindFeature(ctx, elementMatches, setupOne)\n    return () => {}\n  },\n}\n\nexport default textFeature\n","import { bindFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { readAnimationConfig, resolveAnchor } from '../../core/parse'\nimport { matchAnimateValue, type ResolvedPreset } from '../../core/presets'\nimport type { Config } from '../../core/settings'\nimport { collectStaggerTargets } from '../../core/stagger'\nimport { cssWillChange, setupTriggeredAnimation } from '../../core/triggered-animation'\nimport { resolveTriggers } from '../../core/trigger'\n\ninterface RevealClip {\n  from: string\n  to: string\n  needsOpacity?: boolean\n}\n\nconst REVEAL_CLIPS: Record<string, RevealClip> = {\n  'reveal-up': { from: 'inset(100% 0 0 0)', to: 'inset(0% 0 0 0)' },\n  'reveal-down': { from: 'inset(0 0 100% 0)', to: 'inset(0 0 0% 0)' },\n  'reveal-left': { from: 'inset(0 0 0 100%)', to: 'inset(0 0 0 0%)' },\n  'reveal-right': { from: 'inset(0 100% 0 0)', to: 'inset(0 0% 0 0)' },\n  'reveal-center': {\n    from: 'circle(0% at 50% 50%)',\n    to: 'circle(150% at 50% 50%)',\n    needsOpacity: true,\n  },\n  'reveal-oval-up': {\n    from: 'ellipse(0% 0% at 50% 100%)',\n    to: 'ellipse(150% 150% at 50% 100%)',\n  },\n  'reveal-oval-down': {\n    from: 'ellipse(0% 0% at 50% 0%)',\n    to: 'ellipse(150% 150% at 50% 0%)',\n  },\n}\n\nconst CLIP_VARIANTS = new Set(Object.keys(REVEAL_CLIPS))\n\nfunction isSupported(name: string): boolean {\n  return CLIP_VARIANTS.has(name)\n}\n\nfunction elementMatches(el: Element, presetMap: Map<Element, ResolvedPreset>): boolean {\n  return matchAnimateValue(el, presetMap, isSupported)\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  element: Element,\n  config: Config,\n): (() => void) | undefined {\n  const animate = config['aa-animate']\n  if (!animate) return undefined\n  const reveal = REVEAL_CLIPS[animate]\n  if (!reveal) return undefined\n\n  const opts = ctx.options\n  const { duration, delay, ease, scrollStart, scrollEnd, scrub, again } =\n    readAnimationConfig(config, opts)\n\n  const fromState: Record<string, number | string> = reveal.needsOpacity\n    ? { clipPath: reveal.from, opacity: 0 }\n    : { clipPath: reveal.from }\n  const toState: Record<string, number | string> = reveal.needsOpacity\n    ? { clipPath: reveal.to, opacity: 1 }\n    : { clipPath: reveal.to }\n\n  const { targets, stagger } = collectStaggerTargets(element, config, opts)\n\n  const triggerEl = resolveAnchor(element, config['aa-anchor'])\n\n  const handle = setupTriggeredAnimation(ctx, element, {\n    triggers: resolveTriggers(element, config['aa-trigger'], ctx.options.breakpoints),\n    delay,\n    scrollStart,\n    scrollEnd,\n    scrub,\n    again,\n    triggerEl,\n    willChange: cssWillChange(fromState),\n    buildAnimation: (vars) => {\n      const animation = ctx.gsap.gsap.fromTo(targets, fromState, {\n        ...toState,\n        duration,\n        ease,\n        stagger,\n        ...vars,\n      })\n      return { animation }\n    },\n  })\n\n  return handle ? () => handle.dispose() : undefined\n}\n\nconst revealFeature: FeatureModule = {\n  name: 'reveal',\n  init(ctx: FeatureContext): () => void {\n    bindFeature(ctx, elementMatches, setupOne)\n    return () => {}\n  },\n}\n\nexport default revealFeature\n","import { bindFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { parseNum, readAnimationConfig } from '../../core/parse'\nimport { matchAnimateValue, type ResolvedPreset } from '../../core/presets'\nimport type { Config } from '../../core/settings'\nimport { defaultStaggerFor } from '../../core/stagger'\nimport { setupTriggeredAnimation } from '../../core/triggered-animation'\nimport { resolveTriggers } from '../../core/trigger'\n\ntype Direction = 'up' | 'down' | 'left' | 'right'\ntype Mode = 'reveal' | 'cover'\n\ninterface SlicesParams {\n  direction: Direction\n  mode: Mode\n  rows: number\n}\n\nconst DIRECTIONS: Record<string, Direction> = {\n  '': 'up',\n  up: 'up',\n  down: 'down',\n  left: 'left',\n  right: 'right',\n}\n\n/**\n * `aa-animate` for slices is direction-suffixed; mode and row count are\n * space-separated flags on the same attribute:\n *   slices                 → reveal, up, 6 rows (defaults)\n *   slices-down            → reveal, down, 6 rows\n *   slices-right 12        → reveal, right, 12 rows\n *   slices-left cover 8    → cover, left, 8 rows\n *   slices 12 cover        → cover, up, 12 rows (order-independent flags)\n */\nexport function parseSlicesValue(value: string): SlicesParams | null {\n  const tokens = value.trim().split(/\\s+/)\n  const head = tokens[0]\n  if (head !== 'slices' && !head.startsWith('slices-')) return null\n  const dirToken = head === 'slices' ? '' : head.slice('slices-'.length)\n  const direction = DIRECTIONS[dirToken]\n  if (!direction) return null\n\n  let mode: Mode = 'reveal'\n  let rows = 6\n  for (const token of tokens.slice(1)) {\n    if (token === 'cover' || token === 'reveal') {\n      mode = token\n      continue\n    }\n    const n = parseInt(token, 10)\n    if (Number.isFinite(n) && n > 0) rows = n\n  }\n  return { direction, mode, rows }\n}\n\nfunction isSupported(value: string): boolean {\n  return parseSlicesValue(value) !== null\n}\n\nfunction elementMatches(el: Element, presetMap: Map<Element, ResolvedPreset>): boolean {\n  return matchAnimateValue(el, presetMap, isSupported)\n}\n\ninterface AxisConfig {\n  flexDirection: 'column' | 'row'\n  marginAxis: 'margin-bottom' | 'margin-right'\n  scaleProp: 'scaleY' | 'scaleX'\n  /** Anchor edge during the scale. In reveal mode the origin is the *same*\n   *  side as the named direction so each slice collapses toward the next\n   *  still-covered slice (the bottom slice on `slices-up` shrinks upward into\n   *  the slice above). In cover mode the origin is the *opposite* side so the\n   *  slice grows in the named direction. */\n  revealOrigin: 'top center' | 'bottom center' | 'left center' | 'right center'\n  coverOrigin: 'top center' | 'bottom center' | 'left center' | 'right center'\n  /** Stagger order so the cumulative reveal sweeps *toward* the named direction. */\n  staggerFrom: 'start' | 'end'\n}\n\nconst AXIS: Record<Direction, AxisConfig> = {\n  up: {\n    flexDirection: 'column',\n    marginAxis: 'margin-bottom',\n    scaleProp: 'scaleY',\n    revealOrigin: 'top center',\n    coverOrigin: 'bottom center',\n    staggerFrom: 'end',\n  },\n  down: {\n    flexDirection: 'column',\n    marginAxis: 'margin-bottom',\n    scaleProp: 'scaleY',\n    revealOrigin: 'bottom center',\n    coverOrigin: 'top center',\n    staggerFrom: 'start',\n  },\n  left: {\n    flexDirection: 'row',\n    marginAxis: 'margin-right',\n    scaleProp: 'scaleX',\n    revealOrigin: 'left center',\n    coverOrigin: 'right center',\n    staggerFrom: 'end',\n  },\n  right: {\n    flexDirection: 'row',\n    marginAxis: 'margin-right',\n    scaleProp: 'scaleX',\n    revealOrigin: 'right center',\n    coverOrigin: 'left center',\n    staggerFrom: 'start',\n  },\n}\n\ninterface SlicesSetup {\n  panel: HTMLElement\n  slices: HTMLElement[]\n  prevPosition: string\n  prevOverflow: string\n}\n\nfunction buildSlicesPanel(\n  element: HTMLElement,\n  rows: number,\n  axis: AxisConfig,\n): SlicesSetup {\n  const cs = window.getComputedStyle(element)\n  const prevPosition = cs.position === 'static' ? '' : cs.position\n  const prevOverflow = cs.overflow\n\n  if (cs.position === 'static') element.style.position = 'relative'\n  if (cs.overflow === 'visible') element.style.overflow = 'hidden'\n\n  const panel = document.createElement('div')\n  panel.className = 'aa-slices-panel'\n  panel.setAttribute(\n    'style',\n    `position:absolute;inset:0;display:flex;flex-direction:${axis.flexDirection};pointer-events:none;z-index:2`,\n  )\n\n  const slices: HTMLElement[] = []\n  const fragment = document.createDocumentFragment()\n  // -1px overlap on the stacking axis eliminates hairline seams between\n  // fractional-height flex children. Flex redistributes the lost space.\n  const overlap = `${axis.marginAxis}:-1px`\n  for (let i = 0; i < rows; i++) {\n    const slice = document.createElement('div')\n    slice.className = 'aa-slice'\n    slice.setAttribute(\n      'style',\n      `flex:1 1 auto;background:currentColor;will-change:transform;backface-visibility:hidden;${overlap}`,\n    )\n    fragment.appendChild(slice)\n    slices.push(slice)\n  }\n  panel.appendChild(fragment)\n  element.appendChild(panel)\n\n  return { panel, slices, prevPosition, prevOverflow }\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  element: Element,\n  config: Config,\n): (() => void) | undefined {\n  const animate = config['aa-animate']\n  if (!animate) return undefined\n  const params = parseSlicesValue(animate)\n  if (!params) return undefined\n\n  const opts = ctx.options\n  const { direction, mode, rows } = params\n  const axis = AXIS[direction]\n  const { duration, ease, scrollStart, scrollEnd, scrub, again } =\n    readAnimationConfig(config, opts)\n  const stagger = parseNum(config['aa-stagger'], defaultStaggerFor(undefined, opts))\n\n  // Reveal: slices start at scale 1 (covering) and scale to 0 with origin\n  // pinned to the named direction's opposite edge, so they collapse *toward*\n  // that edge — i.e. disappear in the named direction.\n  // Cover: inverse — start at 0, grow to 1 with origin on the opposite edge.\n  const fromScale = mode === 'cover' ? 0 : 1\n  const toScale = mode === 'cover' ? 1 : 0\n  const origin = mode === 'cover' ? axis.coverOrigin : axis.revealOrigin\n\n  const setup = buildSlicesPanel(element as HTMLElement, rows, axis)\n  ctx.gsap.gsap.set(setup.slices, { [axis.scaleProp]: fromScale, transformOrigin: origin })\n\n  const cleanup = (): void => {\n    ctx.gsap.gsap.killTweensOf(setup.slices)\n    setup.panel.remove()\n    const el = element as HTMLElement\n    if (setup.prevPosition === '') el.style.removeProperty('position')\n    if (setup.prevOverflow === 'visible') el.style.removeProperty('overflow')\n  }\n\n  const handle = setupTriggeredAnimation(ctx, element, {\n    triggers: resolveTriggers(element, config['aa-trigger'], ctx.options.breakpoints),\n    delay: 0,\n    scrollStart,\n    scrollEnd,\n    scrub,\n    again,\n    willChange: 'transform',\n    buildAnimation: (vars) => {\n      const animation = ctx.gsap.gsap.to(setup.slices, {\n        [axis.scaleProp]: toScale,\n        duration,\n        ease,\n        stagger: { each: stagger, from: axis.staggerFrom },\n        ...vars,\n      })\n      return { animation }\n    },\n  })\n\n  return () => {\n    handle?.dispose()\n    cleanup()\n  }\n}\n\nconst slicesFeature: FeatureModule = {\n  name: 'slices',\n  init(ctx: FeatureContext): () => void {\n    bindFeature(ctx, elementMatches, setupOne)\n    return () => {}\n  },\n}\n\nexport default slicesFeature\n","import { bindFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { parseNum, parseScrub, resolveAnchor } from '../../core/parse'\nimport { matchAnimateValue, type ResolvedPreset } from '../../core/presets'\nimport type { Config } from '../../core/settings'\n\nconst SUPPORTED = new Set(['parallax', 'parallax-horizontal', 'parallax-vertical'])\n\nfunction elementMatches(el: Element, presetMap: Map<Element, ResolvedPreset>): boolean {\n  return matchAnimateValue(el, presetMap, (v) => SUPPORTED.has(v))\n}\n\nfunction setupOne(ctx: FeatureContext, element: Element, config: Config): undefined {\n  const animate = config['aa-animate']\n  if (!animate || !SUPPORTED.has(animate)) return undefined\n\n  const isHorizontal = animate === 'parallax-horizontal'\n  const prop = isHorizontal ? 'xPercent' : 'yPercent'\n\n  const opts = ctx.options\n  const intensity = parseNum(config['aa-intensity'], opts.intensity)\n  const startVal = parseNum(config['aa-parallax-start'], 10 * intensity)\n  const endVal = parseNum(config['aa-parallax-end'], -10 * intensity)\n  // Parallax defaults to scrubbed when aa-scrub is absent.\n  const scrub = parseScrub(config['aa-scrub']) ?? true\n  // Wrapping in clamp() makes the trigger behave correctly when the element\n  // already overlaps the start position at page load (hero parallax).\n  const scrollStart = `clamp(${config['aa-scroll-start'] ?? 'top bottom'})`\n  const scrollEnd = `clamp(${config['aa-scroll-end'] ?? 'bottom top'})`\n  const triggerEl = resolveAnchor(element, config['aa-anchor'])\n\n  ctx.gsap.gsap.fromTo(\n    element,\n    { [prop]: startVal },\n    {\n      [prop]: endVal,\n      ease: 'none',\n      scrollTrigger: {\n        trigger: triggerEl,\n        start: scrollStart,\n        end: scrollEnd,\n        scrub,\n      },\n    },\n  )\n\n  return undefined\n}\n\nconst parallaxFeature: FeatureModule = {\n  name: 'parallax',\n  init(ctx: FeatureContext): () => void {\n    bindFeature(ctx, elementMatches, setupOne)\n    return () => {}\n  },\n}\n\nexport default parallaxFeature\n","import type { AutoplayOptions } from '../types/index'\n\nexport interface ParsedAutoplay {\n  enabled: boolean\n  interval: number\n  hoverPause: boolean\n  /** `hover-slow` token — marquee-only (slider/tabs ignore it). */\n  hoverSlow: boolean\n}\n\n/**\n * Parse `aa-autoplay`.\n * Presence of the attribute (even empty: `<div aa-autoplay>`) enables autoplay.\n * Tokens:\n *   <number>     — interval/duration in seconds (overrides the default)\n *   hover-pause  — pause cycling while the user hovers the root\n *   hover-slow   — (marquee) ramp the loop down while hovering\n *   none         — opt out (e.g. `aa-autoplay=\"4|none\"` to disable on small screens)\n *\n * `intervalDefault` lets a caller override the fallback seconds (marquee passes\n * 40, its cruise default); when omitted, `defaults.interval` is used.\n */\nexport function parseAutoplay(\n  raw: string | undefined,\n  defaults: AutoplayOptions,\n  attrPresent: boolean,\n  intervalDefault?: number,\n): ParsedAutoplay {\n  const baseInterval = intervalDefault ?? defaults.interval\n  const fallback: ParsedAutoplay = {\n    enabled: false,\n    interval: baseInterval,\n    hoverPause: defaults.hoverPause,\n    hoverSlow: false,\n  }\n  if (!attrPresent) return fallback\n\n  const tokens = (raw ?? '').trim().split(/\\s+/).filter(Boolean)\n  if (tokens.includes('none')) return fallback\n\n  let interval = baseInterval\n  let hoverPause = defaults.hoverPause\n  let hoverSlow = false\n  for (const t of tokens) {\n    if (t === 'hover-pause') hoverPause = true\n    else if (t === 'hover-slow') hoverSlow = true\n    else {\n      const n = parseFloat(t)\n      if (Number.isFinite(n) && n > 0) interval = n\n    }\n  }\n  return { enabled: true, interval, hoverPause, hoverSlow }\n}\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport { hasAnimateAttribute } from '../../core/parse'\nimport { emitTrigger } from '../../core/trigger'\nimport type { TabEntry, TabState } from './state'\n\n// ---------------------------------------------------------------------------\n// Animation controller\n// ---------------------------------------------------------------------------\n\nexport interface OpenOptions {\n  /**\n   * Hold the visual's `tab-active` emit (and the auto cross-fade) for this\n   * many seconds. Set by the orchestrator to the previous entry's visual\n   * duration so a user-defined animate-out finishes before the new one's\n   * animate-in starts.\n   */\n  visualDelay?: number\n  onComplete?: () => void\n}\n\nexport interface AnimationController {\n  /** Set every entry to its closed/inactive visual state (no animation). */\n  applyInitialClosed: (entries: TabEntry[]) => void\n  /** Snap an entry into its open state without animating (used for initial active). */\n  applyInitialOpen: (entry: TabEntry) => void\n  /** Run the open animation: height 0 → auto, visual autoAlpha 0 → 1. Emits tab-active. */\n  open: (entry: TabEntry, opts?: OpenOptions) => void\n  /** Run the close animation: height current → 0, visual autoAlpha 1 → 0. Emits tab-inactive. */\n  close: (entry: TabEntry, onComplete?: () => void) => void\n  /** Kill all in-flight tweens and clear inline styles we added. */\n  cleanup: (entries: TabEntry[]) => void\n}\n\ntype GsapAny = Record<string, any>\n\n/**\n * When the author wraps their own `aa-animate` onto the visual element, we\n * step out of the way: their animation owns visibility (and any transform).\n * Auto-cross-fade only kicks in when the visual is decorative markup.\n */\nexport function hasVisualAnimation(visual: HTMLElement | null): boolean {\n  return hasAnimateAttribute(visual)\n}\n\nfunction emitOnTargets(entry: TabEntry, name: string): void {\n  emitTrigger(entry.toggle, name)\n  if (entry.content) emitTrigger(entry.content, name)\n  if (entry.visual) emitTrigger(entry.visual, name)\n}\n\nexport function createAnimationController(gsapHandle: GsapHandle): AnimationController {\n  const gsap = gsapHandle.gsap as unknown as GsapAny\n\n  // Track the in-flight delayed visual emit so a rapid second open kills the\n  // pending one instead of double-firing tab-active on the visual.\n  let pendingVisualOpen: { kill: () => void } | null = null\n\n  const openHeight = (content: HTMLElement, duration: number, ease: string, onComplete?: () => void): void => {\n    gsap.killTweensOf(content)\n    const startHeight = content.getBoundingClientRect().height\n    gsap.set(content, { height: startHeight })\n    gsap.to(content, {\n      height: 'auto',\n      duration,\n      ease,\n      onComplete: () => {\n        // Clear the inline height so subsequent layout (e.g. images that\n        // load after open, child margin collapse) flows naturally. The\n        // CSS rule [aa-tabs-content] { overflow: hidden } stays in place\n        // so the close tween can clip again from natural height to 0.\n        gsap.set(content, { clearProps: 'height' })\n        onComplete?.()\n      },\n    })\n  }\n\n  const closeHeight = (content: HTMLElement, duration: number, ease: string, onComplete?: () => void): void => {\n    gsap.killTweensOf(content)\n    const startHeight = content.getBoundingClientRect().height\n    gsap.set(content, { height: startHeight })\n    gsap.to(content, { height: 0, duration, ease, onComplete })\n  }\n\n  const showVisual = (visual: HTMLElement, duration: number, ease: string): void => {\n    gsap.killTweensOf(visual)\n    gsap.to(visual, { autoAlpha: 1, duration, ease })\n  }\n\n  const hideVisual = (visual: HTMLElement, duration: number, ease: string): void => {\n    gsap.killTweensOf(visual)\n    gsap.to(visual, { autoAlpha: 0, duration, ease })\n  }\n\n  const applyInitialClosed = (entries: TabEntry[]): void => {\n    for (const e of entries) {\n      if (e.content) gsap.set(e.content, { height: 0 })\n      if (e.visual && !hasVisualAnimation(e.visual)) {\n        gsap.set(e.visual, { autoAlpha: 0 })\n      }\n    }\n  }\n\n  const applyInitialOpen = (entry: TabEntry): void => {\n    if (entry.content) gsap.set(entry.content, { clearProps: 'height' })\n    if (entry.visual && !hasVisualAnimation(entry.visual)) {\n      gsap.set(entry.visual, { autoAlpha: 1, visibility: 'visible' })\n    }\n    emitOnTargets(entry, 'tab-active')\n  }\n\n  const open = (entry: TabEntry, opts?: OpenOptions): void => {\n    pendingVisualOpen?.kill()\n    pendingVisualOpen = null\n\n    // Toggle + content fire immediately so the click feels responsive and the\n    // height tween starts. The visual emit is what's optionally delayed.\n    emitTrigger(entry.toggle, 'tab-active')\n    if (entry.content) emitTrigger(entry.content, 'tab-active')\n    if (entry.content) {\n      openHeight(entry.content, entry.contentDuration, entry.ease, opts?.onComplete)\n    } else {\n      opts?.onComplete?.()\n    }\n\n    if (entry.visual) {\n      const visualEl = entry.visual\n      const fireVisual = (): void => {\n        emitTrigger(visualEl, 'tab-active')\n        if (!hasVisualAnimation(visualEl)) {\n          showVisual(visualEl, entry.visualDuration, entry.ease)\n        }\n        pendingVisualOpen = null\n      }\n      const delay = opts?.visualDelay\n      if (delay && delay > 0) {\n        pendingVisualOpen = gsap.delayedCall(delay, fireVisual)\n      } else {\n        fireVisual()\n      }\n    }\n  }\n\n  const close = (entry: TabEntry, onComplete?: () => void): void => {\n    emitOnTargets(entry, 'tab-inactive')\n    if (entry.content) {\n      closeHeight(entry.content, entry.contentDuration, entry.ease, onComplete)\n    } else {\n      onComplete?.()\n    }\n    if (entry.visual && !hasVisualAnimation(entry.visual)) {\n      hideVisual(entry.visual, entry.visualDuration, entry.ease)\n    }\n  }\n\n  const cleanup = (entries: TabEntry[]): void => {\n    pendingVisualOpen?.kill()\n    pendingVisualOpen = null\n    for (const e of entries) {\n      if (e.content) {\n        gsap.killTweensOf(e.content)\n        gsap.set(e.content, { clearProps: 'height' })\n      }\n      if (e.visual) {\n        gsap.killTweensOf(e.visual)\n        gsap.set(e.visual, { clearProps: 'opacity,visibility' })\n      }\n      if (e.progress) gsap.killTweensOf(e.progress)\n    }\n  }\n\n  return { applyInitialClosed, applyInitialOpen, open, close, cleanup }\n}\n\n// ---------------------------------------------------------------------------\n// Aria controller\n// ---------------------------------------------------------------------------\n\nlet tabsInstanceCounter = 0\n\nexport interface AriaController {\n  applyInitial: () => void\n  applyOpen: (entry: TabEntry) => void\n  applyClosed: (entry: TabEntry) => void\n  cleanup: () => void\n}\n\ninterface EntryAriaShape {\n  /** True when toggle has matching content (accordion semantics — button/region). */\n  accordion: boolean\n  /** True when entry uses tab semantics (visual-only). */\n  tab: boolean\n  toggleId: string\n  contentId: string | null\n  visualId: string | null\n}\n\nfunction shapeFor(entry: TabEntry, instanceId: number): EntryAriaShape {\n  const accordion = !!entry.content\n  const tab = !accordion && !!entry.visual\n  const toggleId = `aa-tabs-${instanceId}-toggle-${entry.index}`\n  const contentId = entry.content ? `aa-tabs-${instanceId}-content-${entry.index}` : null\n  const visualId = entry.visual ? `aa-tabs-${instanceId}-visual-${entry.index}` : null\n  return { accordion, tab, toggleId, contentId, visualId }\n}\n\nexport function createAriaController(state: TabState): AriaController {\n  const instanceId = tabsInstanceCounter++\n  const shapes = new Map<TabEntry, EntryAriaShape>()\n  for (const entry of state.entries) shapes.set(entry, shapeFor(entry, instanceId))\n\n  const undo: Array<() => void> = []\n\n  const setAttrTracked = (el: Element, attr: string, value: string): void => {\n    const had = el.hasAttribute(attr)\n    const prev = had ? el.getAttribute(attr) : null\n    el.setAttribute(attr, value)\n    undo.push(() => {\n      if (had && prev !== null) el.setAttribute(attr, prev)\n      else el.removeAttribute(attr)\n    })\n  }\n\n  const setAttrIfMissing = (el: Element, attr: string, value: string): void => {\n    if (el.hasAttribute(attr)) return\n    el.setAttribute(attr, value)\n    undo.push(() => el.removeAttribute(attr))\n  }\n\n  const applyInitial = (): void => {\n    for (const entry of state.entries) {\n      const shape = shapes.get(entry)\n      if (!shape) continue\n\n      // Toggle gets a stable id and tabindex regardless of pattern.\n      setAttrIfMissing(entry.toggle, 'id', shape.toggleId)\n      setAttrIfMissing(entry.toggle, 'tabindex', '0')\n\n      if (shape.accordion) {\n        setAttrTracked(entry.toggle, 'role', 'button')\n        setAttrTracked(entry.toggle, 'aria-expanded', 'false')\n        if (entry.content && shape.contentId) {\n          setAttrTracked(entry.toggle, 'aria-controls', shape.contentId)\n          setAttrIfMissing(entry.content, 'id', shape.contentId)\n          setAttrTracked(entry.content, 'role', 'region')\n          setAttrTracked(entry.content, 'aria-labelledby', shape.toggleId)\n        }\n        if (entry.visual) {\n          // Visual is decorative when paired with a content panel.\n          setAttrTracked(entry.visual, 'aria-hidden', 'true')\n        }\n      } else if (shape.tab) {\n        setAttrTracked(entry.toggle, 'role', 'tab')\n        setAttrTracked(entry.toggle, 'aria-selected', 'false')\n        if (entry.visual && shape.visualId) {\n          setAttrTracked(entry.toggle, 'aria-controls', shape.visualId)\n          setAttrIfMissing(entry.visual, 'id', shape.visualId)\n          setAttrTracked(entry.visual, 'role', 'tabpanel')\n          setAttrTracked(entry.visual, 'aria-labelledby', shape.toggleId)\n        }\n      }\n    }\n\n    // If every entry is tab-like (visual-only), the parent of the first toggle\n    // becomes the tablist. Mirrors v7 — but only when the pattern is uniform.\n    if (state.hasVisualOnly && state.entries.length > 0) {\n      const parent = state.entries[0].toggle.parentElement\n      if (parent) setAttrTracked(parent, 'role', 'tablist')\n    }\n  }\n\n  const applyOpen = (entry: TabEntry): void => {\n    const shape = shapes.get(entry)\n    if (!shape) return\n    if (shape.accordion) {\n      entry.toggle.setAttribute('aria-expanded', 'true')\n      if (entry.visual) entry.visual.setAttribute('aria-hidden', 'false')\n    } else if (shape.tab) {\n      entry.toggle.setAttribute('aria-selected', 'true')\n    }\n  }\n\n  const applyClosed = (entry: TabEntry): void => {\n    const shape = shapes.get(entry)\n    if (!shape) return\n    if (shape.accordion) {\n      entry.toggle.setAttribute('aria-expanded', 'false')\n      if (entry.visual) entry.visual.setAttribute('aria-hidden', 'true')\n    } else if (shape.tab) {\n      entry.toggle.setAttribute('aria-selected', 'false')\n    }\n  }\n\n  const cleanup = (): void => {\n    while (undo.length) {\n      const fn = undo.pop()\n      if (fn) fn()\n    }\n  }\n\n  return { applyInitial, applyOpen, applyClosed, cleanup }\n}\n","/**\n * Shared progress-indicator setup for autoplay-driven features (slider, tabs).\n *\n * The marked element can be one of:\n *   - a bar (default): the element's `width` (or `height`) tweens 0% → 100%\n *   - a circular sweep: the element is or contains an SVG `<circle>`; we\n *     tween its `stroke-dashoffset` from circumference → 0\n *\n * Both modes pre-set the element to its empty state at setup. The caller\n * drives play / pause / reset via the returned tween-value helpers.\n */\n\nexport type ProgressKind = 'width' | 'height' | 'circle'\n\nexport interface ProgressEntry {\n  /** Element actually being tweened — the inner <circle> for circle mode. */\n  target: Element\n  kind: ProgressKind\n  /** For 'width' / 'height': the CSS property to tween. */\n  property?: 'width' | 'height'\n  /** For 'circle': pre-computed 2πr so we know where to start dashoffset. */\n  circumference?: number\n  /** Per-element ease override (from `aa-ease` on the element) or feature default. */\n  ease: string\n}\n\n/** Just the `gsap.set` signature — pass `gsap.set` (bound or not) directly. */\ntype GsapSet = (target: unknown, vars: Record<string, unknown>) => unknown\n\n/**\n * Build a single ProgressEntry from a marked element, or `null` if the\n * element opts into circle mode but lacks an SVG `<circle>` (we warn and\n * skip rather than throwing — the rest of the autoplay still works).\n */\nexport function createProgressEntry(\n  el: Element,\n  attrName: string,\n  fallbackEase: string,\n  set: GsapSet,\n): ProgressEntry | null {\n  const raw = el.getAttribute(attrName)?.toLowerCase() ?? 'width'\n  const ease = el.getAttribute('aa-ease') ?? fallbackEase\n\n  if (raw === 'circle') {\n    const circle =\n      el.tagName.toLowerCase() === 'circle'\n        ? (el as unknown as SVGCircleElement)\n        : (el.querySelector('circle') as SVGCircleElement | null)\n    if (!circle) {\n      console.warn(\n        `[alrdy-animate] ${attrName}=\"circle\" requires an SVG <circle> on or inside the marked element.`,\n        el,\n      )\n      return null\n    }\n    const r =\n      typeof circle.r?.baseVal?.value === 'number'\n        ? circle.r.baseVal.value\n        : parseFloat(circle.getAttribute('r') ?? '0')\n    const circumference = 2 * Math.PI * r\n    set(circle, { strokeDasharray: circumference, strokeDashoffset: circumference })\n    return { target: circle, kind: 'circle', circumference, ease }\n  }\n\n  const property: 'width' | 'height' = raw === 'height' ? 'height' : 'width'\n  set(el, { [property]: '0%' })\n  return { target: el, kind: property, property, ease }\n}\n\nexport function progressFromValues(entry: ProgressEntry): Record<string, unknown> {\n  if (entry.kind === 'circle') return { strokeDashoffset: entry.circumference }\n  return { [entry.property as string]: '0%' }\n}\n\nexport function progressToValues(entry: ProgressEntry): Record<string, unknown> {\n  if (entry.kind === 'circle') return { strokeDashoffset: 0 }\n  return { [entry.property as string]: '100%' }\n}\n\n/**\n * Set a progress indicator to a fractional fill (0..1). Used by scroll-driven\n * progress where the value is interpolated from scroll position, not animated.\n * The width/height fill uses an inline-style update for parity with the\n * autoplay path; circle uses a strokeDashoffset write so it composes with the\n * stroke-dasharray already set at `createProgressEntry` time.\n */\nexport function progressSetFill(\n  entry: ProgressEntry,\n  fraction: number,\n  set: GsapSet,\n): void {\n  const clamped = Math.max(0, Math.min(1, fraction))\n  if (entry.kind === 'circle') {\n    set(entry.target, {\n      strokeDashoffset: (entry.circumference ?? 0) * (1 - clamped),\n    })\n    return\n  }\n  set(entry.target, { [entry.property as string]: `${clamped * 100}%` })\n}\n\n/** The slice of GSAP a progress group drives. The autoplay controllers already\n *  hold a loosely-typed gsap, so this is structurally satisfied by that. */\ninterface ProgressGsap {\n  set: GsapSet\n  fromTo: (target: unknown, fromVars: Record<string, unknown>, toVars: Record<string, unknown>) => unknown\n  killTweensOf: (target: unknown) => void\n  getTweensOf: (target: unknown) => Array<{ pause: () => void; resume: () => void }>\n}\n\nexport interface ProgressGroup {\n  /** Tween the active index's bar empty → full over `durationFor(index)` and\n   *  snap every other bar back to empty. */\n  play: (activeIndex: number, durationFor: (index: number) => number) => void\n  /** Kill all in-flight tweens and reset every bar to empty. */\n  reset: () => void\n  /** Pause in-flight bar tweens (hover-pause). */\n  pause: () => void\n  /** Resume paused bar tweens. */\n  resume: () => void\n}\n\n/**\n * Drive a set of progress bars (one per slide/tab) as a group. Centralises the\n * `killTweensOf` / `fromTo` / `getTweensOf` plumbing the slider and tabs\n * autoplay controllers both need — the only difference between them (per-entry\n * dwell vs a shared interval) is supplied via the `durationFor` callback.\n * `null` entries (a slide/tab with no progress element) are skipped.\n */\nexport function createProgressGroup(\n  // The autoplay controllers hold a loosely-typed gsap (`Record<string, any>`);\n  // narrow it to the slice we use here.\n  gsapLoose: Record<string, unknown>,\n  entries: ReadonlyArray<ProgressEntry | null>,\n): ProgressGroup {\n  const gsap = gsapLoose as unknown as ProgressGsap\n  return {\n    play(activeIndex, durationFor): void {\n      entries.forEach((entry, i) => {\n        if (!entry) return\n        gsap.killTweensOf(entry.target)\n        if (i === activeIndex) {\n          gsap.fromTo(entry.target, progressFromValues(entry), {\n            ...progressToValues(entry),\n            duration: durationFor(i),\n            ease: entry.ease,\n            overwrite: true,\n          })\n        } else {\n          gsap.set(entry.target, progressFromValues(entry))\n        }\n      })\n    },\n    reset(): void {\n      for (const entry of entries) {\n        if (!entry) continue\n        gsap.killTweensOf(entry.target)\n        gsap.set(entry.target, progressFromValues(entry))\n      }\n    },\n    pause(): void {\n      for (const entry of entries) {\n        if (!entry) continue\n        for (const t of gsap.getTweensOf(entry.target)) t.pause()\n      }\n    },\n    resume(): void {\n      for (const entry of entries) {\n        if (!entry) continue\n        for (const t of gsap.getTweensOf(entry.target)) t.resume()\n      }\n    },\n  }\n}\n","/**\n * Shared gating helpers for autoplay-driven features (slider, tabs, marquee).\n *\n * Two patterns lived in three feature modules verbatim:\n *\n *   1. A ScrollTrigger that calls `onActive` whenever the root is in view\n *      (onEnter / onEnterBack) and `onIdle` when it leaves (onLeave /\n *      onLeaveBack). Skips silently when ScrollTrigger isn't loaded — the\n *      caller falls back to \"always active\" via the no-ScrollTrigger branch.\n *\n *   2. A `mouseenter` / `mouseleave` listener pair gated on\n *      `(hover: none)` so touch devices don't trigger it.\n *\n * The feature-specific state (drag-in-progress flag, isPausedByHover boolean,\n * progress-tween pausing) stays in the feature module — only the listener\n * plumbing is shared here.\n */\n\nimport type { GsapHandle } from './gsap-detect'\nimport { subscribeWithPair, MODAL_CARD_SELECTOR, MODAL_STATUS_ATTR } from './trigger'\n\ninterface ScrollTriggerInstance {\n  kill: () => void\n  isActive: boolean\n}\n\ninterface ScrollTriggerLike {\n  create: (vars: Record<string, unknown>) => ScrollTriggerInstance\n}\n\nexport interface ViewportGateOptions {\n  trigger: Element\n  onActive: () => void\n  onIdle: () => void\n}\n\n/**\n * Create a ScrollTrigger that fires `onActive` on enter/enterBack and `onIdle`\n * on leave/leaveBack, then reflects the current in-view state once on creation.\n * Returns a disposer that kills the trigger. Returns `null` when ScrollTrigger\n * isn't available — caller decides whether to default to always-active or skip\n * silently.\n *\n * Inside a modal the gate switches strategy: a modal is `position:fixed`, and\n * ScrollTrigger's scroll-based in-view math misjudges fixed elements — when the\n * modal is opened at a non-zero scroll, the refresh every resize triggers can\n * decide the element is off-screen and fire `onIdle`, freezing the gated\n * animation for good (a fixed element never scrolls back into view). So we gate\n * on the modal's own open/close lifecycle instead: active while open, idle while\n * closed. This is also more correct — there's no point running the animation\n * while the modal is hidden.\n */\nexport function createViewportGate(\n  gsapHandle: GsapHandle,\n  opts: ViewportGateOptions,\n): (() => void) | null {\n  const modalCard = opts.trigger.closest<HTMLElement>(MODAL_CARD_SELECTOR)\n  if (modalCard) {\n    const dispose = subscribeWithPair({\n      element: opts.trigger,\n      forwardName: 'modal-active',\n      onForward: opts.onActive,\n      onReverse: opts.onIdle,\n    })\n    // The gate is usually created after `modal-active` has already fired (the\n    // marquee/slider builds on reveal, mid-open), so reflect the current open\n    // state now — a future-only subscription would otherwise sit idle until the\n    // next open/close toggle.\n    if (modalCard.getAttribute(MODAL_STATUS_ATTR) === 'active') opts.onActive()\n    else opts.onIdle()\n    return dispose\n  }\n\n  const ScrollTrigger = gsapHandle.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  if (!ScrollTrigger) return null\n\n  const st = ScrollTrigger.create({\n    trigger: opts.trigger,\n    start: 'top bottom',\n    end: 'bottom top',\n    onEnter: opts.onActive,\n    onEnterBack: opts.onActive,\n    onLeave: opts.onIdle,\n    onLeaveBack: opts.onIdle,\n  })\n\n  // ScrollTrigger's enter/leave callbacks fire only on scroll *crossings*, not\n  // for the position the page loads at. An element already below the fold at\n  // load has not crossed its start, so no callback fires and the caller's\n  // animation would run un-gated (e.g. a marquee looping while off-screen). A\n  // scrolled-past element likewise never gets `onLeave`. Reflect the initial\n  // state explicitly so the gate is correct from the first frame.\n  if (st.isActive) opts.onActive()\n  else opts.onIdle()\n\n  return () => st.kill()\n}\n\nexport interface HoverPauseOptions {\n  root: Element\n  onEnter: () => void\n  onLeave: () => void\n}\n\n/**\n * Attach mouseenter / mouseleave listeners gated on pointer capability. Touch\n * devices (`(hover: none)`) skip both listeners entirely so a sustained\n * pointerover doesn't freeze the feature mid-scroll.\n *\n * Returns a disposer; safe to call even when listeners weren't attached\n * (touch devices).\n */\nexport function attachHoverPauseListener(opts: HoverPauseOptions): () => void {\n  if (typeof window !== 'undefined' && window.matchMedia('(hover: none)').matches) {\n    return () => {}\n  }\n  opts.root.addEventListener('mouseenter', opts.onEnter)\n  opts.root.addEventListener('mouseleave', opts.onLeave)\n  return () => {\n    opts.root.removeEventListener('mouseenter', opts.onEnter)\n    opts.root.removeEventListener('mouseleave', opts.onLeave)\n  }\n}\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport {\n  createProgressEntry,\n  createProgressGroup,\n  type ProgressEntry,\n} from '../../core/progress-bar'\nimport { attachHoverPauseListener, createViewportGate } from '../../core/viewport-gate'\nimport type { TabsApi } from './index'\n\nexport interface AutoplayOptions {\n  hoverPause: boolean\n}\n\nexport interface AutoplayController {\n  start: () => void\n  stop: () => void\n  /** User-jumped to a specific tab. Reset progress and resume cycling from idx. */\n  sync: (idx: number) => void\n  destroy: () => void\n}\n\nexport function setupAutoplay(\n  gsapHandle: GsapHandle,\n  root: HTMLElement,\n  api: TabsApi,\n  options: AutoplayOptions,\n): AutoplayController {\n  const gsap = gsapHandle.gsap as unknown as Record<string, any>\n  const { hoverPause } = options\n  const entries = api.state.entries\n\n  let autoplayCall:\n    | { kill: () => void; pause: () => void; resume: () => void; paused: () => boolean }\n    | null = null\n  let isPausedByHover = false\n  let isHovering = false\n  let currentIdx = Math.max(0, entries.findIndex((e) => api.state.isActive(e)))\n\n  // Build progress entries for each toggle (null when no progress element).\n  const progressByIdx: Array<ProgressEntry | null> = entries.map((entry) =>\n    entry.progress\n      ? createProgressEntry(entry.progress, 'aa-tabs-progress', entry.ease, gsap.set)\n      : null,\n  )\n  const progress = createProgressGroup(gsap, progressByIdx)\n  // Each tab carries its own dwell, so the active bar fills over that tab's interval.\n  const dwellFor = (i: number): number => entries[i].interval\n\n  const tick = (): void => {\n    const next = (currentIdx + 1) % entries.length\n    currentIdx = next\n    api.open(entries[next])\n    progress.play(next, dwellFor)\n    const dwell = entries[next].interval\n    autoplayCall = gsap.delayedCall(dwell, tick)\n  }\n\n  const start = (): void => {\n    if (autoplayCall) return\n    progress.play(currentIdx, dwellFor)\n    const dwell = entries[currentIdx].interval\n    autoplayCall = gsap.delayedCall(dwell, tick)\n  }\n\n  const stop = (): void => {\n    if (autoplayCall) {\n      autoplayCall.kill()\n      autoplayCall = null\n    }\n    progress.reset()\n    isPausedByHover = false\n  }\n\n  const sync = (idx: number): void => {\n    if (idx < 0 || idx >= entries.length) return\n    if (autoplayCall) {\n      autoplayCall.kill()\n      autoplayCall = null\n    }\n    progress.reset()\n    currentIdx = idx\n    api.open(entries[idx])\n    // In hover-pause mode, a click *while hovering* should leave autoplay\n    // paused — the user is reading the panel. mouseleave will start a fresh\n    // cycle from this index. With plain autoplay, restart immediately.\n    if (hoverPause && isHovering) {\n      isPausedByHover = true\n      return\n    }\n    isPausedByHover = false\n    progress.play(idx, dwellFor)\n    const dwell = entries[idx].interval\n    autoplayCall = gsap.delayedCall(dwell, tick)\n  }\n\n  const pauseByHover = (): void => {\n    if (autoplayCall && !autoplayCall.paused()) {\n      autoplayCall.pause()\n      progress.pause()\n      isPausedByHover = true\n    }\n  }\n  const resumeFromHover = (): void => {\n    if (autoplayCall && isPausedByHover) {\n      autoplayCall.resume()\n      progress.resume()\n      isPausedByHover = false\n    }\n  }\n\n  const cleanups: Array<() => void> = []\n\n  if (hoverPause) {\n    cleanups.push(\n      attachHoverPauseListener({\n        root,\n        onEnter: () => {\n          isHovering = true\n          if (autoplayCall && !autoplayCall.paused()) pauseByHover()\n        },\n        onLeave: () => {\n          isHovering = false\n          if (!isPausedByHover) return\n          // If a paused tween is still alive, resume it where it left off. If\n          // the tween was killed (e.g. user clicked a tab while hovering), spin\n          // up a fresh cycle from currentIdx instead.\n          if (autoplayCall) {\n            resumeFromHover()\n          } else {\n            isPausedByHover = false\n            start()\n          }\n        },\n      }),\n    )\n  }\n\n  // Viewport gate: only autoplay when the tabs root is in view. `onActive`\n  // defers one tick so the initial-active openSnap settles first; `onIdle`\n  // kills the in-flight delayedCall.\n  const onIdle = (): void => {\n    if (autoplayCall) {\n      autoplayCall.kill()\n      autoplayCall = null\n    }\n  }\n  const onActive = (): void => {\n    gsap.delayedCall(0.1, start)\n  }\n  const gateDispose = createViewportGate(gsapHandle, { trigger: root, onActive, onIdle })\n  if (gateDispose) cleanups.push(gateDispose)\n  else onActive() // No ScrollTrigger plugin → just start (deferred).\n\n  const destroy = (): void => {\n    stop()\n    for (const fn of cleanups) fn()\n  }\n\n  return { start, stop, sync, destroy }\n}\n","export interface KeyboardHandlers {\n  activate: (toggle: HTMLElement) => void\n}\n\nconst ACTIVATE_KEYS = new Set(['Enter', ' '])\nconst NAV_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'])\n\nexport function attachKeyboard(\n  root: HTMLElement,\n  toggles: HTMLElement[],\n  handlers: KeyboardHandlers,\n): () => void {\n  if (toggles.length === 0) return () => {}\n\n  const onKey = (e: KeyboardEvent): void => {\n    const target = e.target as Element | null\n    if (!target) return\n    const toggle = target.closest<HTMLElement>('[aa-tabs-toggle]')\n    if (!toggle || !root.contains(toggle)) return\n\n    if (ACTIVATE_KEYS.has(e.key)) {\n      e.preventDefault()\n      handlers.activate(toggle)\n      return\n    }\n\n    if (!NAV_KEYS.has(e.key)) return\n\n    const idx = toggles.indexOf(toggle)\n    if (idx === -1) return\n\n    let next = idx\n    switch (e.key) {\n      case 'ArrowDown':\n      case 'ArrowRight':\n        next = (idx + 1) % toggles.length\n        break\n      case 'ArrowUp':\n      case 'ArrowLeft':\n        next = (idx - 1 + toggles.length) % toggles.length\n        break\n      case 'Home':\n        next = 0\n        break\n      case 'End':\n        next = toggles.length - 1\n        break\n    }\n    if (next !== idx) {\n      e.preventDefault()\n      toggles[next].focus()\n    }\n  }\n\n  root.addEventListener('keydown', onKey)\n  return () => root.removeEventListener('keydown', onKey)\n}\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport {\n  createProgressEntry,\n  progressSetFill,\n  type ProgressEntry,\n} from '../../core/progress-bar'\nimport type { TabsApi } from './index'\n\nexport interface ScrollOptions {\n  distanceVh: number\n  scrollStart: string\n  scrub: boolean | number\n}\n\nexport interface ScrollController {\n  jumpToIndex: (idx: number) => void\n  destroy: () => void\n}\n\ninterface ScrollTriggerInstance {\n  kill: () => void\n  start: number\n  end: number\n}\n\ninterface ScrollTriggerLike {\n  create: (vars: Record<string, unknown>) => ScrollTriggerInstance\n}\n\ninterface DummyTween {\n  kill: () => void\n}\n\nexport function setupScroll(\n  gsapHandle: GsapHandle,\n  root: HTMLElement,\n  api: TabsApi,\n  options: ScrollOptions,\n): ScrollController | null {\n  const ScrollTrigger = gsapHandle.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  if (!ScrollTrigger) {\n    console.warn(\n      '[alrdy-animate] aa-tabs=\"scroll\" requires ScrollTrigger. Add the plugin <script> tag before alrdy-animate.',\n    )\n    return null\n  }\n  const gsap = gsapHandle.gsap as unknown as Record<string, any>\n  const entries = api.state.entries\n  const N = entries.length\n  if (N === 0) return null\n\n  // Resolve each entry's progress indicator once. createProgressEntry handles\n  // both width/height/circle modes and pre-sets the dasharray on circles so\n  // subsequent progressSetFill writes only touch dashoffset.\n  const progressByIdx: Array<ProgressEntry | null> = entries.map((entry) =>\n    entry.progress\n      ? createProgressEntry(entry.progress, 'aa-tabs-progress', entry.ease, gsap.set)\n      : null,\n  )\n\n  // Total scroll distance in pixels (vh × N).\n  const totalDistance = (N * options.distanceVh * window.innerHeight) / 100\n\n  // Track which entry is active. The orchestrator's deferred openSnap will\n  // already make entries[0] active by the time onUpdate first fires; calls\n  // to api.open / api.close are no-ops when the state already matches.\n  let currentIdx = -1\n\n  const dummyProgress = { v: 0 }\n  const dummyTween: DummyTween = gsap.to(dummyProgress, {\n    v: 1,\n    duration: 1,\n    ease: 'none',\n    paused: true,\n    onUpdate: () => {\n      const p = dummyProgress.v\n      const newIdx = Math.min(Math.max(0, Math.floor(p * N)), N - 1)\n\n      if (newIdx !== currentIdx) {\n        if (currentIdx >= 0) api.close(entries[currentIdx])\n        api.open(entries[newIdx])\n        currentIdx = newIdx\n      }\n\n      // Per-tab progress bars: active bar fills proportionally over its\n      // segment of the pin range, others stay at 0.\n      progressByIdx.forEach((entry, i) => {\n        if (!entry) return\n        const fill = i === newIdx ? p * N - i : 0\n        progressSetFill(entry, fill, gsap.set)\n      })\n    },\n  })\n\n  const st = ScrollTrigger.create({\n    trigger: root,\n    start: options.scrollStart,\n    end: `+=${totalDistance}`,\n    pin: true,\n    pinSpacing: true,\n    scrub: options.scrub,\n    animation: dummyTween,\n  })\n\n  const jumpToIndex = (idx: number): void => {\n    if (idx < 0 || idx >= N) return\n    // Use the live ScrollTrigger range — the closure's totalDistance can drift\n    // after a refresh / viewport resize.\n    const liveRange = st.end - st.start\n    const distancePerSegment = liveRange / N\n    // Step ~5% into the segment so the active state actually changes.\n    const targetY = st.start + idx * distancePerSegment + distancePerSegment * 0.05\n\n    const w = window as unknown as Record<string, any>\n    const lenis = w.lenis\n    if (lenis && typeof lenis.scrollTo === 'function') {\n      // Lenis is already smoothing every scroll input via its own RAF, so\n      // a short scrollTo blends naturally with momentum scrolling. Longer\n      // durations feel sluggish next to manual wheel scrolling.\n      lenis.scrollTo(targetY, { duration: 0.3, offset: 0 })\n      return\n    }\n    // Manual smooth scroll via gsap on a dummy. The browser's native\n    // `behavior: 'smooth'` truncates short of the target when scrolling\n    // through a pinned section, so we drive window.scrollTo from a tween\n    // ourselves — no ScrollToPlugin required.\n    const proxy = { y: window.scrollY }\n    gsap.to(proxy, {\n      y: targetY,\n      duration: 1.2,\n      ease: 'power2.inOut',\n      overwrite: true,\n      onUpdate: () => {\n        window.scrollTo(0, proxy.y)\n      },\n    })\n  }\n\n  const destroy = (): void => {\n    dummyTween.kill()\n    st.kill()\n  }\n\n  return { jumpToIndex, destroy }\n}\n","import { parseNum } from '../../core/parse'\n\nexport type TabMode = 'default' | 'single' | 'multi' | 'autoplay' | 'scroll'\n\nexport interface ParsedTabsConfig {\n  mode: TabMode\n  isNone: boolean\n}\n\n/**\n * Mode tokens recognised on `aa-tabs`. Autoplay is no longer a token here —\n * presence of `aa-autoplay` on the root activates autoplay mode (handled in\n * setupOne after parseAutoplay).\n */\nexport function parseTabsValue(raw: string | undefined): ParsedTabsConfig {\n  const tokens = (raw ?? '')\n    .trim()\n    .split(/\\s+/)\n    .filter(Boolean)\n  const isNone = tokens.includes('none')\n  let mode: TabMode = 'default'\n  if (tokens.includes('scroll')) mode = 'scroll'\n  else if (tokens.includes('multi')) mode = 'multi'\n  else if (tokens.includes('single')) mode = 'single'\n  return { mode, isNone }\n}\n\nexport interface TabEntry {\n  id: string\n  index: number\n  toggle: HTMLElement\n  content: HTMLElement | null\n  visual: HTMLElement | null\n  wrapper: HTMLElement | null\n  progress: HTMLElement | null\n  /** Toggle-level (or root-level) duration — used for the height tween. */\n  contentDuration: number\n  /** Visual cross-fade duration. */\n  visualDuration: number\n  /** Per-tab dwell for autoplay; only meaningful when mode === 'autoplay'. */\n  interval: number\n  ease: string\n}\n\nexport interface TabStateDefaults {\n  duration: number\n  /** Default autoplay interval (seconds) inherited from root or init.autoplay.interval. */\n  interval: number\n  ease: string\n}\n\nexport interface TabState {\n  root: HTMLElement\n  entries: TabEntry[]\n  byId: Map<string, TabEntry>\n  useWrapperPattern: boolean\n  hasContent: boolean\n  hasVisualOnly: boolean\n  /** Status host for an entry — wrapper if present, else toggle. */\n  statusEl: (entry: TabEntry) => HTMLElement\n  isActive: (entry: TabEntry) => boolean\n  setStatus: (entry: TabEntry, status: 'active' | 'inactive') => void\n  activeEntry: () => TabEntry | null\n  initialEntry: () => TabEntry | null\n}\n\nconst STATUS_ATTR = 'aa-tabs-status'\n\nfunction autoAssignIds(root: HTMLElement): void {\n  const wrappers = root.querySelectorAll<HTMLElement>('[aa-tabs-wrapper]')\n  const useWrapper = wrappers.length > 0\n\n  if (useWrapper) {\n    wrappers.forEach((wrapper, i) => {\n      let id = wrapper.getAttribute('aa-tabs-wrapper')\n      if (!id) {\n        id = `aa-tabs-${i}`\n        wrapper.setAttribute('aa-tabs-wrapper', id)\n      }\n      const toggle = wrapper.querySelector<HTMLElement>('[aa-tabs-toggle]')\n      const content = wrapper.querySelector<HTMLElement>('[aa-tabs-content]')\n      if (toggle && !toggle.getAttribute('aa-tabs-toggle')) {\n        toggle.setAttribute('aa-tabs-toggle', id)\n      }\n      if (content && !content.getAttribute('aa-tabs-content')) {\n        content.setAttribute('aa-tabs-content', id)\n      }\n    })\n    root.querySelectorAll<HTMLElement>('[aa-tabs-visual]').forEach((visual, i) => {\n      if (!visual.getAttribute('aa-tabs-visual')) {\n        visual.setAttribute('aa-tabs-visual', `aa-tabs-${i}`)\n      }\n    })\n    return\n  }\n\n  root.querySelectorAll<HTMLElement>('[aa-tabs-toggle]').forEach((el, i) => {\n    if (!el.getAttribute('aa-tabs-toggle')) el.setAttribute('aa-tabs-toggle', `aa-tabs-${i}`)\n  })\n  root.querySelectorAll<HTMLElement>('[aa-tabs-content]').forEach((el, i) => {\n    if (!el.getAttribute('aa-tabs-content')) el.setAttribute('aa-tabs-content', `aa-tabs-${i}`)\n  })\n  root.querySelectorAll<HTMLElement>('[aa-tabs-visual]').forEach((el, i) => {\n    if (!el.getAttribute('aa-tabs-visual')) el.setAttribute('aa-tabs-visual', `aa-tabs-${i}`)\n  })\n}\n\nfunction readDuration(el: HTMLElement | null, fallback: number): number {\n  if (!el) return fallback\n  return parseNum(el.getAttribute('aa-duration'), fallback)\n}\n\nfunction readEase(el: HTMLElement | null, fallback: string): string {\n  if (!el) return fallback\n  const v = el.getAttribute('aa-ease')\n  return v && v.length > 0 ? v : fallback\n}\n\n/**\n * Read the autoplay interval declared on an element via `aa-autoplay`. The\n * attribute syntax matches the global parser: a numeric token sets the\n * interval; `hover-pause` is a flag the global parser handles (we ignore it\n * per-tab). Absent attribute or no usable number → returns fallback.\n */\nfunction readInterval(el: HTMLElement | null, fallback: number): number {\n  if (!el || !el.hasAttribute('aa-autoplay')) return fallback\n  const raw = el.getAttribute('aa-autoplay') ?? ''\n  for (const t of raw.trim().split(/\\s+/)) {\n    const n = parseFloat(t)\n    if (Number.isFinite(n) && n > 0) return n\n  }\n  return fallback\n}\n\nexport function createTabState(root: HTMLElement, defaults: TabStateDefaults): TabState {\n  autoAssignIds(root)\n\n  const wrappers = Array.from(root.querySelectorAll<HTMLElement>('[aa-tabs-wrapper]'))\n  const useWrapperPattern = wrappers.length > 0\n\n  const toggles = Array.from(root.querySelectorAll<HTMLElement>('[aa-tabs-toggle]'))\n  const entries: TabEntry[] = []\n  const byId = new Map<string, TabEntry>()\n\n  // Root-level overrides waterfall down to toggle/content/visual. Per-tab\n  // autoplay interval comes from each toggle's `aa-autoplay` (numeric token\n  // only); the root `aa-autoplay` is the per-tabset baseline; init.autoplay\n  // is the global default.\n  const rootDuration = readDuration(root, defaults.duration)\n  const rootEase = readEase(root, defaults.ease)\n  const rootInterval = readInterval(root, defaults.interval)\n\n  toggles.forEach((toggle, i) => {\n    const id = toggle.getAttribute('aa-tabs-toggle') ?? `aa-tabs-${i}`\n    const content = root.querySelector<HTMLElement>(`[aa-tabs-content=\"${CSS.escape(id)}\"]`)\n    const visual = root.querySelector<HTMLElement>(`[aa-tabs-visual=\"${CSS.escape(id)}\"]`)\n    const wrapper = useWrapperPattern ? toggle.closest<HTMLElement>('[aa-tabs-wrapper]') : null\n    const progress = toggle.querySelector<HTMLElement>('[aa-tabs-progress]')\n\n    const toggleDuration = readDuration(toggle, rootDuration)\n    const toggleEase = readEase(toggle, rootEase)\n    const toggleInterval = readInterval(toggle, rootInterval)\n\n    const contentDuration = readDuration(content, toggleDuration)\n    const visualDuration = readDuration(visual, toggleDuration)\n\n    const entry: TabEntry = {\n      id,\n      index: i,\n      toggle,\n      content,\n      visual,\n      wrapper,\n      progress,\n      contentDuration,\n      visualDuration,\n      interval: toggleInterval,\n      ease: toggleEase,\n    }\n    entries.push(entry)\n    byId.set(id, entry)\n  })\n\n  const hasContent = entries.some((e) => !!e.content)\n  const hasVisualOnly = !hasContent && entries.some((e) => !!e.visual)\n\n  const statusEl = (entry: TabEntry): HTMLElement => entry.wrapper ?? entry.toggle\n  const isActive = (entry: TabEntry): boolean => statusEl(entry).getAttribute(STATUS_ATTR) === 'active'\n  const setStatus = (entry: TabEntry, status: 'active' | 'inactive'): void => {\n    statusEl(entry).setAttribute(STATUS_ATTR, status)\n    // When not using wrapper pattern, also tag content/visual so authors can\n    // style them off [aa-tabs-content][aa-tabs-status=\"active\"] etc.\n    if (!entry.wrapper) {\n      if (entry.content) entry.content.setAttribute(STATUS_ATTR, status)\n    }\n    if (entry.visual) entry.visual.setAttribute(STATUS_ATTR, status)\n  }\n  const activeEntry = (): TabEntry | null => entries.find(isActive) ?? null\n\n  const initialEntry = (): TabEntry | null => {\n    const explicit = root.querySelector<HTMLElement>('[aa-tabs-initial]')\n    if (explicit) {\n      const matchingToggle = explicit.matches('[aa-tabs-toggle]')\n        ? explicit\n        : explicit.querySelector<HTMLElement>('[aa-tabs-toggle]')\n      if (matchingToggle) {\n        const id = matchingToggle.getAttribute('aa-tabs-toggle')\n        if (id) return byId.get(id) ?? null\n      }\n      // Wrapper-based: aa-tabs-initial on the wrapper → use the toggle inside it\n      const wrapperToggle = explicit.querySelector<HTMLElement>('[aa-tabs-toggle]')\n      if (wrapperToggle) {\n        const id = wrapperToggle.getAttribute('aa-tabs-toggle')\n        if (id) return byId.get(id) ?? null\n      }\n    }\n    return null\n  }\n\n  return {\n    root,\n    entries,\n    byId,\n    useWrapperPattern,\n    hasContent,\n    hasVisualOnly,\n    statusEl,\n    isActive,\n    setStatus,\n    activeEntry,\n    initialEntry,\n  }\n}\n\nexport const TABS_STATUS_ATTR = STATUS_ATTR\n","import { parseAutoplay } from '../../core/autoplay'\nimport { bindRootFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport type { Config } from '../../core/settings'\nimport { REVERSE_TIME_SCALE } from '../../core/trigger'\nimport { createAnimationController, createAriaController, hasVisualAnimation } from './controller'\nimport { setupAutoplay, type AutoplayController } from './autoplay'\nimport { attachKeyboard } from './keyboard'\nimport { setupScroll, type ScrollController } from './scroll'\nimport {\n  TABS_STATUS_ATTR,\n  createTabState,\n  parseTabsValue,\n  type TabEntry,\n  type TabMode,\n  type TabState,\n} from './state'\n\nexport interface TabsApi {\n  state: TabState\n  mode: TabMode\n  open: (entry: TabEntry) => void\n  openSnap: (entry: TabEntry) => void\n  close: (entry: TabEntry) => void\n}\n\ninterface ScrollTriggerLike {\n  isTouch: boolean | number\n  refresh: () => void\n}\n\nfunction setupOne(ctx: FeatureContext, root: HTMLElement, config: Config): (() => void) | undefined {\n  const parsed = parseTabsValue(config['aa-tabs'])\n  if (parsed.isNone) return undefined\n\n  const opts = ctx.options\n  const defaultDuration = (() => {\n    const c = config['aa-duration']\n    const n = c !== undefined ? parseFloat(c) : NaN\n    return Number.isFinite(n) ? n : opts.duration\n  })()\n  const defaultEase = config['aa-ease'] ?? opts.ease\n\n  const autoplay = parseAutoplay(\n    config['aa-autoplay'],\n    opts.autoplay,\n    'aa-autoplay' in config,\n  )\n\n  const state = createTabState(root, {\n    duration: defaultDuration,\n    interval: autoplay.interval,\n    ease: defaultEase,\n  })\n  if (state.entries.length === 0) return undefined\n\n  const gsap = ctx.gsap.gsap as unknown as Record<string, any>\n  const ScrollTrigger = ctx.gsap.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n\n  // Mode resolution: presence of `aa-autoplay` activates autoplay mode and\n  // overrides whatever `aa-tabs` declared. Conflict (`aa-tabs=\"scroll\"` plus\n  // `aa-autoplay`) → autoplay wins; warn in dev so the override isn't silent.\n  let mode: TabMode = parsed.mode\n  if (autoplay.enabled) {\n    if (mode === 'scroll' && ctx.debug) {\n      console.warn(\n        '[alrdy-animate] aa-tabs=\"scroll\" + aa-autoplay both set; autoplay overrides scroll mode.',\n        root,\n      )\n    }\n    mode = 'autoplay'\n  }\n  // Touch fallback: scroll mode degrades to single — pin scrubbing on touch\n  // is brittle and the click-to-jump behaviour is more useful. Keep mutation\n  // local; never touch the DOM attribute (responsive bookkeeping owns that).\n  if (mode === 'scroll' && ScrollTrigger && ScrollTrigger.isTouch) {\n    mode = 'single'\n  }\n\n  const aria = createAriaController(state)\n  const animation = createAnimationController(ctx.gsap)\n\n  aria.applyInitial()\n  animation.applyInitialClosed(state.entries)\n  for (const entry of state.entries) state.setStatus(entry, 'inactive')\n\n  let refreshCall: { kill: () => void } | null = null\n  const debouncedRefresh = (): void => {\n    if (!ScrollTrigger) return\n    refreshCall?.kill()\n    refreshCall = gsap.delayedCall(0.1, () => {\n      ScrollTrigger.refresh()\n      refreshCall = null\n    })\n  }\n\n  const openEntry = (entry: TabEntry): void => {\n    if (state.isActive(entry)) return\n    // For non-multi modes, close any other active entry before opening the new one.\n    let visualDelay = 0\n    if (mode !== 'multi') {\n      const prev = state.activeEntry()\n      if (prev && prev !== entry) {\n        // When the previous visual carries its own aa-animate, wait for that\n        // animate-out to finish before the incoming animate-in fires. Default\n        // cross-fade visuals overlap as before (no delay). The reverse runs\n        // at REVERSE_TIME_SCALE × forward speed, so the actual wall-clock\n        // time we wait is duration / REVERSE_TIME_SCALE.\n        if (prev.visual && hasVisualAnimation(prev.visual)) {\n          visualDelay = prev.visualDuration / REVERSE_TIME_SCALE\n        }\n        closeEntry(prev)\n      }\n    }\n    state.setStatus(entry, 'active')\n    aria.applyOpen(entry)\n    animation.open(entry, { visualDelay, onComplete: debouncedRefresh })\n  }\n\n  const openEntrySnap = (entry: TabEntry): void => {\n    if (state.isActive(entry)) return\n    if (mode !== 'multi') {\n      const prev = state.activeEntry()\n      if (prev && prev !== entry) closeEntry(prev)\n    }\n    state.setStatus(entry, 'active')\n    aria.applyOpen(entry)\n    animation.applyInitialOpen(entry)\n  }\n\n  const closeEntry = (entry: TabEntry): void => {\n    if (!state.isActive(entry)) return\n    state.setStatus(entry, 'inactive')\n    aria.applyClosed(entry)\n    animation.close(entry, debouncedRefresh)\n  }\n\n  const api: TabsApi = {\n    state,\n    mode,\n    open: openEntry,\n    openSnap: openEntrySnap,\n    close: closeEntry,\n  }\n\n  // mode-specific controllers (forward-declared so click handler can stop autoplay).\n  let autoplayCtl: AutoplayController | null = null\n  let scrollCtrl: ScrollController | null = null\n\n  // Determine which entry to open at init.\n  // - Explicit aa-tabs-initial wins.\n  // - Single / autoplay / scroll modes: fall back to the first entry.\n  // - Default / multi: leave everything closed unless an explicit initial is set.\n  const initialEntry = (() => {\n    const explicit = state.initialEntry()\n    if (explicit) return explicit\n    if (mode === 'single' || mode === 'autoplay' || mode === 'scroll') {\n      return state.entries[0] ?? null\n    }\n    return null\n  })()\n\n  // Defer one tick so trigger subscribers (e.g. text feature on inner aa-animate)\n  // have registered before tab-active fires.\n  if (initialEntry) {\n    gsap.delayedCall(0, () => {\n      if (!state.isActive(initialEntry)) openEntrySnap(initialEntry)\n    })\n  }\n\n  const handleToggle = (toggle: HTMLElement): void => {\n    const id = toggle.getAttribute('aa-tabs-toggle')\n    if (!id) return\n    const entry = state.byId.get(id)\n    if (!entry) return\n\n    const active = state.isActive(entry)\n    const cantClose = mode === 'single' || mode === 'autoplay' || mode === 'scroll'\n    if (active && cantClose) return\n\n    // Scroll mode delegates to the scroll controller so the pinned scroll\n    // position drives state. Autoplay restarts its progress on the clicked\n    // tab and keeps cycling.\n    if (scrollCtrl) {\n      scrollCtrl.jumpToIndex(entry.index)\n      return\n    }\n    if (autoplayCtl) {\n      autoplayCtl.sync(entry.index)\n      return\n    }\n\n    if (active) closeEntry(entry)\n    else openEntry(entry)\n  }\n\n  const onClick = (e: Event): void => {\n    const target = e.target as Element | null\n    if (!target) return\n    const toggle = target.closest<HTMLElement>('[aa-tabs-toggle]')\n    if (!toggle || !root.contains(toggle)) return\n    handleToggle(toggle)\n  }\n  root.addEventListener('click', onClick)\n\n  const cleanups: Array<() => void> = []\n  cleanups.push(() => root.removeEventListener('click', onClick))\n\n  cleanups.push(\n    attachKeyboard(root, state.entries.map((e) => e.toggle), {\n      activate: handleToggle,\n    }),\n  )\n\n  if (mode === 'autoplay') {\n    autoplayCtl = setupAutoplay(ctx.gsap, root, api, {\n      hoverPause: autoplay.hoverPause,\n    })\n    cleanups.push(() => autoplayCtl?.destroy())\n  } else if (mode === 'scroll') {\n    // 30vh per tab is the design baseline. `aa-intensity` multiplies it:\n    // intensity=1 (default) = 30vh per tab, 2 = 60vh, 0.5 = 15vh.\n    const intensity = parseFloat(config['aa-intensity'] ?? '') || 1\n    const scrollStart = config['aa-scroll-start'] ?? 'top 20%'\n    const scrubAttr = config['aa-scrub']\n    const scrub = scrubAttr === undefined ? true : scrubAttr === 'true' ? true : parseFloat(scrubAttr) || true\n    scrollCtrl = setupScroll(ctx.gsap, root, api, {\n      distanceVh: 30 * intensity,\n      scrollStart,\n      scrub,\n    })\n    if (scrollCtrl) cleanups.push(() => scrollCtrl?.destroy())\n  }\n\n  return () => {\n    for (const fn of cleanups) fn()\n    refreshCall?.kill()\n    refreshCall = null\n    animation.cleanup(state.entries)\n    for (const entry of state.entries) {\n      state.statusEl(entry).removeAttribute(TABS_STATUS_ATTR)\n      if (!entry.wrapper && entry.content) entry.content.removeAttribute(TABS_STATUS_ATTR)\n      if (entry.visual) entry.visual.removeAttribute(TABS_STATUS_ATTR)\n    }\n    aria.cleanup()\n  }\n}\n\nconst tabsFeature: FeatureModule = {\n  name: 'tabs',\n  init(ctx: FeatureContext): () => void {\n    bindRootFeature(ctx, 'aa-tabs', setupOne)\n    return () => {}\n  },\n}\n\nexport default tabsFeature\n","import { parseAutoplay } from '../../core/autoplay'\nimport { bindRootFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport { parseNum, parseScrub } from '../../core/parse'\nimport { readAttrs, type BucketKey, type Config } from '../../core/settings'\nimport { attachHoverPauseListener, createViewportGate } from '../../core/viewport-gate'\n\ninterface ParsedTokens {\n  isRight: boolean\n  hasSwitch: boolean\n  isDraggable: boolean\n  isNone: boolean\n}\n\nfunction parseMarqueeValue(raw: string | undefined): ParsedTokens {\n  const tokens = (raw ?? '')\n    .trim()\n    .split(/\\s+/)\n    .filter(Boolean)\n  return {\n    isRight: tokens.includes('right'),\n    hasSwitch: tokens.includes('switch'),\n    isDraggable: tokens.includes('draggable'),\n    isNone: tokens.includes('none'),\n  }\n}\n\n// Animation attributes stripped from clones so the FOUC guard\n// (`[aa-animate]:not([aa-ready])`) doesn't leave them hidden and no stray\n// ScrollTrigger/entrance re-fires on a duplicated item. Originals keep theirs.\nconst CLONE_STRIPPED_ATTRS = [\n  'aa-animate',\n  'aa-delay',\n  'aa-duration',\n  'aa-stagger',\n  'aa-trigger',\n  'aa-again',\n  'aa-scroll-start',\n  'aa-scroll-end',\n  'aa-ease',\n]\n// Inline from-state GSAP may have applied to the original before cloning.\n// Includes clip-path (reveal-*) and both vendor forms.\nconst CLONE_CLEARED_STYLES = [\n  'opacity',\n  'transform',\n  'filter',\n  'visibility',\n  'clip-path',\n  '-webkit-clip-path',\n]\n\nfunction clearFromState(el: HTMLElement): void {\n  for (const prop of CLONE_CLEARED_STYLES) el.style.removeProperty(prop)\n}\n\n// Strip the animation attributes so the clone is never rescanned or FOUC-hidden;\n// then clear any inline from-state so the clone renders solid. The from-state\n// may sit on the `aa-animate` element itself, on its direct children (the\n// `aa-stagger` targets), or deeper still (split text lands opacity/transform on\n// grandchild char/word/line spans) — so clear across the whole animated subtree.\nfunction sanitizeClone(clone: HTMLElement): void {\n  const animated = clone.matches('[aa-animate]')\n    ? [clone, ...clone.querySelectorAll<HTMLElement>('[aa-animate]')]\n    : [...clone.querySelectorAll<HTMLElement>('[aa-animate]')]\n  for (const el of animated) {\n    for (const attr of CLONE_STRIPPED_ATTRS) el.removeAttribute(attr)\n    clearFromState(el)\n    for (const desc of el.querySelectorAll<HTMLElement>('*')) clearFromState(desc)\n  }\n}\n\n// `hover-slow` ramps the loop down to this fraction of its cruise timeScale.\nconst HOVER_SLOW_FACTOR = 0.15\n\ninterface DraggableInstance {\n  kill: () => void\n  enable: () => DraggableInstance\n  disable: () => DraggableInstance\n  startX: number\n  x: number\n  isThrowing: boolean\n  getDirection: (from: 'start' | 'velocity') => string\n  vars: Record<string, unknown>\n  /** The InertiaPlugin throw tween (present while a throw is in flight). */\n  tween?: { kill: () => void }\n}\n\ninterface DraggableConstructor {\n  create: (target: unknown, vars: Record<string, unknown>) => DraggableInstance[]\n}\n\ninterface ScrollTriggerLike {\n  create: (vars: Record<string, unknown>) => { kill: () => void }\n}\n\ninterface InertiaPluginLike {\n  track?: (target: unknown, properties: string) => unknown[]\n  untrack?: (target: unknown, properties?: string) => void\n  getVelocity?: (target: unknown, property: string) => number\n}\n\nfunction fillTrack(\n  list: HTMLElement,\n  track: HTMLElement,\n  rootWidth: number,\n  cycleDistance: number,\n  scrubOvershootPx: number,\n): HTMLElement[] {\n  const clones: HTMLElement[] = []\n  // Loop wrap needs `viewport + cycleDistance` worth of content so the seam\n  // is invisible. Scrub mode shifts the scroller by ±scrubOvershoot on top of\n  // that, so we add 2× the overshoot to keep the visible window populated at\n  // both extremes of the sweep. +2px slop tolerates sub-pixel rounding.\n  const minRequiredWidth = rootWidth + cycleDistance + scrubOvershootPx * 2 + 2\n  let safety = 0\n  while (track.scrollWidth < minRequiredWidth && safety < 20) {\n    const clone = list.cloneNode(true) as HTMLElement\n    clone.setAttribute('aa-marquee-clone', '')\n    clone.setAttribute('aria-hidden', 'true')\n    // Strip aa-animate (+ companions + inline from-state) so cloned items\n    // render solid instead of staying FOUC-hidden or replaying an entrance.\n    sanitizeClone(clone)\n    track.appendChild(clone)\n    clones.push(clone)\n    safety++\n  }\n  return clones\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  root: HTMLElement,\n  config: Config,\n): (() => void) | undefined {\n  const tokens = parseMarqueeValue(config['aa-marquee'])\n  if (tokens.isNone) return undefined\n\n  // Track (infinite-loop layer, where clones land) and list (the authored\n  // cluster, cloned to fill the track) are always required. Scroller is the\n  // optional scroll-driven sweep layer — only needed when `aa-scrub` is set;\n  // it wraps the track when present.\n  const track = root.querySelector<HTMLElement>('[aa-marquee-track]')\n  const list = root.querySelector<HTMLElement>('[aa-marquee-list]')\n  if (!track || !list) {\n    if (ctx.debug) {\n      console.warn(\n        '[alrdy-animate] aa-marquee requires [aa-marquee-track] and [aa-marquee-list] descendants.',\n        root,\n      )\n    }\n    return undefined\n  }\n\n  // Autoplay drives the infinite loop. Presence of `aa-autoplay` enables it\n  // (matching slider/tabs); absence leaves the marquee static (scrub may still\n  // apply). The value is the seconds-per-cycle duration, defaulting to 40.\n  const autoplay = parseAutoplay(\n    config['aa-autoplay'],\n    ctx.options.autoplay,\n    'aa-autoplay' in config,\n    40,\n  )\n  const isPlaying = autoplay.enabled\n  const duration = autoplay.interval\n\n  // Scrub is enabled by the presence of `aa-scrub` on the root (as with every\n  // other feature). The value becomes the ScrollTrigger scrub delay — `true`\n  // for an instant lock, or seconds for smoothing. The sweep travel is a\n  // percentage of the marquee's own width, authored on the scroller element:\n  // `aa-marquee-scroller=\"30\"` → ±30% of the marquee width per side (default\n  // 20 → ±20%). Width-relative (not viewport-relative) so the sweep feels the\n  // same regardless of how wide the browser is. Scrub requires the wrapper.\n  const scroller = root.querySelector<HTMLElement>('[aa-marquee-scroller]')\n  const scrubValue = parseScrub(config['aa-scrub'])\n  const wantsScrub = scrubValue !== undefined\n  if (wantsScrub && !scroller && ctx.debug) {\n    console.warn(\n      '[alrdy-animate] aa-marquee scrub requires an [aa-marquee-scroller] wrapper around [aa-marquee-track].',\n      root,\n    )\n  }\n  const isScrub = wantsScrub && !!scroller\n  const scrubTravelPct = parseNum(config['aa-marquee-scroller'], 20)\n\n  const gsap = ctx.gsap.gsap as unknown as Record<string, any>\n  const ScrollTrigger = ctx.gsap.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  const Draggable = ctx.gsap.plugins.Draggable as DraggableConstructor | undefined\n  const InertiaPlugin = ctx.gsap.plugins.InertiaPlugin as InertiaPluginLike | undefined\n  void InertiaPlugin\n\n  // Cycle distance is just list.scrollWidth — `margin-left` / `margin-right`\n  // on items fold into that measurement, so cloned-list seams match in-list\n  // spacing automatically. CSS `gap` / `column-gap` is not supported. We\n  // remeasure on demand (never cache long-term) because lazy images and late\n  // web fonts grow the list *after* init — see the ResizeObserver below.\n  const measureCycle = (): number => list.scrollWidth || list.getBoundingClientRect().width\n\n  // Loop + clones + scrub all depend on the measured cycle. They live inside\n  // buildInner so the ResizeObserver can tear the whole lot down and rebuild\n  // it against a fresh measurement. activeLoop/builtCycle bridge the current\n  // build out to the rebuild scheduler.\n  let activeLoop: ReturnType<typeof gsap.to> | undefined\n  let builtCycle = 0\n\n  const buildInner = (prevProgress?: number): (() => void) | undefined => {\n    const rootWidth = root.getBoundingClientRect().width\n    const cycleDistance = measureCycle()\n    if (!rootWidth || !cycleDistance) return undefined\n    builtCycle = cycleDistance\n\n    // Compute scrub overshoot up front so fillTrack provisions enough clones\n    // to cover both the loop wrap AND the scroller sweep at its extremes. The\n    // sweep is `scrubTravelPct` percent of the marquee's own width per side, so\n    // half-sweep px = rootWidth * scrubTravelPct / 100.\n    const halfSweepPx = isScrub ? (rootWidth * scrubTravelPct) / 100 : 0\n\n    const clones = fillTrack(list, track, rootWidth, cycleDistance, halfSweepPx)\n\n    // Scrub composes with the loop by sitting on a different transform layer:\n    // the scroller takes the scroll-driven x sweep, the track takes the infinite\n    // loop x — both translate independently, the browser composes them. Without\n    // the marginLeft offset, the scroller's content span would not cover root's\n    // left edge at the +halfSweepPx extreme (max right shift), exposing the gap\n    // between root.left and the shifted scroller. We restore the original inline\n    // margin-left on cleanup so authored CSS keeps owning the static state.\n    const originalScrollerMarginLeft = scroller?.style.marginLeft ?? ''\n    if (isScrub && scroller) {\n      scroller.style.marginLeft = `${-halfSweepPx}px`\n    }\n\n    // Build the infinite tween. modifiers.x wraps x ∈ [-cycleDistance, 0) so the\n    // track translates leftward forever without an actual reset jump. The same\n    // tween drives both directions — direction is set via timeScale, not by\n    // changing the tween target.\n    const wrapX = (gsap.utils.wrap as (a: number, b: number) => (n: number) => number)(\n      -cycleDistance,\n      0,\n    )\n    gsap.set(track, { x: 0 })\n    // Create paused so we can set progress + timeScale before the first tick.\n    // Without this, the tween auto-starts forward at timeScale=1 and a few\n    // microseconds of forward motion leak in before the right-direction setup\n    // (progress(1) + timeScale(-1)) lands. With repeat:-1, the loop bounces\n    // forward forever; with timeScale<0 it reverses, and onReverseComplete\n    // fires when the reversed loop reaches time 0 — without bouncing it back\n    // to the end, the loop just stops there. Mirror Osmo's pattern.\n    let loop: ReturnType<typeof gsap.to>\n    loop = gsap.to(track, {\n      x: -cycleDistance,\n      duration,\n      ease: 'none',\n      repeat: -1,\n      paused: true,\n      onReverseComplete: () => loop.progress(1),\n      modifiers: {\n        x: (x: string) => wrapX(parseFloat(x)) + 'px',\n      },\n    })\n    activeLoop = loop\n\n    // Direction: left = +1 (default), right = -1. Track this in a tweenable\n    // wrapper so drag/switch interactions can smoothly ramp it.\n    const baseDirection = tokens.isRight ? -1 : 1\n    const timeScale = { value: baseDirection }\n    let lastSwitchDirection = baseDirection\n    // Last `aa-marquee-direction` value written, so applyTimeScale can skip\n    // redundant same-value attribute writes on its per-frame ramp path.\n    let lastDirectionAttr: 'left' | 'right' | undefined\n\n    // hover-slow scales the cruise timeScale by a positive factor (1 = full\n    // speed). It multiplies onto timeScale.value so it composes with switch's\n    // direction ramp and draggable's resume. Direction reflects the sign of\n    // timeScale.value alone — the factor is always positive, so it never flips\n    // the reported direction.\n    const hoverFactor = { value: 1 }\n\n    const applyTimeScale = (): void => {\n      const ts = timeScale.value * hoverFactor.value\n      // A tween sitting exactly at a boundary has no runway to play *toward*\n      // that boundary: reverse (ts < 0) from progress 0, or forward from\n      // progress 1, freezes — GSAP won't wrap a repeat tween past the edge it's\n      // already on, and `onReverseComplete` only fires mid-playback, not when a\n      // reversed tween is resumed already at the start. The wrap modifier makes\n      // progress 0 and 1 render identically, so nudging to the far edge is\n      // invisible and restores runway. This also seeds the right-direction first\n      // build (progress 0, ts -1 → nudged to 1), and rescues a loop reversed by\n      // `switch` / draggable while still parked at the boundary (e.g. built\n      // paused after loading scrolled-past). The check only fires at the seam\n      // (progress ∈ {0,1}); mid-cycle onUpdate frames are no-ops.\n      const p = loop.progress()\n      if (ts < 0 && p <= 0) loop.progress(1)\n      else if (ts > 0 && p >= 1) loop.progress(0)\n      loop.timeScale(ts)\n      // Only touch the attribute when the direction sign actually flips —\n      // applyTimeScale runs every frame of the switch / hover-slow ramps, and a\n      // same-value setAttribute still invalidates style on the element.\n      const dir = timeScale.value < 0 ? 'right' : 'left'\n      if (dir !== lastDirectionAttr) {\n        root.setAttribute('aa-marquee-direction', dir)\n        lastDirectionAttr = dir\n      }\n    }\n\n    // Restore the prior progress fraction across a rebuild so the corrective\n    // remeasure (lazy images loaded) doesn't itself flash a reset. On the first\n    // build there's no prior progress: applyTimeScale's boundary guard seeds\n    // the right-direction headroom (progress 0 + ts -1 → nudged to 1, Osmo).\n    if (typeof prevProgress === 'number') loop.progress(prevProgress)\n    applyTimeScale()\n    if (isPlaying) loop.play()\n\n    const cleanups: Array<() => void> = []\n\n    // Scrub layer: scroll progress drives the wrapper's x. The sweep is a\n    // percentage of the marquee's own width — `aa-marquee-scroller=\"30\"` →\n    // ±30% of rootWidth per side (default 20 → ±20%). baseDirection (left/right)\n    // flips which way the row drifts on scroll-down. A viewport resize rebuilds\n    // the whole unit (rootWidth is remeasured), so this layer doesn't need its\n    // own resize listener.\n    if (isScrub && scroller && ScrollTrigger) {\n      const sweepPx = (rootWidth * scrubTravelPct) / 100\n      // Default direction (left) sweeps right→left as you scroll down so it\n      // composes with the leftward loop. `right` token flips both ends.\n      const startX = baseDirection > 0 ? sweepPx : -sweepPx\n      const endX = -startX\n      const scrubTween = gsap.fromTo(\n        scroller,\n        { x: startX },\n        {\n          x: endX,\n          ease: 'none',\n          immediateRender: true,\n          scrollTrigger: {\n            trigger: root,\n            start: 'top bottom',\n            end: 'bottom top',\n            scrub: scrubValue,\n            invalidateOnRefresh: true,\n          },\n        },\n      )\n      cleanups.push(() => {\n        ;(scrubTween as { scrollTrigger?: { kill: () => void } }).scrollTrigger?.kill()\n        scrubTween.kill()\n      })\n    }\n\n    let draggable: DraggableInstance | null = null\n\n    // Optional draggable: mirror the slider's horizontalLoop pattern. On press\n    // we pause the loop and capture its progress, mapping the proxy's x to that\n    // progress so subsequent drag delta translates 1:1 into progress delta. Each\n    // drag tick aligns loop.progress() to the wrapped target. Draggable's own\n    // inertia continues to drive align after release; on throw complete, the\n    // loop resumes in the direction of the last flick (captured on release).\n    if (tokens.isDraggable) {\n      if (!Draggable || typeof Draggable.create !== 'function' || !InertiaPlugin) {\n        if (ctx.debug) {\n          console.warn(\n            '[alrdy-animate] aa-marquee=\"draggable\" requires GSAP Draggable + InertiaPlugin. Add the Draggable.min.js and InertiaPlugin.min.js script tags.',\n            root,\n          )\n        }\n      } else {\n        const proxy = document.createElement('div')\n        proxy.setAttribute('aria-hidden', 'true')\n        proxy.style.cssText = 'position:absolute;width:0;height:0;pointer-events:none;'\n        root.appendChild(proxy)\n\n        const wrap = (gsap.utils.wrap as (a: number, b: number) => (n: number) => number)(0, 1)\n        const ratio = 1 / cycleDistance\n        let startProgress = 0\n        // Resume direction after the throw lands. Default to baseDirection so a\n        // press-without-flick (or no-velocity click) returns to the original\n        // cruise direction. Each release with measurable velocity overrides it.\n        let throwDirection = baseDirection\n\n        // Proxy-space speed (px/s) that matches the loop's cruise: the loop\n        // advances one cycle (progress 0→1) over `duration`s, and align maps\n        // proxy.x → progress at 1/cycleDistance, so cruise ≡ cycleDistance/duration.\n        const cruiseVelPxPerS = cycleDistance / duration\n        // Per-throw velocity sampling so we can hand the decelerating throw off\n        // to the loop the instant it slows to cruise speed (see onThrowUpdate).\n        let prevThrowX = 0\n        let prevThrowT = 0\n        let handedOff = false\n\n        const align = (): void => {\n          if (!draggable) return\n          loop.progress(wrap(startProgress + (draggable.startX - draggable.x) * ratio))\n        }\n\n        const resumeLoop = (): void => {\n          // Without autoplay the loop has no cruise to resume — the drag\n          // settles and the marquee stays put.\n          if (!isPlaying) return\n          timeScale.value = throwDirection\n          applyTimeScale()\n          loop.resume()\n        }\n\n        draggable = Draggable.create(proxy, {\n          trigger: root,\n          type: 'x',\n          inertia: true,\n          cursor: 'grab',\n          activeCursor: 'grabbing',\n          onPressInit(this: DraggableInstance) {\n            gsap.killTweensOf(timeScale)\n            gsap.killTweensOf(loop)\n            loop.pause()\n            startProgress = loop.progress()\n            // Anchor proxy.x at -progress/ratio so subsequent drag delta\n            // becomes (startX - x) = drag delta, which align() turns into\n            // progress delta with the right sign.\n            gsap.set(proxy, { x: -startProgress / ratio })\n            prevThrowT = 0\n            handedOff = false\n          },\n          onDrag: align,\n          onThrowUpdate(this: DraggableInstance) {\n            align()\n            // Blend the throw into the cruise loop: once the decelerating throw\n            // slows to the loop's own speed, kill the inertia and resume the\n            // loop from here. Because the speeds (and direction — throwDirection\n            // is the flick direction) match at the crossover, it continues\n            // seamlessly instead of coasting to a stop and then jumping back up\n            // to cruise. dt-free-ish: sample proxy.x speed frame to frame.\n            if (!isPlaying || handedOff) return\n            const now = performance.now()\n            const x = this.x\n            if (prevThrowT) {\n              const dt = (now - prevThrowT) / 1000\n              if (dt > 0 && Math.abs(x - prevThrowX) / dt <= cruiseVelPxPerS) {\n                handedOff = true\n                this.tween?.kill()\n                resumeLoop()\n                return\n              }\n            }\n            prevThrowX = x\n            prevThrowT = now\n          },\n          onRelease(this: DraggableInstance) {\n            // Capture the flick direction from velocity at release.\n            // Drag right (proxy.x increasing → progress decreasing → track moves\n            // right) ⇒ resume loop in right direction (timeScale -1).\n            // Drag left ⇒ resume in left direction (timeScale +1).\n            // Empty / vertical-only velocity leaves throwDirection unchanged.\n            const dir = this.getDirection('velocity')\n            if (dir.startsWith('right')) throwDirection = -1\n            else if (dir.startsWith('left')) throwDirection = 1\n            // No throw means a static press — onThrowComplete will not fire,\n            // so resume here. With a real throw, defer to onThrowComplete.\n            if (!this.isThrowing) resumeLoop()\n          },\n          onThrowComplete: resumeLoop,\n        })[0]\n\n        cleanups.push(() => {\n          draggable?.kill()\n          proxy.remove()\n        })\n      }\n    }\n\n    // Optional hover-pause. Skipped on touch devices (no hover semantics) and\n    // when the element is also draggable — dragging implies sustained pointerover\n    // and a hover-pause would freeze the loop mid-drag. Critical: use resume()\n    // not play() — play() always plays forward and would flip the direction of\n    // a right-direction marquee. resume() preserves the current play direction.\n    if (autoplay.hoverPause && !tokens.isDraggable && isPlaying) {\n      let pausedByHover = false\n      cleanups.push(\n        attachHoverPauseListener({\n          root,\n          onEnter: () => {\n            if (loop.paused()) return\n            loop.pause()\n            pausedByHover = true\n          },\n          onLeave: () => {\n            if (!pausedByHover) return\n            pausedByHover = false\n            loop.resume()\n          },\n        }),\n      )\n    }\n\n    // Optional hover-slow. Same gating as hover-pause (skip on touch + when\n    // draggable), and yields to hover-pause when both are set — pausing and\n    // slowing on the same pointerover would fight. We tween hoverFactor between\n    // 1 and HOVER_SLOW_FACTOR and re-apply via applyTimeScale on every frame so\n    // the ramp respects the live direction (switch may flip it mid-hover).\n    if (autoplay.hoverSlow && !autoplay.hoverPause && !tokens.isDraggable && isPlaying) {\n      const rampTo = (target: number): void => {\n        gsap.killTweensOf(hoverFactor)\n        gsap.to(hoverFactor, {\n          value: target,\n          duration: 0.4,\n          ease: 'power2.out',\n          onUpdate: applyTimeScale,\n          onComplete: applyTimeScale,\n        })\n      }\n      cleanups.push(\n        attachHoverPauseListener({\n          root,\n          onEnter: () => rampTo(HOVER_SLOW_FACTOR),\n          onLeave: () => rampTo(1),\n        }),\n      )\n      cleanups.push(() => gsap.killTweensOf(hoverFactor))\n    }\n\n    // Optional switch: invert direction when body[aa-scroll-direction] flips.\n    // Needs a running loop (autoplay) to have a direction to flip, and conflicts\n    // with draggable's velocity-driven timeScale, so we skip it in both cases.\n    if (tokens.hasSwitch && !tokens.isDraggable && isPlaying) {\n      const apply = (): void => {\n        const scrollDirection = document.body.getAttribute('aa-scroll-direction') ?? 'down'\n        const isInverted = scrollDirection === 'up'\n        const newDirection = isInverted ? -baseDirection : baseDirection\n        if (newDirection === lastSwitchDirection) return\n        lastSwitchDirection = newDirection\n        gsap.killTweensOf(timeScale)\n        gsap.to(timeScale, {\n          value: newDirection,\n          duration: 0.3,\n          ease: 'power2.out',\n          onUpdate: applyTimeScale,\n          onComplete: applyTimeScale,\n        })\n      }\n      const mo = new MutationObserver((mutations) => {\n        for (const m of mutations) {\n          if (m.attributeName === 'aa-scroll-direction') {\n            apply()\n            break\n          }\n        }\n      })\n      mo.observe(document.body, {\n        attributes: true,\n        attributeFilter: ['aa-scroll-direction'],\n      })\n      cleanups.push(() => mo.disconnect())\n      apply()\n    }\n\n    // Pause loop + drag input when the marquee is off-screen — mirrors the\n    // viewport gating slider/tabs autoplay use. Without this the loop keeps\n    // ticking far below or above the fold for no visible benefit. Use resume()\n    // here too so right-direction loops don't get flipped by the gating.\n    const gateDispose = createViewportGate(ctx.gsap, {\n      trigger: root,\n      onActive: () => {\n        if (isPlaying) loop.resume()\n        applyTimeScale()\n        draggable?.enable()\n      },\n      onIdle: () => {\n        loop.pause()\n        draggable?.disable()\n      },\n    })\n    if (gateDispose) cleanups.push(gateDispose)\n\n    return () => {\n      for (const fn of cleanups) fn()\n      gsap.killTweensOf(timeScale)\n      loop.kill()\n      if (activeLoop === loop) activeLoop = undefined\n      for (const c of clones) c.remove()\n      gsap.set(track, { clearProps: 'transform,x' })\n      if (isScrub && scroller) {\n        gsap.set(scroller, { clearProps: 'transform,x' })\n        // Restore whatever inline margin-left the author had (usually empty).\n        // We never touch external CSS, so styles applied via classes are\n        // unaffected — only our own inline override is reverted.\n        scroller.style.marginLeft = originalScrollerMarginLeft\n      }\n      root.removeAttribute('aa-marquee-direction')\n    }\n  }\n\n  // buildInner returns undefined when the marquee measures 0×0 — it's hidden\n  // (display:none inside a closed modal or a Webflow form-success wrapper) or\n  // its content hasn't laid out yet. Don't bail permanently: fall through and\n  // let the ResizeObserver below rebuild the moment the list gains width (the\n  // modal opens / late images land) — scheduleRebuild already tolerates a\n  // never-built start (activeLoop/teardownInner undefined, builtCycle 0). Only\n  // give up when there's no ResizeObserver to recover with (SSR / ancient\n  // browsers), where the deferred build could never fire.\n  let teardownInner = buildInner()\n  if (!teardownInner && typeof ResizeObserver === 'undefined') return undefined\n\n  // Lazy images and late web fonts grow the list *after* the first measurement,\n  // which would leave the loop wrapping at a stale, too-short distance — the\n  // marquee then visibly snaps back mid-list (the seam lands wherever the old\n  // wrap point now sits). A ResizeObserver on the list is the right primitive:\n  // it fires on every layout-size change (images, fonts, responsive item\n  // widths) and never on the loop's transform (which animates the track, not\n  // the list's box), so the steady-state animation pays nothing. We debounce so\n  // a burst of images loading triggers a single rebuild, guard on a real change\n  // so no-op fires are dropped, and preserve the loop's progress fraction so the\n  // rebuild is seamless. Viewport resizes also rebuild when scrubbing, because\n  // the sweep magnitude is viewport-relative.\n  let rebuildTimer: ReturnType<typeof setTimeout> | undefined\n  let forceRebuild = false\n  const scheduleRebuild = (force: boolean): void => {\n    if (force) forceRebuild = true\n    if (rebuildTimer) clearTimeout(rebuildTimer)\n    rebuildTimer = setTimeout(() => {\n      rebuildTimer = undefined\n      const doForce = forceRebuild\n      forceRebuild = false\n      const next = measureCycle()\n      if (!next) return\n      if (Math.abs(next - builtCycle) < 1 && !doForce) return\n      const prevProgress = activeLoop ? activeLoop.progress() : undefined\n      teardownInner?.()\n      teardownInner = buildInner(prevProgress)\n    }, 150)\n  }\n\n  const ro =\n    typeof ResizeObserver !== 'undefined'\n      ? new ResizeObserver(() => scheduleRebuild(false))\n      : null\n  ro?.observe(list)\n\n  // Viewport resize only needs to rebuild when scrubbing (the sweep scales with\n  // rootWidth, which usually changes on resize); a pure-loop marquee's cycle is\n  // caught by the RO.\n  const offResize = isScrub ? ctx.onResize(() => scheduleRebuild(true), 200) : undefined\n\n  return () => {\n    if (rebuildTimer) clearTimeout(rebuildTimer)\n    ro?.disconnect()\n    offResize?.()\n    teardownInner?.()\n  }\n}\n\n// `aa-marquee-scroller` lives on the (optional) scroller child, not the root,\n// so the standard root-only readAttrs never sees it. We read the child's own\n// per-breakpoint buckets and fold its `aa-marquee-scroller` values into the\n// root's buckets, so the scrub travel resolves through the same `|`/suffix\n// pipeline (and matchMedia rebuild) as every other responsive attribute.\nfunction mergeScrollerAttrs(root: HTMLElement): ReturnType<typeof readAttrs> {\n  const attrs = readAttrs(root)\n  const scroller = root.querySelector<HTMLElement>('[aa-marquee-scroller]')\n  if (!scroller) return attrs\n  const scrollerAttrs = readAttrs(scroller)\n  for (const [key, bucket] of scrollerAttrs.buckets) {\n    const travel = bucket['aa-marquee-scroller']\n    if (travel === undefined) continue\n    let target = attrs.buckets.get(key as BucketKey)\n    if (!target) {\n      target = {}\n      attrs.buckets.set(key as BucketKey, target)\n    }\n    target['aa-marquee-scroller'] = travel\n  }\n  return attrs\n}\n\nconst marqueeFeature: FeatureModule = {\n  name: 'marquee',\n  init(ctx: FeatureContext): () => void {\n    bindRootFeature(ctx, 'aa-marquee', setupOne, mergeScrollerAttrs)\n    return () => {}\n  },\n}\n\nexport default marqueeFeature\n","import type { GsapTween } from '../../core/gsap-detect'\nimport type { FeatureContext, FeatureModule } from '../../core/registry'\nimport { parseNum } from '../../core/parse'\nimport { readAttrs } from '../../core/settings'\n\ninterface ScrollTriggerLike {\n  create: (vars: Record<string, unknown>) => ScrollTriggerInstance\n}\n\ninterface ScrollTriggerInstance {\n  kill: () => void\n}\n\ninterface FlipLike {\n  fit: (\n    target: Element,\n    source: Element,\n    vars?: Record<string, unknown>,\n  ) => unknown\n}\n\ninterface ParsedNavValue {\n  hide: boolean\n  change: boolean\n  scrolledPx: number\n  none: boolean\n}\n\nfunction parseNavValue(value: string | undefined): ParsedNavValue {\n  const result: ParsedNavValue = { hide: false, change: false, scrolledPx: 100, none: false }\n  if (!value) return result\n  const tokens = value.split(/\\s+/).filter(Boolean)\n  for (const token of tokens) {\n    if (token === 'none') result.none = true\n    else if (token === 'hide') result.hide = true\n    else if (token === 'change') result.change = true\n    else if (token.startsWith('change-')) {\n      result.change = true\n      const n = parseInt(token.slice(7), 10)\n      if (Number.isFinite(n)) result.scrolledPx = n\n    }\n    // No `hide-<px>`: the hide animation is gated globally by the body's\n    // aa-scroll-started threshold (50px, set in core/scroll-state.ts) so a\n    // per-nav hide threshold can't be expressed by the CSS-driven approach.\n  }\n  return result\n}\n\n/**\n * 3a. GSAP-driven hide + JS-toggled `is-scrolled` class.\n * Responsive: bound through ctx.responsive so `aa-nav=\"hide|none\"` opts out\n * cleanly per breakpoint.\n */\nfunction setupHideAndChange(ctx: FeatureContext, navElement: HTMLElement): () => void {\n  const attrs = readAttrs(navElement)\n  ctx.responsive.bind(navElement, attrs, ({ config }) => {\n    const parsed = parseNavValue(config['aa-nav'])\n    if (parsed.none) return undefined\n\n    const cleanups: Array<() => void> = []\n\n    if (parsed.hide) {\n      // GSAP-driven, not CSS. The nav commonly also carries an `aa-animate`\n      // entrance whose tween owns the element's `transform` (and zeroes the\n      // individual `translate`/`rotate`/`scale` props so they can't fight it),\n      // so the hide has to run through GSAP too — one system owning `transform`\n      // means no inline-vs-stylesheet conflict and no author-`transition`\n      // clobber. `overwrite: 'auto'` lets a mid-hide direction reversal pick up\n      // from the current position instead of snapping, so there's no flash.\n      //\n      // -150% is the design baseline: at intensity=1 the nav slides far enough\n      // off-screen to clear a typical drop-shadow. The 150 is baked in here so\n      // aa-intensity=1 reproduces the recommended look across every feature.\n      const gsap = ctx.gsap.gsap\n      const intensity = parseNum(config['aa-intensity'], 1)\n      const duration = parseNum(config['aa-duration'], ctx.options.duration)\n      const ease = config['aa-ease'] ?? 'osmo'\n      const hiddenY = -150 * intensity\n\n      // Drive off the same body scroll-state attributes the CSS used to read\n      // (set by core/scroll-state.ts; gated together with it under\n      // init({ scrollState }).)\n      const body = document.body\n      const shouldHide = (): boolean =>\n        body.getAttribute('aa-scroll-direction') === 'down' &&\n        body.getAttribute('aa-scroll-started') === 'true'\n\n      let hidden = shouldHide()\n      // Seed the resting state without a tween so init() never overwrites a\n      // concurrent entrance tween mid-flight. Seeding hidden=true only happens\n      // on a reload already scrolled past the threshold, where snapping\n      // off-screen is the correct first frame anyway.\n      if (hidden) gsap.set(navElement, { yPercent: hiddenY })\n\n      let tween: GsapTween | undefined\n      const sync = (): void => {\n        const next = shouldHide()\n        if (next === hidden) return\n        hidden = next\n        tween = gsap.to(navElement, {\n          yPercent: next ? hiddenY : 0,\n          duration,\n          ease,\n          overwrite: 'auto',\n        })\n      }\n\n      const observer = new MutationObserver(sync)\n      observer.observe(body, {\n        attributes: true,\n        attributeFilter: ['aa-scroll-direction', 'aa-scroll-started'],\n      })\n\n      cleanups.push(() => {\n        observer.disconnect()\n        tween?.kill()\n        gsap.set(navElement, { yPercent: 0 })\n      })\n    }\n\n    if (parsed.change) {\n      const threshold = parsed.scrolledPx\n      let hasClass = false\n      const update = (): void => {\n        const past = window.scrollY >= threshold\n        if (past && !hasClass) {\n          navElement.classList.add('is-scrolled')\n          hasClass = true\n        } else if (!past && hasClass) {\n          navElement.classList.remove('is-scrolled')\n          hasClass = false\n        }\n      }\n      update()\n      window.addEventListener('scroll', update, { passive: true })\n      cleanups.push(() => {\n        window.removeEventListener('scroll', update)\n        navElement.classList.remove('is-scrolled')\n      })\n    }\n\n    return () => cleanups.forEach((c) => c())\n  })\n\n  return () => {}\n}\n\n/**\n * 3b. Highlight the nav link whose `aa-scroll-target` section is in view.\n * Adds `is-current` on enter, removes on leave. Mirrors v7 onEnter/onEnterBack\n * /onLeave/onLeaveBack behaviour.\n */\nfunction setupCurrentLinkTracking(\n  ctx: FeatureContext,\n  navElement: HTMLElement,\n): () => void {\n  const ScrollTrigger = ctx.gsap.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  if (!ScrollTrigger) return () => {}\n\n  const navItems = navElement.querySelectorAll<HTMLElement>('[aa-scroll-target]')\n  if (navItems.length === 0) return () => {}\n\n  const triggers: ScrollTriggerInstance[] = []\n  navItems.forEach((navItem) => {\n    const targetSelector = navItem.getAttribute('aa-scroll-target')\n    if (!targetSelector) return\n    const section = document.querySelector(targetSelector)\n    if (!section) return\n\n    const setCurrent = (): void => {\n      navItems.forEach((item) => item.classList.remove('is-current'))\n      navItem.classList.add('is-current')\n    }\n    const clearCurrent = (): void => {\n      navItem.classList.remove('is-current')\n    }\n\n    triggers.push(\n      ScrollTrigger.create({\n        trigger: section,\n        start: '0% 50%',\n        end: '100% 50%',\n        invalidateOnRefresh: true,\n        onEnter: setCurrent,\n        onEnterBack: setCurrent,\n        onLeave: clearCurrent,\n        onLeaveBack: clearCurrent,\n      }),\n    )\n  })\n\n  return () => {\n    for (const t of triggers) {\n      try {\n        t.kill()\n      } catch {\n        // ignore\n      }\n    }\n  }\n}\n\n/**\n * 3c. Toggle a class on the nav element while a section with\n * `aa-nav-section=\"my-class\"` is in view.\n */\nfunction setupSectionClasses(ctx: FeatureContext, navElement: HTMLElement): () => void {\n  const ScrollTrigger = ctx.gsap.plugins.ScrollTrigger as ScrollTriggerLike | undefined\n  if (!ScrollTrigger) return () => {}\n\n  const sections = document.querySelectorAll<HTMLElement>('[aa-nav-section]')\n  if (sections.length === 0) return () => {}\n\n  const allClasses: string[] = []\n  sections.forEach((section) => {\n    const cls = section.getAttribute('aa-nav-section')\n    if (cls) allClasses.push(cls)\n  })\n\n  const triggers: ScrollTriggerInstance[] = []\n  sections.forEach((section) => {\n    const sectionClass = section.getAttribute('aa-nav-section')\n    if (!sectionClass) return\n\n    const start = section.getAttribute('aa-scroll-start') ?? 'top 0%'\n    const end = section.getAttribute('aa-scroll-end') ?? 'bottom 0%'\n\n    const setActive = (): void => {\n      for (const cls of allClasses) navElement.classList.remove(cls)\n      navElement.classList.add(sectionClass)\n    }\n    const clearActive = (): void => {\n      navElement.classList.remove(sectionClass)\n    }\n\n    triggers.push(\n      ScrollTrigger.create({\n        trigger: section,\n        start,\n        end,\n        invalidateOnRefresh: true,\n        onEnter: setActive,\n        onEnterBack: setActive,\n        onLeave: clearActive,\n        onLeaveBack: clearActive,\n      }),\n    )\n  })\n\n  return () => {\n    for (const t of triggers) {\n      try {\n        t.kill()\n      } catch {\n        // ignore\n      }\n    }\n    for (const cls of allClasses) navElement.classList.remove(cls)\n  }\n}\n\ninterface IndicatorConfig {\n  duration: number\n  ease: string\n  flipConfig: Record<string, unknown>\n}\n\nfunction readIndicatorConfig(indicator: HTMLElement): IndicatorConfig {\n  const duration = parseNum(indicator.getAttribute('aa-duration') ?? undefined, 0.4)\n  const ease = indicator.getAttribute('aa-ease') ?? 'power2.out'\n  return {\n    duration,\n    ease,\n    flipConfig: { duration, ease, absolute: true, simple: true, overwrite: 'auto' },\n  }\n}\n\nfunction getCurrentItem(navElement: HTMLElement, items: NodeListOf<HTMLElement>): HTMLElement {\n  const explicit = navElement.querySelector<HTMLElement>('[aa-scroll-target].is-current')\n  return explicit ?? items[0]\n}\n\n/**\n * 3d. Indicator that morphs (Flip.fit) to whichever nav link has `is-current`.\n * Updates on `is-current` class addition (MutationObserver) and on resize.\n */\nfunction setupCurrentIndicator(ctx: FeatureContext, navElement: HTMLElement): () => void {\n  const Flip = ctx.gsap.plugins.Flip as FlipLike | undefined\n  if (!Flip) return () => {}\n\n  const indicator = navElement.querySelector<HTMLElement>('[aa-nav-current-indicator]')\n  if (!indicator) return () => {}\n\n  const navItems = navElement.querySelectorAll<HTMLElement>('[aa-scroll-target]')\n  if (navItems.length === 0) return () => {}\n\n  const cfg = readIndicatorConfig(indicator)\n  let lastCurrentItem: HTMLElement | null = null\n\n  requestAnimationFrame(() => {\n    const item = getCurrentItem(navElement, navItems)\n    if (!item) return\n    lastCurrentItem = item\n    Flip.fit(indicator, item, { duration: 0, absolute: true, simple: true })\n    setTimeout(() => {\n      indicator.style.opacity = '1'\n    }, cfg.duration * 1000)\n  })\n\n  const observer = new MutationObserver((mutations) => {\n    for (const mutation of mutations) {\n      if (mutation.type !== 'attributes') continue\n      const target = mutation.target as HTMLElement\n      if (target.classList.contains('is-current')) {\n        lastCurrentItem = target\n        Flip.fit(indicator, target, cfg.flipConfig)\n        break\n      }\n    }\n  })\n  navItems.forEach((item) => {\n    observer.observe(item, { attributes: true, attributeFilter: ['class'] })\n  })\n\n  const offResize = ctx.onResize(() => {\n    if (lastCurrentItem) {\n      Flip.fit(indicator, lastCurrentItem, { duration: 0, absolute: true, simple: true })\n    }\n  }, 50)\n\n  return () => {\n    observer.disconnect()\n    offResize()\n  }\n}\n\n/**\n * 3e. Indicator that follows the hovered nav link, returning to the current\n * one when the pointer leaves the nav. Disabled on touch devices.\n */\nfunction setupHoverIndicator(ctx: FeatureContext, navElement: HTMLElement): () => void {\n  const Flip = ctx.gsap.plugins.Flip as FlipLike | undefined\n  if (!Flip) return () => {}\n\n  const isTouch =\n    typeof window !== 'undefined' &&\n    ('ontouchstart' in window || (navigator?.maxTouchPoints ?? 0) > 0)\n  if (isTouch) return () => {}\n\n  const indicator = navElement.querySelector<HTMLElement>('[aa-nav-hover-indicator]')\n  if (!indicator) return () => {}\n\n  const navItems = navElement.querySelectorAll<HTMLElement>('[aa-scroll-target]')\n  if (navItems.length === 0) return () => {}\n\n  const cfg = readIndicatorConfig(indicator)\n  let lastCurrentItem: HTMLElement | null = null\n  let isHovering = false\n\n  const animateTo = (target: HTMLElement, durationOverride?: number): void => {\n    if (durationOverride === 0) {\n      Flip.fit(indicator, target, { duration: 0, absolute: true, simple: true })\n    } else {\n      Flip.fit(indicator, target, cfg.flipConfig)\n    }\n  }\n\n  requestAnimationFrame(() => {\n    const item = getCurrentItem(navElement, navItems)\n    if (!item) return\n    lastCurrentItem = item\n    animateTo(item, 0)\n    setTimeout(() => {\n      indicator.style.opacity = '1'\n    }, cfg.duration * 1000)\n  })\n\n  const observer = new MutationObserver((mutations) => {\n    for (const mutation of mutations) {\n      if (mutation.type !== 'attributes') continue\n      const target = mutation.target as HTMLElement\n      if (target.classList.contains('is-current')) {\n        lastCurrentItem = target\n        if (!isHovering) animateTo(target)\n        break\n      }\n    }\n  })\n  navItems.forEach((item) => {\n    observer.observe(item, { attributes: true, attributeFilter: ['class'] })\n  })\n\n  const enterHandlers = new Map<HTMLElement, () => void>()\n  navItems.forEach((item) => {\n    const fn = (): void => {\n      isHovering = true\n      animateTo(item)\n    }\n    item.addEventListener('mouseenter', fn)\n    enterHandlers.set(item, fn)\n  })\n\n  const onNavLeave = (): void => {\n    isHovering = false\n    if (lastCurrentItem) animateTo(lastCurrentItem)\n  }\n  navElement.addEventListener('mouseleave', onNavLeave)\n\n  const offResize = ctx.onResize(() => {\n    if (lastCurrentItem) animateTo(lastCurrentItem, 0)\n  }, 50)\n\n  return () => {\n    observer.disconnect()\n    for (const [item, fn] of enterHandlers) item.removeEventListener('mouseenter', fn)\n    navElement.removeEventListener('mouseleave', onNavLeave)\n    offResize()\n  }\n}\n\nconst navFeature: FeatureModule = {\n  name: 'nav',\n  init(ctx: FeatureContext): () => void {\n    const navElements = ctx.elements.filter(\n      (el): el is HTMLElement => el instanceof HTMLElement && el.hasAttribute('aa-nav'),\n    )\n    if (navElements.length === 0) return () => {}\n\n    const disposers: Array<() => void> = []\n    for (const navElement of navElements) {\n      disposers.push(\n        setupHideAndChange(ctx, navElement),\n        setupCurrentLinkTracking(ctx, navElement),\n        setupSectionClasses(ctx, navElement),\n        setupCurrentIndicator(ctx, navElement),\n        setupHoverIndicator(ctx, navElement),\n      )\n    }\n\n    return () => {\n      for (const d of disposers) {\n        try {\n          d()\n        } catch (err) {\n          if (ctx.debug) console.error('[alrdy-animate] nav disposer threw', err)\n        }\n      }\n    }\n  },\n}\n\nexport default navFeature\n","/**\n * Watch an element's box width and run `onChange` when it changes to a non-zero\n * value. Built on ResizeObserver, so it fires for the causes a window 'resize'\n * listener misses:\n *\n *   - **reveal from hidden** (a modal opens, a tab activates, `display:none` →\n *     block): the box goes `0 → laid-out`. This is the one case that strands\n *     measure-at-init components — a slider whose widths were all `0` because it\n *     was inside a closed modal stays broken until the user resizes the window.\n *   - **content growth** (lazy images, late web fonts, responsive item widths)\n *     that resizes the box with no window resize.\n *\n * It also fires on viewport resize (the element's width tracks it), so a\n * consumer can drop its window 'resize' subscription and let this be the single\n * re-measure signal. Debounced; no-op fires (same width) and transitions *into*\n * hidden (`width === 0`) are dropped without calling `onChange`. Returns a\n * disposer. No-op where ResizeObserver is unavailable (SSR).\n */\nexport function observeSize(\n  element: Element,\n  onChange: () => void,\n  { debounce = 150 }: { debounce?: number } = {},\n): () => void {\n  if (typeof ResizeObserver === 'undefined') return () => {}\n  let lastWidth = element.getBoundingClientRect().width\n  let timer: ReturnType<typeof setTimeout> | undefined\n  const ro = new ResizeObserver(() => {\n    const width = element.getBoundingClientRect().width\n    if (width === lastWidth) return\n    lastWidth = width\n    if (width === 0) return\n    if (timer) clearTimeout(timer)\n    timer = setTimeout(onChange, debounce)\n  })\n  ro.observe(element)\n  return () => {\n    if (timer) clearTimeout(timer)\n    ro.disconnect()\n  }\n}\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport {\n  createProgressEntry,\n  createProgressGroup,\n  type ProgressEntry,\n} from '../../core/progress-bar'\nimport { attachHoverPauseListener, createViewportGate } from '../../core/viewport-gate'\nimport type { SliderLoop } from './horizontal-loop'\n\nexport interface AutoplayOptions {\n  /** Seconds between slide advances. */\n  interval: number\n  /** Slide-transition duration (used by the slider tween, not autoplay timing). */\n  duration: number\n  ease: string\n  hoverPause: boolean\n  /**\n   * How to advance one slide. Defaults to `slider.next(...)` (infinite wrap).\n   * The finite slider overrides this to rewind to the first slide instead of\n   * no-op'ing at the last.\n   */\n  advance?: () => void\n}\n\nexport interface AutoplayController {\n  start: () => void\n  stop: () => void\n  /** Update progress bars to reflect the given active slide index. */\n  syncProgress: (index: number) => void\n  /** Pause autoplay (without resetting progress). For external nav restarts. */\n  reset: () => void\n  /**\n   * Mark whether a drag/throw is in progress. When true, the hover\n   * mouseleave handler won't auto-start autoplay (the caller will restart\n   * once the throw completes on the correct landing slide).\n   */\n  setDragInProgress: (active: boolean) => void\n  destroy: () => void\n}\n\nexport function setupAutoplay(\n  gsapHandle: GsapHandle,\n  root: HTMLElement,\n  slider: SliderLoop,\n  options: AutoplayOptions,\n): AutoplayController {\n  const gsap = gsapHandle.gsap as unknown as Record<string, any>\n  const { interval, duration, ease, hoverPause } = options\n  const advance = options.advance ?? ((): void => void slider.next({ duration, ease }))\n\n  let autoplayCall:\n    | { kill: () => void; pause: () => void; resume: () => void; paused: () => boolean }\n    | null = null\n  let isPausedByHover = false\n  let dragInProgress = false\n\n  const progressEntries: ProgressEntry[] = []\n  for (const el of root.querySelectorAll<Element>('[aa-slider-progress]')) {\n    const entry = createProgressEntry(el, 'aa-slider-progress', ease, gsap.set)\n    if (entry) progressEntries.push(entry)\n  }\n  const progress = createProgressGroup(gsap, progressEntries)\n  // Every slide shares the same dwell (`interval`).\n  const syncProgress = (activeIndex: number): void => progress.play(activeIndex, () => interval)\n\n  const start = (): void => {\n    if (autoplayCall) return\n    const tick = (): void => {\n      advance()\n      gsap.delayedCall(duration / 2, () => {\n        syncProgress(slider.current())\n      })\n      autoplayCall = gsap.delayedCall(duration + interval, tick)\n    }\n    syncProgress(slider.current())\n    autoplayCall = gsap.delayedCall(interval, tick)\n  }\n\n  const stop = (): void => {\n    if (autoplayCall) {\n      autoplayCall.kill()\n      autoplayCall = null\n    }\n    progress.reset()\n    isPausedByHover = false\n  }\n\n  const reset = (): void => {\n    stop()\n  }\n\n  const pauseByHover = (): void => {\n    if (autoplayCall) {\n      autoplayCall.pause()\n      progress.pause()\n      isPausedByHover = true\n    }\n  }\n\n  const resumeFromHover = (): void => {\n    if (autoplayCall && isPausedByHover) {\n      autoplayCall.resume()\n      progress.resume()\n      isPausedByHover = false\n    }\n  }\n\n  const cleanups: Array<() => void> = []\n\n  // Hover pause is opt-in (autoplay-hover token) and only on non-touch devices.\n  if (hoverPause) {\n    cleanups.push(\n      attachHoverPauseListener({\n        root,\n        onEnter: () => {\n          if (autoplayCall && !autoplayCall.paused()) pauseByHover()\n        },\n        onLeave: () => {\n          if (isPausedByHover) resumeFromHover()\n          else if (!autoplayCall && !dragInProgress) start()\n        },\n      }),\n    )\n  }\n\n  // Pause autoplay when slider scrolls out of viewport.\n  const gateDispose = createViewportGate(gsapHandle, {\n    trigger: root,\n    onActive: start,\n    onIdle: stop,\n  })\n  if (gateDispose) cleanups.push(gateDispose)\n  else start() // No ScrollTrigger plugin → just start immediately.\n\n  const destroy = (): void => {\n    stop()\n    for (const fn of cleanups) fn()\n  }\n\n  const setDragInProgress = (active: boolean): void => {\n    dragInProgress = active\n  }\n\n  return { start, stop, syncProgress, reset, setDragInProgress, destroy }\n}\n","interface TouchGuardTarget {\n  enable: () => void\n  disable: () => void\n}\n\n/**\n * Disable a Draggable while the user is scrolling the page vertically, so a\n * vertical swipe over the slider scrolls the page instead of dragging the\n * track. Shared by both slider engines (horizontalLoop + finiteTrack).\n *\n * When a drag is suppressed for vertical scroll, `onStaticRelease` is invoked\n * on touchend: disabling Draggable mid-press strips its own pointerup listener,\n * so its `onRelease` never fires, and the caller's static-press path (e.g.\n * restart autoplay) would otherwise never run. Returns a cleanup function.\n */\nexport function attachTouchScrollGuard(\n  trigger: HTMLElement,\n  draggable: TouchGuardTarget,\n  onStaticRelease: () => void,\n): () => void {\n  let touchStartX = 0\n  let touchStartY = 0\n  let isDragInitialized = false\n  let disabledForScroll = false\n\n  const handleTouchStart = (e: TouchEvent): void => {\n    touchStartX = e.touches[0].clientX\n    touchStartY = e.touches[0].clientY\n  }\n  const handleTouchMove = (e: TouchEvent): void => {\n    if (isDragInitialized) return\n    const deltaX = Math.abs(e.touches[0].clientX - touchStartX)\n    const deltaY = Math.abs(e.touches[0].clientY - touchStartY)\n    if (deltaY > deltaX) {\n      draggable.disable()\n      disabledForScroll = true\n    } else {\n      isDragInitialized = true\n    }\n  }\n  const handleTouchEnd = (): void => {\n    if (!isDragInitialized) draggable.enable()\n    if (disabledForScroll) {\n      disabledForScroll = false\n      onStaticRelease()\n    }\n    isDragInitialized = false\n  }\n\n  trigger.addEventListener('touchstart', handleTouchStart, { passive: true })\n  trigger.addEventListener('touchmove', handleTouchMove, { passive: true })\n  trigger.addEventListener('touchend', handleTouchEnd)\n\n  return () => {\n    trigger.removeEventListener('touchstart', handleTouchStart)\n    trigger.removeEventListener('touchmove', handleTouchMove)\n    trigger.removeEventListener('touchend', handleTouchEnd)\n  }\n}\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport type {\n  DraggableInstance,\n  HorizontalLoopConfig,\n  SliderLoop,\n} from './horizontal-loop'\nimport { attachTouchScrollGuard } from './touch-guard'\n\ninterface DraggableConstructor {\n  create: (target: unknown, vars: Record<string, unknown>) => DraggableInstance[]\n}\n\n/**\n * Finite (non-looping) counterpart to horizontalLoop. Implements the same\n * SliderLoop interface but the track has hard start/end bounds: navigation\n * clamps at the first/last slide and Draggable is bounded (no wrap). Items are\n * translated collectively via a single `x` transform rather than the loop's\n * per-item xPercent wrap, so nav siblings are never moved and no track-wrapper\n * is assumed. The infinite engine's delicate math is intentionally not reused.\n */\nexport function finiteTrack(\n  gsapHandle: GsapHandle,\n  rawItems: ArrayLike<Element>,\n  config: HorizontalLoopConfig = {},\n): SliderLoop {\n  const gsap = gsapHandle.gsap as unknown as Record<string, any>\n  const Draggable = gsapHandle.plugins.Draggable as DraggableConstructor | undefined\n\n  const items: HTMLElement[] = (gsap.utils.toArray as (v: unknown) => HTMLElement[])(rawItems)\n  const length = items.length\n  const onChange = config.onChange\n  const center = config.center\n  // index.ts passes the per-slide transition duration as `speed` (horizontalLoop\n  // reads that field as pixels-per-second; finite uses it only as the fallback\n  // duration for a toIndex/next call that omits an explicit one — every real\n  // caller passes a duration, so this is just a defensive default).\n  const fallbackDuration = config.speed && config.speed > 0 ? config.speed : 0.5\n\n  // Items' parent is the overflow-clipping viewport (the convention the loop's\n  // center mode also relies on).\n  const container = items[0].parentNode as HTMLElement\n\n  const targets: number[] = []\n  let minX = 0\n  let maxX = 0\n  let curIndex = 0\n  let lastIndex = 0\n  let currentX = 0\n  let indexIsDirty = false\n  // True when the last populate() ran while the track was laid out at 0 width\n  // (slider hidden inside a closed modal / form-success). refresh() uses it to\n  // spot the reveal and re-seat onto the first slide.\n  let measuredHidden = false\n\n  const clamp = (min: number, max: number, v: number): number =>\n    v < min ? min : v > max ? max : v\n\n  const getPropX = (el: HTMLElement): number =>\n    parseFloat(String(gsap.getProperty(el, 'x', 'px'))) || 0\n\n  const getClosestIndex = (value: number): number => {\n    let closest = 1e10\n    let index = 0\n    for (let i = 0; i < length; i++) {\n      const d = Math.abs(targets[i] - value)\n      if (d < closest) {\n        closest = d\n        index = i\n      }\n    }\n    return index\n  }\n\n  // The x that seats slide `i`, clamped to the reachable range. Index detection\n  // uses the raw `targets`; positioning goes through this so a multi-up\n  // left-aligned track never scrolls past its last slide (matching drag bounds).\n  const xForIndex = (i: number): number =>\n    clamp(minX, maxX, targets[clamp(0, length - 1, i)])\n\n  const populate = (): void => {\n    const containerWidth = container.offsetWidth\n    measuredHidden = containerWidth === 0\n    const startLeft = items[0].offsetLeft\n    let contentWidth = 0\n    items.forEach((el, i) => {\n      const slideLeft = el.offsetLeft - startLeft\n      const width = el.offsetWidth\n      targets[i] = center ? containerWidth / 2 - (slideLeft + width / 2) : -slideLeft\n      // Inter-item gaps are already baked into offsetLeft, so the content's\n      // right edge is simply the last slide's left offset plus its width.\n      contentWidth = slideLeft + width\n    })\n    if (center) {\n      maxX = targets[0]\n      minX = targets[length - 1]\n    } else {\n      maxX = 0\n      minX = Math.min(0, containerWidth - contentWidth)\n    }\n  }\n\n  const applyX = (x: number): void => {\n    gsap.set(items, { x })\n    currentX = x\n  }\n\n  const fireChange = (index: number): void => {\n    if (index === lastIndex) return\n    lastIndex = index\n    if (onChange) onChange(items[index], index)\n  }\n\n  const tl = gsap.timeline({ paused: true }) as any\n\n  const closestIndex = (setCurrent?: boolean): number => {\n    const index = getClosestIndex(currentX)\n    if (setCurrent) {\n      curIndex = index\n      indexIsDirty = false\n    }\n    return index\n  }\n\n  const current = (): number => (indexIsDirty ? closestIndex(true) : curIndex)\n\n  let moveTween: { kill: () => void } | null = null\n\n  function toIndex(index: number, vars?: Record<string, unknown>): unknown {\n    const target = clamp(0, length - 1, Math.round(index))\n    const targetX = xForIndex(target)\n    curIndex = target\n    fireChange(target)\n    const duration = vars?.['duration'] as number | undefined\n    if (duration === 0) {\n      moveTween?.kill()\n      applyX(targetX)\n      return undefined\n    }\n    moveTween = gsap.to(items, {\n      x: targetX,\n      duration: duration ?? fallbackDuration,\n      ease: (vars?.['ease'] as string | undefined) ?? 'power2.out',\n      overwrite: true,\n      onUpdate: () => {\n        currentX = getPropX(items[0])\n      },\n      onComplete: () => {\n        currentX = targetX\n      },\n    })\n    return moveTween\n  }\n\n  let proxy: HTMLDivElement | undefined\n\n  gsap.set(items, { x: 0 })\n  populate()\n\n  tl.toIndex = toIndex\n  tl.closestIndex = closestIndex\n  tl.current = current\n  tl.next = (vars?: Record<string, unknown>) => toIndex(current() + 1, vars)\n  tl.previous = (vars?: Record<string, unknown>) => toIndex(current() - 1, vars)\n  tl.times = targets\n\n  const refresh = (): void => {\n    const wasHidden = measuredHidden\n    populate()\n    const drag = tl.draggable as DraggableInstance | undefined\n    if (drag) {\n      ;(drag as unknown as { applyBounds: (b: unknown) => void }).applyBounds({ minX, maxX })\n    }\n    if (wasHidden && !measuredHidden) {\n      // Reveal from hidden: the seated index was built on zero-width metrics.\n      // Reset to the first slide and fire onChange so counter/active-class move.\n      curIndex = 0\n      lastIndex = -1\n      indexIsDirty = false\n      applyX(xForIndex(0))\n      fireChange(0)\n    } else {\n      // A drag/throw leaves curIndex pointing at the pre-throw slide until the\n      // throw lands (indexIsDirty). Re-seating onto that stale index snaps the\n      // track back to where the throw *started* — visible on mobile when the\n      // address bar toggles and fires a resize during a vertical scroll that\n      // interrupted a throw. Seat onto the slide nearest the current position.\n      const seatIndex = indexIsDirty ? closestIndex(true) : curIndex\n      applyX(xForIndex(seatIndex))\n    }\n  }\n  tl.refresh = refresh\n\n  if (config.draggable && Draggable && typeof Draggable.create === 'function') {\n    proxy = document.createElement('div')\n    let draggable: DraggableInstance\n\n    draggable = Draggable.create(proxy, {\n      trigger: items[0].parentNode,\n      type: 'x',\n      bounds: { minX, maxX },\n      edgeResistance: 0.85,\n      inertia: true,\n      maxDuration: 1.5,\n      minDuration: 0.3,\n      onPressInit(this: DraggableInstance) {\n        // Stop any nav tween in flight; its onUpdate has kept currentX current.\n        moveTween?.kill()\n        // Re-measure geometry (layout may have shifted) but do NOT re-seat: a\n        // press mid-throw must hold the current position, not snap back to the\n        // slide the throw started from. refresh() re-seats, so we measure by hand.\n        populate()\n        ;(draggable as unknown as { applyBounds: (b: unknown) => void }).applyBounds({\n          minX,\n          maxX,\n        })\n        gsap.set(proxy, { x: currentX })\n        config.onDragStart?.()\n      },\n      onDrag(this: DraggableInstance) {\n        applyX(this.x)\n        fireChange(getClosestIndex(this.x))\n      },\n      onThrowUpdate(this: DraggableInstance) {\n        applyX(this.x)\n        fireChange(getClosestIndex(this.x))\n      },\n      snap(value: number): number {\n        return clamp(minX, maxX, targets[getClosestIndex(value)])\n      },\n      onRelease(this: DraggableInstance) {\n        const wasThrowing = !!this.isThrowing\n        closestIndex(true)\n        if (wasThrowing) indexIsDirty = true\n        config.onRelease?.(wasThrowing)\n      },\n      onThrowComplete() {\n        closestIndex(true)\n        fireChange(curIndex)\n        config.onThrowComplete?.(curIndex)\n      },\n    })[0]\n\n    tl.touchCleanup = attachTouchScrollGuard(\n      items[0].parentNode as HTMLElement,\n      draggable,\n      () => config.onRelease?.(false),\n    )\n\n    tl.draggable = draggable\n  }\n\n  // The movement tween lives on `items`, not as a child of the empty timeline,\n  // so the native kill() wouldn't stop it. Wrap kill to clean both up.\n  const nativeKill = tl.kill.bind(tl)\n  tl.kill = (): unknown => {\n    moveTween?.kill()\n    gsap.killTweensOf(items)\n    if (proxy) gsap.killTweensOf(proxy)\n    return nativeKill()\n  }\n\n  applyX(xForIndex(0))\n  curIndex = 0\n  lastIndex = 0\n  if (onChange) onChange(items[0], 0)\n\n  return tl as SliderLoop\n}\n","import type { GsapHandle, GsapTimeline } from '../../core/gsap-detect'\nimport { attachTouchScrollGuard } from './touch-guard'\n\n/**\n * Augmented timeline returned by horizontalLoop. Adds index navigation methods,\n * a Draggable handle, and an optional touchCleanup function.\n */\nexport interface SliderLoop extends GsapTimeline {\n  next: (vars?: Record<string, unknown>) => unknown\n  previous: (vars?: Record<string, unknown>) => unknown\n  toIndex: (index: number, vars?: Record<string, unknown>) => unknown\n  current: () => number\n  closestIndex: (setCurrent?: boolean) => number\n  refresh: (deep?: boolean) => void\n  times: number[]\n  draggable?: DraggableInstance\n  touchCleanup?: () => void\n}\n\nexport interface DraggableInstance {\n  kill: () => void\n  enable: () => void\n  disable: () => void\n  startX: number\n  startY: number\n  x: number\n  y: number\n  pointerX: number\n  pointerY: number\n  isThrowing: boolean\n  vars: Record<string, unknown>\n}\n\ninterface DraggableConstructor {\n  create: (target: unknown, vars: Record<string, unknown>) => DraggableInstance[]\n}\n\nexport interface HorizontalLoopConfig {\n  speed?: number\n  paused?: boolean\n  repeat?: number\n  draggable?: boolean\n  center?: boolean | string\n  reversed?: boolean\n  paddingRight?: number\n  snap?: number | false\n  onChange?: (item: Element, index: number) => void\n  /** Fires once on drag press-init, before the timeline pause. */\n  onDragStart?: () => void\n  /**\n   * Fires on every drag release. `isThrowing` is true when the release\n   * triggered an inertia throw — `onThrowComplete` will fire after that\n   * lands. False on a static press / click with no movement, in which case\n   * `onThrowComplete` will NOT fire and the caller is responsible for any\n   * post-press cleanup.\n   */\n  onRelease?: (isThrowing: boolean) => void\n  /** Fires after the inertia throw lands on a new slide boundary. */\n  onThrowComplete?: (index: number) => void\n}\n\n/**\n * Seamless horizontal looping timeline ported from v7's horizontalLoop helper\n * (originally https://gsap.com/docs/v3/HelperFunctions/helpers/seamlessLoop).\n * The math is delicate; this is a near-verbatim port — do not \"improve\" it.\n */\nexport function horizontalLoop(\n  gsapHandle: GsapHandle,\n  rawItems: ArrayLike<Element>,\n  config: HorizontalLoopConfig = {},\n): SliderLoop {\n  const gsap = gsapHandle.gsap as unknown as Record<string, any>\n  const Draggable = gsapHandle.plugins.Draggable as DraggableConstructor | undefined\n\n  const items: HTMLElement[] = (gsap.utils.toArray as (v: unknown) => HTMLElement[])(rawItems)\n  const onChange = config.onChange\n  let lastIndex = 0\n  const tl = gsap.timeline({\n    repeat: config.repeat,\n    onUpdate:\n      onChange &&\n      function (this: { closestIndex: () => number }) {\n        const i = (tl as unknown as { closestIndex: () => number }).closestIndex()\n        if (lastIndex !== i) {\n          lastIndex = i\n          onChange(items[i], i)\n        }\n      },\n    paused: config.paused,\n    defaults: { ease: 'none' },\n    onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100),\n  }) as any\n\n  const length = items.length\n  let startX = items[0].offsetLeft\n  const times: number[] = []\n  const widths: number[] = []\n  const spaceBefore: number[] = []\n  const xPercents: number[] = []\n  let curIndex = 0\n  let indexIsDirty = false\n  const center = config.center\n  const pixelsPerSecond = (config.speed || 1) * 100\n  const snap =\n    config.snap === false\n      ? (v: number) => v\n      : (gsap.utils.snap as (v: number) => (n: number) => number)(\n          (config.snap as number | undefined) ?? 1,\n        )\n  let timeOffset = 0\n  const container: HTMLElement =\n    center === true\n      ? (items[0].parentNode as HTMLElement)\n      : ((gsap.utils.toArray as (v: unknown) => HTMLElement[])(center)[0] ||\n        (items[0].parentNode as HTMLElement))\n  let totalWidth = 0\n  // True when the last populateWidths() ran while the track was laid out at 0\n  // width (the slider was hidden — display:none inside a closed modal /\n  // form-success). refresh() uses it to spot the reveal and reset the index.\n  let measuredHidden = false\n\n  const getTotalWidth = (): number =>\n    items[length - 1].offsetLeft +\n    (xPercents[length - 1] / 100) * widths[length - 1] -\n    startX +\n    items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], 'scaleX') +\n    (parseFloat(String(config.paddingRight ?? 0)) || 0)\n\n  const populateWidths = (): void => {\n    let b1 = container.getBoundingClientRect()\n    measuredHidden = b1.width === 0\n    let b2: DOMRect\n    items.forEach((el, i) => {\n      widths[i] = parseFloat(gsap.getProperty(el, 'width', 'px'))\n      xPercents[i] = snap(\n        (parseFloat(gsap.getProperty(el, 'x', 'px')) / widths[i]) * 100 +\n          (gsap.getProperty(el, 'xPercent') as number),\n      )\n      b2 = el.getBoundingClientRect()\n      spaceBefore[i] = b2.left - (i ? b1.right : b1.left)\n      b1 = b2\n    })\n    gsap.set(items, {\n      xPercent: (i: number) => xPercents[i],\n    })\n    totalWidth = getTotalWidth()\n  }\n\n  let timeWrap: (n: number) => number = (n) => n\n\n  const populateOffsets = (): void => {\n    timeOffset = center ? (tl.duration() * (container.offsetWidth / 2)) / totalWidth : 0\n    if (center) {\n      times.forEach((_t, i) => {\n        times[i] = timeWrap(\n          tl.labels['label' + i] + (tl.duration() * widths[i]) / 2 / totalWidth - timeOffset,\n        )\n      })\n    }\n  }\n\n  const getClosest = (values: number[], value: number, wrap: number): number => {\n    let i = values.length\n    let closest = 1e10\n    let index = 0\n    let d: number\n    while (i--) {\n      d = Math.abs(values[i] - value)\n      if (d > wrap / 2) d = wrap - d\n      if (d < closest) {\n        closest = d\n        index = i\n      }\n    }\n    return index\n  }\n\n  const populateTimeline = (): void => {\n    let item: HTMLElement\n    let curX: number\n    let distanceToStart: number\n    let distanceToLoop: number\n    tl.clear()\n    for (let i = 0; i < length; i++) {\n      item = items[i]\n      curX = (xPercents[i] / 100) * widths[i]\n      distanceToStart = item.offsetLeft + curX - startX + spaceBefore[0]\n      distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, 'scaleX')\n\n      tl.to(\n        item,\n        {\n          xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100),\n          duration: distanceToLoop / pixelsPerSecond,\n        },\n        0,\n      )\n        .fromTo(\n          item,\n          { xPercent: snap(((curX - distanceToLoop + totalWidth) / widths[i]) * 100) },\n          {\n            xPercent: xPercents[i],\n            duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond,\n            immediateRender: false,\n          },\n          distanceToLoop / pixelsPerSecond,\n        )\n        .add('label' + i, distanceToStart / pixelsPerSecond)\n\n      times[i] = distanceToStart / pixelsPerSecond\n    }\n    timeWrap = (gsap.utils.wrap as (a: number, b: number) => (n: number) => number)(\n      0,\n      tl.duration(),\n    )\n  }\n\n  const refresh = (deep?: boolean): void => {\n    const progress = tl.progress()\n    // Capture the live active slide before the playhead is reset below. During\n    // a throw curIndex is stale (still the pre-throw slide until the throw\n    // lands), so re-seating to it would snap the loop back to where the throw\n    // started — visible on mobile when the address bar toggles and fires a\n    // resize mid-throw. closestIndex() reads the current playhead here, before\n    // tl.progress(0) wipes it.\n    const activeIndex: number = indexIsDirty ? tl.closestIndex() : curIndex\n    // Was the slider built/last-measured while hidden? If so, curIndex and\n    // progress were seated from zero-width metrics (closestIndex lands on the\n    // last slide). populateWidths() below refreshes measuredHidden.\n    const wasHidden = measuredHidden\n    tl.progress(0, true)\n    startX = items[0].offsetLeft\n    populateWidths()\n    if (deep) populateTimeline()\n    populateOffsets()\n    if (deep && wasHidden && !measuredHidden) {\n      // Reveal (hidden → laid-out): the seated index is meaningless. Now that we\n      // own real geometry, reset to the first slide and fire onChange explicitly\n      // so the counter/active-class move to 0 (tl.time alone is a no-op when the\n      // playhead already sits at times[0], so onUpdate wouldn't fire).\n      curIndex = 0\n      tl.time(times[0], true)\n      lastIndex = 0\n      if (onChange) onChange(items[0], 0)\n    } else if (deep && tl.draggable) {\n      // A drag/throw leaves the playhead between slides; re-seat onto the slide\n      // nearest the live position (activeIndex), not the possibly-stale curIndex.\n      curIndex = activeIndex\n      indexIsDirty = false\n      tl.time(times[activeIndex], true)\n    } else {\n      // Non-draggable: preserve the running progress fraction so a resize that\n      // lands mid-transition doesn't snap the slide.\n      tl.progress(progress, true)\n    }\n  }\n\n  let proxy: HTMLDivElement | undefined\n\n  gsap.set(items, { x: 0 })\n  populateWidths()\n  populateTimeline()\n  populateOffsets()\n\n  function toIndex(index: number, vars?: Record<string, unknown>): unknown {\n    const v: Record<string, unknown> = vars ? { ...vars } : {}\n    if (Math.abs(index - curIndex) > length / 2) {\n      index += index > curIndex ? -length : length\n    }\n    const newIndex = (gsap.utils.wrap as (a: number, b: number, c: number) => number)(\n      0,\n      length,\n      index,\n    )\n    let time = times[newIndex]\n    if (time > tl.time() !== index > curIndex && index !== curIndex) {\n      time += tl.duration() * (index > curIndex ? 1 : -1)\n    }\n    if (time < 0 || time > tl.duration()) {\n      v.modifiers = { time: timeWrap }\n    }\n    curIndex = newIndex\n    v.overwrite = true\n    if (proxy) gsap.killTweensOf(proxy)\n    return v.duration === 0 ? tl.time(timeWrap(time)) : tl.tweenTo(time, v)\n  }\n\n  tl.toIndex = toIndex\n  tl.closestIndex = (setCurrent?: boolean) => {\n    const index = getClosest(times, tl.time(), tl.duration())\n    if (setCurrent) {\n      curIndex = index\n      indexIsDirty = false\n    }\n    return index\n  }\n  tl.current = () => (indexIsDirty ? tl.closestIndex(true) : curIndex)\n  tl.next = (vars?: Record<string, unknown>) => toIndex(tl.current() + 1, vars)\n  tl.previous = (vars?: Record<string, unknown>) => toIndex(tl.current() - 1, vars)\n  tl.times = times\n  tl.progress(1, true).progress(0, true) // pre-render for performance\n\n  if (config.reversed) {\n    tl.vars.onReverseComplete()\n    tl.reverse()\n  }\n\n  if (config.draggable && Draggable && typeof Draggable.create === 'function') {\n    proxy = document.createElement('div')\n    const wrap = (gsap.utils.wrap as (a: number, b: number) => (n: number) => number)(0, 1)\n    let ratio = 0\n    let startProgress = 0\n    let lastSnap = 0\n    let initChangeX = 0\n    let wasPlaying = false\n    let draggable: DraggableInstance\n\n    const align = (): void => {\n      tl.progress(wrap(startProgress + (draggable.startX - draggable.x) * ratio))\n    }\n    const syncIndex = (): number => tl.closestIndex(true)\n\n    draggable = Draggable.create(proxy, {\n      trigger: items[0].parentNode,\n      type: 'x',\n      onPressInit(this: DraggableInstance) {\n        const x = this.x\n        gsap.killTweensOf(tl)\n        wasPlaying = !tl.paused()\n        tl.pause()\n        startProgress = tl.progress()\n        refresh()\n        ratio = 1 / totalWidth\n        initChangeX = startProgress / -ratio - x\n        gsap.set(proxy, { x: startProgress / -ratio })\n        config.onDragStart?.()\n      },\n      onDrag: align,\n      onThrowUpdate: align,\n      overshootTolerance: 0,\n      inertia: true,\n      maxDuration: 1.5,\n      minDuration: 0.3,\n      snap(this: DraggableInstance, value: number): number {\n        if (Math.abs(startProgress / -ratio - this.x) < 10) {\n          return lastSnap + initChangeX\n        }\n        let time = -(value * ratio) * tl.duration()\n        const wrappedTime = timeWrap(time)\n        const snapTime = times[getClosest(times, wrappedTime, tl.duration())]\n        let dif = snapTime - wrappedTime\n        if (Math.abs(dif) > tl.duration() / 2) dif += dif < 0 ? tl.duration() : -tl.duration()\n        lastSnap = (time + dif) / tl.duration() / -ratio\n        return lastSnap\n      },\n      onRelease(this: DraggableInstance) {\n        syncIndex()\n        if (this.isThrowing) indexIsDirty = true\n        config.onRelease?.(!!this.isThrowing)\n      },\n      onThrowComplete: () => {\n        syncIndex()\n        if (wasPlaying) tl.play()\n        config.onThrowComplete?.(curIndex)\n      },\n    })[0]\n\n    tl.touchCleanup = attachTouchScrollGuard(\n      items[0].parentNode as HTMLElement,\n      draggable,\n      () => config.onRelease?.(false),\n    )\n\n    tl.draggable = draggable\n  }\n\n  tl.closestIndex(true)\n\n  // Move to center on load if configured (also runs a deep refresh so the\n  // first slide is positioned at the centered offset).\n  if (config.center) {\n    toIndex(0, { duration: 0 })\n    refresh(true)\n  }\n\n  lastIndex = curIndex\n  if (onChange) onChange(items[curIndex], curIndex)\n\n  // Expose refresh on the timeline so the resize bus can call it without\n  // capturing a closure here.\n  tl.refresh = refresh\n\n  return tl as SliderLoop\n}\n","export interface KeyboardHandlers {\n  next: () => void\n  previous: () => void\n  toIndex: (index: number) => void\n}\n\nconst HANDLED_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'Home', 'End'])\n\nexport function attachKeyboard(\n  root: HTMLElement,\n  total: number,\n  handlers: KeyboardHandlers,\n): () => void {\n  // Make the slider focusable if it isn't already; arrow keys only fire when\n  // the slider has focus (or focus is on a slide/thumb inside it).\n  const hadTabindex = root.hasAttribute('tabindex')\n  if (!hadTabindex) root.setAttribute('tabindex', '0')\n\n  const onKey = (e: KeyboardEvent): void => {\n    if (!HANDLED_KEYS.has(e.key)) return\n    // Ignore key events from form controls inside the slider — those have\n    // their own arrow-key semantics.\n    const target = e.target as HTMLElement | null\n    if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) return\n\n    e.preventDefault()\n    switch (e.key) {\n      case 'ArrowRight':\n        handlers.next()\n        break\n      case 'ArrowLeft':\n        handlers.previous()\n        break\n      case 'Home':\n        handlers.toIndex(0)\n        break\n      case 'End':\n        if (total > 0) handlers.toIndex(total - 1)\n        break\n    }\n  }\n\n  root.addEventListener('keydown', onKey)\n\n  return () => {\n    root.removeEventListener('keydown', onKey)\n    if (!hadTabindex) root.removeAttribute('tabindex')\n  }\n}\n","import { emitTrigger } from '../../core/trigger'\n\nlet sliderInstanceCounter = 0\n\nexport interface NavSetupResult {\n  /** onChange callback for the horizontalLoop config — wires up class/ARIA toggles + emits events. */\n  onChange: (item: Element, rawIndex: number) => void\n  /** Items the slider is operating on (already queried). */\n  items: HTMLElement[]\n  /** Total slide count. */\n  total: number\n  /** Wire up click handlers; needs the slider timeline + nav-restart callback. */\n  attachClickListeners: (handlers: NavClickHandlers) => () => void\n}\n\nexport interface NavClickHandlers {\n  next: () => void\n  previous: () => void\n  toIndex: (target: number) => void\n  current: () => number\n}\n\nexport interface NavOptions {\n  /** Finite (non-looping) slider: disable prev/next at the first/last slide. */\n  finite?: boolean\n}\n\nexport function setupNav(root: HTMLElement, opts: NavOptions = {}): NavSetupResult {\n  const items = Array.from(root.querySelectorAll<HTMLElement>('[aa-slider-item]'))\n  if (items.length === 0) {\n    return {\n      onChange: () => {},\n      items: [],\n      total: 0,\n      attachClickListeners: () => () => {},\n    }\n  }\n\n  const total = items.length\n  const sliderIdPrefix = root.id || `aa-slider-${sliderInstanceCounter++}`\n\n  const nextButton = root.querySelector<HTMLElement>('[aa-slider-next]')\n  const prevButton = root.querySelector<HTMLElement>('[aa-slider-prev]')\n  const currentEl = root.querySelector<HTMLElement>('[aa-slider-current]')\n  const totalEl = root.querySelector<HTMLElement>('[aa-slider-total]')\n\n  // Slide-specific buttons: include those nested inside the slider plus any\n  // external ones that target this slider's id via aa-slider-target.\n  const internalThumbs = Array.from(root.querySelectorAll<HTMLElement>('[aa-slider-button]'))\n  const externalThumbs = root.id\n    ? Array.from(\n        document.querySelectorAll<HTMLElement>(\n          `[aa-slider-button][aa-slider-target=\"${root.id}\"]`,\n        ),\n      )\n    : []\n  const thumbs = [...internalThumbs, ...externalThumbs]\n\n  // Root ARIA. Don't override an existing role attribute (Webflow CMS lists\n  // for instance). aa-slider-region role enables tablist semantics for thumbs.\n  if (!root.hasAttribute('role')) root.setAttribute('role', 'region')\n  root.setAttribute('aria-roledescription', 'carousel')\n  // A carousel region needs an accessible name. Supply a generic fallback when\n  // the author hasn't labelled it — otherwise screen readers announce an unnamed\n  // \"carousel\", and a bare role=\"region\" with no name is itself flagged.\n  if (!root.hasAttribute('aria-label') && !root.hasAttribute('aria-labelledby')) {\n    root.setAttribute('aria-label', 'Carousel')\n  }\n\n  // Per-slide ARIA + unique id.\n  items.forEach((slide, i) => {\n    const isCmsItem = slide.classList.contains('w-dyn-item')\n    if (!isCmsItem && !slide.hasAttribute('role')) slide.setAttribute('role', 'group')\n    slide.setAttribute('aria-roledescription', 'slide')\n    slide.setAttribute('aria-label', `Slide ${i + 1} of ${total}`)\n    if (!slide.id) slide.id = `${sliderIdPrefix}-slide-${i}`\n  })\n\n  if (nextButton) {\n    if (!nextButton.hasAttribute('aria-label')) nextButton.setAttribute('aria-label', 'Next slide')\n    if (!nextButton.hasAttribute('role')) nextButton.setAttribute('role', 'button')\n  }\n  if (prevButton) {\n    if (!prevButton.hasAttribute('aria-label'))\n      prevButton.setAttribute('aria-label', 'Previous slide')\n    if (!prevButton.hasAttribute('role')) prevButton.setAttribute('role', 'button')\n  }\n\n  if (thumbs.length > 0) {\n    thumbs.forEach((btn, i) => {\n      if (!btn.hasAttribute('aria-label')) btn.setAttribute('aria-label', `Go to slide ${i + 1}`)\n      // Plain labelled buttons rather than role=\"tab\": a tab requires a strict\n      // role=\"tablist\" parent, which can't be guaranteed when thumbs come from a\n      // Webflow CMS Collection List (each thumb is wrapped in a role=\"listitem\"\n      // .w-dyn-item inside a role=\"list\" .w-dyn-items). aria-current marks the\n      // active dot — see onChange below.\n      if (btn.tagName !== 'BUTTON' && !btn.hasAttribute('role')) btn.setAttribute('role', 'button')\n      btn.setAttribute('aria-controls', `${sliderIdPrefix}-slide-${i}`)\n    })\n  }\n\n  if (totalEl) {\n    totalEl.textContent = total < 10 ? `0${total}` : String(total)\n  }\n\n  const formatIndex = (n: number): string => (n < 10 ? `0${n}` : String(n))\n\n  const onChange = (_item: Element, rawIndex: number): void => {\n    const index = ((rawIndex % total) + total) % total\n\n    items.forEach((slide, i) => {\n      const wasActive = slide.classList.contains('is-active')\n      const isActive = i === index\n      slide.classList.toggle('is-active', isActive)\n      // Deliberately no aria-hidden toggle: slide width is CSS-driven, so the\n      // library can't know how many slides are actually on screen (multi-up,\n      // center mode, partial neighbours). Hiding all-but-active would hide\n      // visible content and risk aria-hidden-focus. The active slide is conveyed\n      // by the is-active class and the active dot's aria-current.\n      if (isActive && !wasActive) emitTrigger(slide, 'slide-active')\n      else if (!isActive && wasActive) emitTrigger(slide, 'slide-inactive')\n    })\n\n    if (thumbs.length > 0) {\n      thumbs.forEach((btn, i) => {\n        const isActive = i === index\n        btn.classList.toggle('is-active', isActive)\n        if (isActive) btn.setAttribute('aria-current', 'true')\n        else btn.removeAttribute('aria-current')\n      })\n    }\n\n    if (currentEl) {\n      currentEl.textContent = formatIndex(index + 1)\n    }\n\n    // Finite slider: reflect the hard bounds on the arrow buttons so authors\n    // can style the disabled state. The handlers still fire but the engine\n    // clamps, so this is purely an affordance.\n    if (opts.finite) {\n      if (prevButton) {\n        const disabled = index === 0\n        prevButton.classList.toggle('is-disabled', disabled)\n        prevButton.setAttribute('aria-disabled', String(disabled))\n      }\n      if (nextButton) {\n        const disabled = index === total - 1\n        nextButton.classList.toggle('is-disabled', disabled)\n        nextButton.setAttribute('aria-disabled', String(disabled))\n      }\n    }\n  }\n\n  const attachClickListeners = (handlers: NavClickHandlers): (() => void) => {\n    const cleanups: Array<() => void> = []\n    const add = (el: HTMLElement, evt: string, fn: EventListener): void => {\n      el.addEventListener(evt, fn)\n      cleanups.push(() => el.removeEventListener(evt, fn))\n    }\n\n    if (nextButton) add(nextButton, 'click', () => handlers.next())\n    if (prevButton) add(prevButton, 'click', () => handlers.previous())\n    thumbs.forEach((btn, i) => {\n      add(btn, 'click', () => {\n        if (i === handlers.current()) return\n        handlers.toIndex(i)\n      })\n    })\n\n    return () => {\n      for (const fn of cleanups) fn()\n    }\n  }\n\n  return { onChange, items, total, attachClickListeners }\n}\n","import { parseAutoplay } from '../../core/autoplay'\nimport { parseNum } from '../../core/parse'\nimport { observeSize } from '../../core/visibility'\nimport { bindRootFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport type { Config } from '../../core/settings'\nimport { setupAutoplay, type AutoplayController } from './autoplay'\nimport { finiteTrack } from './finite-track'\nimport { horizontalLoop, type SliderLoop } from './horizontal-loop'\nimport { attachKeyboard } from './keyboard'\nimport { setupNav } from './nav'\n\ninterface ParsedTokens {\n  isDraggable: boolean\n  isCenter: boolean\n  isFinite: boolean\n  isNone: boolean\n}\n\nfunction parseSliderValue(raw: string | undefined): ParsedTokens {\n  const tokens = (raw ?? '')\n    .trim()\n    .split(/\\s+/)\n    .filter(Boolean)\n  return {\n    isDraggable: tokens.includes('draggable'),\n    isCenter: tokens.includes('center'),\n    isFinite: tokens.includes('finite'),\n    isNone: tokens.includes('none'),\n  }\n}\n\nfunction setupOne(ctx: FeatureContext, root: HTMLElement, config: Config): (() => void) | undefined {\n  const tokens = parseSliderValue(config['aa-slider'])\n  if (tokens.isNone) return undefined\n\n  const items = root.querySelectorAll<HTMLElement>('[aa-slider-item]')\n  if (items.length === 0) return undefined\n\n  const opts = ctx.options\n  const duration = parseNum(config['aa-duration'], opts.duration)\n  const ease = config['aa-ease'] ?? opts.ease\n  const autoplay = parseAutoplay(\n    config['aa-autoplay'],\n    opts.autoplay,\n    'aa-autoplay' in config,\n  )\n\n  // Use the slider-item's parent (the track) for gap detection.\n  const firstItemParent = items[0].parentElement\n  const gap = firstItemParent\n    ? parseFloat(window.getComputedStyle(firstItemParent).columnGap || '0') || 0\n    : 0\n\n  const nav = setupNav(root, { finite: tokens.isFinite })\n\n  const gsap = ctx.gsap.gsap as unknown as Record<string, any>\n\n  // Wrap nav.onChange so its first invocation — the synchronous one fired by\n  // horizontalLoop during construction — is deferred by one tick. This lets\n  // appearance features inside slides (e.g. text-fade-up listening for\n  // event:slide-active) register their listeners before the initial event\n  // fires, regardless of feature init order. Subsequent calls (drag, autoplay,\n  // manual nav) run immediately so interaction stays snappy. Mirrors the\n  // pattern in tabs/index.ts where `openEntrySnap(initialEntry)` is wrapped\n  // in `gsap.delayedCall(0, ...)` for the same reason.\n  let initialOnChange = true\n  const handleChange = (item: Element, index: number): void => {\n    if (initialOnChange) {\n      initialOnChange = false\n      gsap.delayedCall(0, () => nav.onChange(item, index))\n      return\n    }\n    nav.onChange(item, index)\n  }\n\n  // Forward declare so the drag callbacks (which run via horizontalLoop) can\n  // reach the autoplay controller defined below.\n  let autoplayCtl: AutoplayController | null = null\n\n  // Restart after a manual nav (button click, keyboard, drag throw). With\n  // hover-pause we must NOT restart while the cursor is still over the slider\n  // — restarting here would skip the mouseenter pause hook (mouseenter only\n  // fires on entry, not when already inside) and the autoplay would cycle\n  // through hover, defeating hover-pause. The autoplay's own mouseleave\n  // handler picks up the restart when the cursor leaves. Without hover-pause\n  // there is no mouseleave handler at all, so restart unconditionally —\n  // otherwise clicking next while the cursor sits on the button leaves\n  // autoplay stopped forever.\n  const restartAutoplayAfterManualNav = (): void => {\n    if (!autoplayCtl) return\n    if (autoplay.hoverPause) {\n      const hovered = root.matches(':hover') && !window.matchMedia('(hover: none)').matches\n      if (!hovered) autoplayCtl.start()\n    } else {\n      autoplayCtl.start()\n    }\n  }\n\n  const buildSlider = tokens.isFinite ? finiteTrack : horizontalLoop\n  const slider: SliderLoop = buildSlider(ctx.gsap, items, {\n    speed: duration,\n    repeat: -1,\n    paused: true,\n    paddingRight: gap,\n    center: tokens.isCenter,\n    draggable: tokens.isDraggable,\n    onChange: handleChange,\n    onDragStart: () => {\n      autoplayCtl?.setDragInProgress(true)\n      autoplayCtl?.stop()\n    },\n    onRelease: (isThrowing) => {\n      // No throw means a static press / click with no drag movement —\n      // onThrowComplete will never fire, so we must clear the drag flag and\n      // attempt a restart here. With a real throw, defer to onThrowComplete\n      // which runs after the inertia tween lands on its snap target.\n      if (!isThrowing) {\n        autoplayCtl?.setDragInProgress(false)\n        restartAutoplayAfterManualNav()\n      }\n    },\n    onThrowComplete: () => {\n      // Throw landed on a snap target → safe to restart autoplay so the\n      // progress bar starts fresh on the correct active slide.\n      autoplayCtl?.setDragInProgress(false)\n      restartAutoplayAfterManualNav()\n    },\n  })\n\n  const cleanups: Array<() => void> = []\n\n  // Autoplay (optional). Hooks into ScrollTrigger viewport gating itself.\n  if (autoplay.enabled) {\n    // Finite sliders don't wrap, so next() no-ops at the last slide. Rewind to\n    // the first slide there so autoplay keeps cycling.\n    const advance = tokens.isFinite\n      ? (): void => {\n          if (slider.current() >= nav.total - 1) slider.toIndex(0, { duration, ease })\n          else slider.next({ duration, ease })\n        }\n      : undefined\n    autoplayCtl = setupAutoplay(ctx.gsap, root, slider, {\n      interval: autoplay.interval,\n      duration,\n      ease,\n      hoverPause: autoplay.hoverPause,\n      ...(advance ? { advance } : {}),\n    })\n    cleanups.push(() => autoplayCtl?.destroy())\n  }\n\n  const afterManualNav = (): void => {\n    if (autoplayCtl) gsap.delayedCall(0.1, restartAutoplayAfterManualNav)\n  }\n\n  const navHandlers = {\n    next: () => {\n      autoplayCtl?.stop()\n      slider.next({ duration, ease })\n      afterManualNav()\n    },\n    previous: () => {\n      autoplayCtl?.stop()\n      slider.previous({ duration, ease })\n      afterManualNav()\n    },\n    toIndex: (target: number) => {\n      autoplayCtl?.stop()\n      slider.toIndex(target, { duration, ease })\n      afterManualNav()\n    },\n    current: () => slider.current(),\n  }\n\n  cleanups.push(nav.attachClickListeners(navHandlers))\n\n  cleanups.push(\n    attachKeyboard(root, nav.total, {\n      next: navHandlers.next,\n      previous: navHandlers.previous,\n      toIndex: navHandlers.toIndex,\n    }),\n  )\n\n  // Re-measure the carousel. Two complementary signals — neither alone is a\n  // superset of the other:\n  //\n  //  - ctx.onResize (window resize): catches viewport changes that don't alter\n  //    the root's own width — a fixed-width root with vw-sized slides, or a\n  //    media query that re-lays-out the slides without resizing root.\n  //  - observeSize (ResizeObserver on root): catches the box going 0 → laid-out\n  //    when the slider is revealed (a display:none modal / form-success opens)\n  //    and content growth (late images) — neither fires a window resize, and\n  //    horizontalLoop measured every width as 0 while hidden, so the carousel\n  //    math stays dead until this fires.\n  //\n  // Both run a deep refresh; refresh() itself detects a reveal-from-hidden\n  // (degenerate zero-width build) and re-seats onto the first slide, so the\n  // callbacks are identical and a redundant double-refresh on a plain responsive\n  // resize is harmless (idempotent re-measure).\n  const remeasure = (): void => slider.refresh(true)\n  cleanups.push(ctx.onResize(remeasure, 150))\n  cleanups.push(observeSize(root, remeasure))\n\n  // Initial onChange (fired by horizontalLoop on construction) has already\n  // toggled is-active classes and emitted slide-active on the starting slide\n  // so descendant aa-trigger=\"event:slide-active\" animations play on first\n  // paint. No additional bootstrap call needed here.\n\n  return () => {\n    for (const fn of cleanups) fn()\n    slider.touchCleanup?.()\n    slider.draggable?.kill()\n    slider.kill()\n  }\n}\n\nconst sliderFeature: FeatureModule = {\n  name: 'slider',\n  init(ctx: FeatureContext): () => void {\n    bindRootFeature(ctx, 'aa-slider', setupOne)\n    return () => {}\n  },\n}\n\nexport default sliderFeature\n","import type { GsapHandle } from '../../core/gsap-detect'\nimport { hasAnimateAttribute } from '../../core/parse'\nimport { REVERSE_TIME_SCALE, emitTrigger } from '../../core/trigger'\nimport type { ModalEntry } from './state'\n\nconst BACKDROP_DURATION = 0.4\n\ntype GsapAny = Record<string, any>\n\nexport interface AnimationController {\n  applyInitialClosed: (entries: ModalEntry[], backdrop: HTMLElement | null) => void\n  open: (entry: ModalEntry, backdrop: HTMLElement | null, cardDuration: number) => void\n  /**\n   * Reverse the card + inner aa-animate timelines (via the modal-inactive\n   * event, which paired-reverses each subscriber at REVERSE_TIME_SCALE) and\n   * fade the backdrop out. Calls onComplete after the longest of the two has\n   * finished so the caller can hide the group / unlock scroll.\n   */\n  close: (\n    entry: ModalEntry,\n    backdrop: HTMLElement | null,\n    cardDuration: number,\n    onComplete?: () => void,\n  ) => void\n  cleanup: (entries: ModalEntry[], backdrop: HTMLElement | null) => void\n}\n\nfunction cardHasAnimate(card: HTMLElement): boolean {\n  return hasAnimateAttribute(card)\n}\n\nexport function createAnimationController(gsapHandle: GsapHandle): AnimationController {\n  const gsap = gsapHandle.gsap as unknown as GsapAny\n\n  const applyInitialClosed = (entries: ModalEntry[], backdrop: HTMLElement | null): void => {\n    for (const e of entries) {\n      // Hide via visibility, NOT display:none. SplitText's autoSplit uses a\n      // ResizeObserver that fires when an element transitions from 0×0 (which\n      // display:none produces) to laid-out — that resplit destroys the\n      // original char/word/line spans and orphans any tween bound to them.\n      // visibility:hidden keeps the cards measurable so SplitText completes\n      // its initial split once and the tween survives the open transition.\n      // pointer-events:none stops the hidden card from intercepting clicks.\n      e.card.style.visibility = 'hidden'\n      e.card.style.pointerEvents = 'none'\n      if (!cardHasAnimate(e.card)) {\n        gsap.set(e.card, { autoAlpha: 0 })\n      }\n    }\n    if (backdrop) gsap.set(backdrop, { autoAlpha: 0 })\n  }\n\n  const open = (entry: ModalEntry, backdrop: HTMLElement | null, cardDuration: number): void => {\n    // Reveal the card. The scroll/text/reveal feature owns opacity/transform\n    // of the card via its paused tween — we just unhide.\n    entry.card.style.visibility = 'visible'\n    entry.card.style.pointerEvents = ''\n    if (!cardHasAnimate(entry.card)) {\n      gsap.fromTo(\n        entry.card,\n        { autoAlpha: 0 },\n        { autoAlpha: 1, duration: cardDuration, ease: 'power2.out' },\n      )\n    }\n    if (backdrop) {\n      gsap.killTweensOf(backdrop)\n      gsap.fromTo(\n        backdrop,\n        { autoAlpha: 0 },\n        { autoAlpha: 1, duration: BACKDROP_DURATION, ease: 'power2.out' },\n      )\n    }\n    emitTrigger(entry.card, 'modal-active')\n  }\n\n  const close = (\n    entry: ModalEntry,\n    backdrop: HTMLElement | null,\n    cardDuration: number,\n    onComplete?: () => void,\n  ): void => {\n    emitTrigger(entry.card, 'modal-inactive')\n\n    // Wall-clock duration of the card's reverse — the trigger orchestrator\n    // multiplies reverse playback by REVERSE_TIME_SCALE, so the actual time\n    // the user sees is forward-duration / REVERSE_TIME_SCALE.\n    const cardWall = cardDuration / REVERSE_TIME_SCALE\n\n    if (!cardHasAnimate(entry.card)) {\n      gsap.killTweensOf(entry.card)\n      gsap.to(entry.card, { autoAlpha: 0, duration: cardWall, ease: 'power2.in' })\n    }\n\n    // Align the backdrop fade-out so it ends with the card disappearing.\n    const backdropDelay = Math.max(0, cardWall - BACKDROP_DURATION)\n    if (backdrop) {\n      gsap.killTweensOf(backdrop)\n      gsap.to(backdrop, {\n        autoAlpha: 0,\n        duration: BACKDROP_DURATION,\n        ease: 'power2.in',\n        delay: backdropDelay,\n      })\n    }\n\n    const totalWait = Math.max(cardWall, backdropDelay + BACKDROP_DURATION)\n    gsap.delayedCall(totalWait, () => {\n      entry.card.style.visibility = 'hidden'\n      entry.card.style.pointerEvents = 'none'\n      onComplete?.()\n    })\n  }\n\n  const cleanup = (entries: ModalEntry[], backdrop: HTMLElement | null): void => {\n    for (const e of entries) {\n      gsap.killTweensOf(e.card)\n      gsap.set(e.card, { clearProps: 'opacity,visibility' })\n      e.card.style.pointerEvents = ''\n    }\n    if (backdrop) {\n      gsap.killTweensOf(backdrop)\n      gsap.set(backdrop, { clearProps: 'opacity,visibility' })\n    }\n  }\n\n  return { applyInitialClosed, open, close, cleanup }\n}\n","const FOCUSABLE_SELECTOR = [\n  'a[href]',\n  'button:not([disabled])',\n  'input:not([disabled]):not([type=\"hidden\"])',\n  'select:not([disabled])',\n  'textarea:not([disabled])',\n  '[tabindex]:not([tabindex=\"-1\"])',\n].join(',')\n\nconst INPUT_SELECTOR = [\n  'input:not([disabled]):not([type=\"hidden\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"])',\n  'select:not([disabled])',\n  'textarea:not([disabled])',\n].join(',')\n\nfunction getFocusable(card: HTMLElement): HTMLElement[] {\n  return Array.from(card.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n    (el) => !el.hasAttribute('disabled') && el.offsetParent !== null,\n  )\n}\n\nfunction getFirstInput(card: HTMLElement): HTMLElement | null {\n  return (\n    Array.from(card.querySelectorAll<HTMLElement>(INPUT_SELECTOR)).find(\n      (el) => !el.hasAttribute('disabled') && el.offsetParent !== null,\n    ) ?? null\n  )\n}\n\n/**\n * Trap Tab/Shift+Tab focus inside the card. We listen on the card itself, not\n * document, so multiple modals/groups don't fight each other. Returns a\n * disposer that removes the listener.\n */\nexport function trapFocus(card: HTMLElement): () => void {\n  const onKeydown = (e: KeyboardEvent): void => {\n    if (e.key !== 'Tab') return\n    const focusable = getFocusable(card)\n    if (focusable.length === 0) {\n      e.preventDefault()\n      card.focus({ preventScroll: true })\n      return\n    }\n    const first = focusable[0]\n    const last = focusable[focusable.length - 1]\n    const active = document.activeElement as HTMLElement | null\n    if (e.shiftKey) {\n      if (active === first || !card.contains(active)) {\n        e.preventDefault()\n        last.focus()\n      }\n    } else {\n      if (active === last) {\n        e.preventDefault()\n        first.focus()\n      }\n    }\n  }\n  card.addEventListener('keydown', onKeydown)\n  return () => card.removeEventListener('keydown', onKeydown)\n}\n\n/**\n * Focus the first form input field (input/select/textarea) inside the card,\n * if one exists. We deliberately do NOT auto-focus buttons or links on open —\n * landing focus on a primary/close button invites accidental activation and\n * yanks the viewport. When there's no input to fill, anchor focus on the card\n * itself (tabindex=\"-1\") so the trap has somewhere to start — with\n * `preventScroll` so anchoring a fieldless modal never jumps the page (and\n * never fights a stopped Lenis), and with its focus outline suppressed in CSS\n * (`[aa-modal-name]:focus`) since the card is a non-interactive container, not\n * a control. The first input keeps its default focus so a below-the-fold field\n * in a tall scrollable card still scrolls natively into view.\n */\nexport function focusFirst(card: HTMLElement): void {\n  const firstInput = getFirstInput(card)\n  if (firstInput) {\n    firstInput.focus()\n    return\n  }\n  if (!card.hasAttribute('tabindex')) card.setAttribute('tabindex', '-1')\n  card.focus({ preventScroll: true })\n}\n\nconst ACCESSIBLE_NAME_MAX = 80\n\n/**\n * Derive the dialog's accessible name from the first text block inside the\n * card — the leading text-bearing element, usually the title line — rather\n * than assuming a heading (modals are outside the page's heading flow) or\n * scooping text across the whole card (which would run the title into the body\n * copy). Skips `aria-hidden` subtrees so split text isn't read from the hidden\n * animated element (the split runtime exposes an `.aa-sr-only` clone for AT).\n * Collapses whitespace and truncates at a word boundary so the name stays\n * short; falls back to the capped wrapper text when the modal has no inner\n * structure.\n */\nfunction deriveAccessibleName(card: HTMLElement): string | null {\n  if (typeof document === 'undefined') return null\n  const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, {\n    acceptNode(node): number {\n      if (!node.textContent || !node.textContent.trim()) return NodeFilter.FILTER_REJECT\n      for (let el = node.parentElement; el && el !== card; el = el.parentElement) {\n        if (el.getAttribute('aria-hidden') === 'true') return NodeFilter.FILTER_REJECT\n      }\n      return NodeFilter.FILTER_ACCEPT\n    },\n  })\n  const first = walker.nextNode()\n  if (!first) return null\n  const block = first.parentElement ?? card\n  const text = (block.textContent ?? '').replace(/\\s+/g, ' ').trim()\n  if (!text) return null\n  if (text.length <= ACCESSIBLE_NAME_MAX) return text\n  const slice = text.slice(0, ACCESSIBLE_NAME_MAX)\n  const cut = slice.lastIndexOf(' ')\n  return (cut > ACCESSIBLE_NAME_MAX / 2 ? slice.slice(0, cut) : slice).trim()\n}\n\n/**\n * Apply dialog semantics so assistive tech announces the card as a modal\n * dialog and treats the rest of the page as inert. Respects author-set `role`\n * / `aria-modal` / accessible name. When the author hasn't named the dialog,\n * derive a name from its leading text; if there's no text at all, warn (dev\n * only) — `aria-modal` without a name announces as an unlabelled \"dialog\".\n */\nexport function applyDialogSemantics(card: HTMLElement, debug: boolean): void {\n  if (!card.hasAttribute('role')) card.setAttribute('role', 'dialog')\n  if (!card.hasAttribute('aria-modal')) card.setAttribute('aria-modal', 'true')\n\n  if (!card.hasAttribute('aria-label') && !card.hasAttribute('aria-labelledby')) {\n    const name = deriveAccessibleName(card)\n    if (name) {\n      card.setAttribute('aria-label', name)\n    } else if (debug) {\n      console.warn(\n        '[alrdy-animate] modal has no text to derive an accessible name from — add an `aria-label` to the [aa-modal-name] element so screen readers can announce the dialog.',\n      )\n    }\n  }\n}\n\n/**\n * Mark the controls that open these modals with `aria-haspopup=\"dialog\"` so\n * assistive tech announces that activating them opens a dialog. Triggers are\n * click-delegated and may live anywhere in the document, so match by name.\n */\nexport function markDialogTriggers(names: Set<string>): void {\n  if (typeof document === 'undefined') return\n  for (const trigger of document.querySelectorAll<HTMLElement>('[aa-modal-target]')) {\n    const name = trigger.getAttribute('aa-modal-target')\n    if (name && names.has(name) && !trigger.hasAttribute('aria-haspopup')) {\n      trigger.setAttribute('aria-haspopup', 'dialog')\n    }\n  }\n}\n\n/**\n * Document-level Escape listener. Returns a disposer.\n */\nexport function attachEsc(onEsc: () => void): () => void {\n  const onKeydown = (e: KeyboardEvent): void => {\n    if (e.key === 'Escape') onEsc()\n  }\n  document.addEventListener('keydown', onKeydown)\n  return () => document.removeEventListener('keydown', onKeydown)\n}\n","/**\n * Reference-counted scroll lock. Two simultaneously-open modals (e.g. one in\n * each of two separate groups, however unusual) only release the lock when\n * both have closed. Lenis is preferred when present so its momentum and\n * data-lenis-prevent honoring keep working; otherwise we fall back to a body\n * class that pins overflow.\n */\n\nconst LOCK_CLASS = 'aa-modal-locked'\nlet lockCount = 0\n\nexport function lockBodyScroll(): void {\n  lockCount += 1\n  if (lockCount > 1) return\n  if (typeof window !== 'undefined' && window.lenis) {\n    try {\n      window.lenis.stop()\n    } catch {\n      // ignore — fallback to body class below\n    }\n  }\n  if (typeof document !== 'undefined') {\n    document.body.classList.add(LOCK_CLASS)\n  }\n}\n\nexport function unlockBodyScroll(): void {\n  if (lockCount === 0) return\n  lockCount -= 1\n  if (lockCount > 0) return\n  if (typeof window !== 'undefined' && window.lenis) {\n    try {\n      window.lenis.start()\n    } catch {\n      // ignore\n    }\n  }\n  if (typeof document !== 'undefined') {\n    document.body.classList.remove(LOCK_CLASS)\n  }\n}\n\nexport function resetScrollLock(): void {\n  if (lockCount === 0) return\n  lockCount = 0\n  if (typeof window !== 'undefined' && window.lenis) {\n    try {\n      window.lenis.start()\n    } catch {\n      // ignore\n    }\n  }\n  if (typeof document !== 'undefined') {\n    document.body.classList.remove(LOCK_CLASS)\n  }\n}\n","import { MODAL_STATUS_ATTR } from '../../core/trigger'\n\nexport { MODAL_STATUS_ATTR }\nexport const MODAL_GROUP_STATUS_ATTR = 'aa-modal-group-status'\n\nexport interface ModalEntry {\n  name: string\n  card: HTMLElement\n}\n\nexport interface ModalState {\n  group: HTMLElement\n  entries: ModalEntry[]\n  byName: Map<string, ModalEntry>\n  backdrop: HTMLElement | null\n  isActive: (entry: ModalEntry) => boolean\n  setStatus: (entry: ModalEntry, status: 'active' | 'not-active') => void\n  setGroupStatus: (status: 'active' | 'not-active') => void\n  activeEntry: () => ModalEntry | null\n}\n\nexport function createModalState(group: HTMLElement): ModalState {\n  const cards = Array.from(group.querySelectorAll<HTMLElement>('[aa-modal-name]'))\n  const entries: ModalEntry[] = []\n  const byName = new Map<string, ModalEntry>()\n  for (const card of cards) {\n    const name = card.getAttribute('aa-modal-name')\n    if (!name) continue\n    const entry: ModalEntry = { name, card }\n    entries.push(entry)\n    byName.set(name, entry)\n  }\n\n  // First [aa-modal-backdrop] inside the group; backdrop is optional.\n  const backdrop = group.querySelector<HTMLElement>('[aa-modal-backdrop]')\n\n  const isActive = (entry: ModalEntry): boolean =>\n    entry.card.getAttribute(MODAL_STATUS_ATTR) === 'active'\n\n  const setStatus = (entry: ModalEntry, status: 'active' | 'not-active'): void => {\n    entry.card.setAttribute(MODAL_STATUS_ATTR, status)\n  }\n\n  const setGroupStatus = (status: 'active' | 'not-active'): void => {\n    group.setAttribute(MODAL_GROUP_STATUS_ATTR, status)\n    // Drive the group's own visibility inline so users don't need custom CSS\n    // keyed on the status attribute. visibility (not display) keeps the cards\n    // measurable for SplitText; a child card's own visibility:visible on open\n    // overrides this hidden parent, so the active card still shows.\n    group.style.visibility = status === 'active' ? 'visible' : 'hidden'\n  }\n\n  const activeEntry = (): ModalEntry | null => entries.find(isActive) ?? null\n\n  return { group, entries, byName, backdrop, isActive, setStatus, setGroupStatus, activeEntry }\n}\n","import { bindRootFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport type { Config } from '../../core/settings'\nimport { createAnimationController } from './animation'\nimport {\n  applyDialogSemantics,\n  attachEsc,\n  focusFirst,\n  markDialogTriggers,\n  trapFocus,\n} from './a11y'\nimport { lockBodyScroll, resetScrollLock, unlockBodyScroll } from './scroll-lock'\nimport {\n  MODAL_GROUP_STATUS_ATTR,\n  MODAL_STATUS_ATTR,\n  createModalState,\n  type ModalEntry,\n  type ModalState,\n} from './state'\n\nfunction parseDuration(config: Config, fallback: number): number {\n  const c = config['aa-duration']\n  if (c === undefined) return fallback\n  const n = parseFloat(c)\n  return Number.isFinite(n) ? n : fallback\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  group: HTMLElement,\n  config: Config,\n): (() => void) | undefined {\n  const state = createModalState(group)\n  if (state.entries.length === 0) return undefined\n\n  // Portal to <body>. A modal is fixed-position chrome, but a `transform` /\n  // `filter` / `contain: paint` on any ancestor turns its `position: fixed`\n  // into `position: absolute` relative to that ancestor, which also clamps\n  // its z-index to that ancestor's stacking context. Moving the group to\n  // body sidesteps both — z-index now competes against page-level chrome\n  // directly. Skip if already there or running in a non-DOM environment.\n  if (typeof document !== 'undefined' && group.parentElement !== document.body) {\n    document.body.appendChild(group)\n  }\n\n  const opts = ctx.options\n  const groupDuration = parseDuration(config, opts.duration)\n  const animation = createAnimationController(ctx.gsap)\n  const gsap = ctx.gsap.gsap as unknown as Record<string, any>\n  const cleanups: Array<() => void> = []\n\n  // Per-card duration: prefer the card's own aa-duration, else group, else init default.\n  const durationFor = (entry: ModalEntry): number => {\n    const v = entry.card.getAttribute('aa-duration')\n    if (v) {\n      const n = parseFloat(v)\n      if (Number.isFinite(n)) return n\n    }\n    return groupDuration\n  }\n\n  state.setGroupStatus('not-active')\n  for (const entry of state.entries) state.setStatus(entry, 'not-active')\n  animation.applyInitialClosed(state.entries, state.backdrop)\n\n  // Dialog semantics: announce each card as a modal dialog and mark its\n  // triggers. Static (set once); closed cards are visibility:hidden so they\n  // stay out of the a11y tree until opened.\n  const debug = ctx.options.debug ?? false\n  for (const entry of state.entries) applyDialogSemantics(entry.card, debug)\n  markDialogTriggers(new Set(state.entries.map((e) => e.name)))\n\n  let detachTrap: (() => void) | null = null\n  let detachEsc: (() => void) | null = null\n  let pendingOpenFocus: { kill: () => void } | null = null\n\n  const closeEntry = (entry: ModalEntry): void => {\n    if (!state.isActive(entry)) return\n    detachTrap?.()\n    detachTrap = null\n    detachEsc?.()\n    detachEsc = null\n    pendingOpenFocus?.kill()\n    pendingOpenFocus = null\n\n    const cardDuration = durationFor(entry)\n    animation.close(entry, state.backdrop, cardDuration, () => {\n      state.setStatus(entry, 'not-active')\n      if (!state.activeEntry()) state.setGroupStatus('not-active')\n      unlockBodyScroll()\n    })\n  }\n\n  const openEntry = (entry: ModalEntry): void => {\n    if (state.isActive(entry)) return\n\n    // If another modal in this group is already open, close it first. We\n    // don't await it — the close + open animations overlap, which feels\n    // snappier than a sequential handoff.\n    const prev = state.activeEntry()\n    if (prev && prev !== entry) closeEntry(prev)\n\n    state.setGroupStatus('active')\n    state.setStatus(entry, 'active')\n    lockBodyScroll()\n    const cardDuration = durationFor(entry)\n    animation.open(entry, state.backdrop, cardDuration)\n\n    detachTrap = trapFocus(entry.card)\n    detachEsc = attachEsc(() => closeEntry(entry))\n\n    pendingOpenFocus?.kill()\n    pendingOpenFocus = gsap.delayedCall(cardDuration, () => {\n      focusFirst(entry.card)\n      pendingOpenFocus = null\n    })\n  }\n\n  // Document-level click delegation: trigger buttons can live anywhere in the\n  // page, not necessarily inside the group.\n  const onDocClick = (e: Event): void => {\n    const target = e.target as Element | null\n    if (!target) return\n    const trigger = target.closest<HTMLElement>('[aa-modal-target]')\n    if (!trigger) return\n    const name = trigger.getAttribute('aa-modal-target')\n    if (!name) return\n    const entry = state.byName.get(name)\n    if (!entry) return\n    e.preventDefault()\n    openEntry(entry)\n  }\n  document.addEventListener('click', onDocClick)\n  cleanups.push(() => document.removeEventListener('click', onDocClick))\n\n  // Group-scoped click delegation for close affordances (close buttons,\n  // backdrop). Handled separately so [aa-modal-close] outside the group is\n  // never interpreted as a close (avoids surprising cross-group behavior).\n  const onGroupClick = (e: Event): void => {\n    const target = e.target as Element | null\n    if (!target) return\n    const closer = target.closest<HTMLElement>('[aa-modal-close]')\n    if (!closer || !group.contains(closer)) return\n    const active = state.activeEntry()\n    if (!active) return\n    e.preventDefault()\n    closeEntry(active)\n  }\n  group.addEventListener('click', onGroupClick)\n  cleanups.push(() => group.removeEventListener('click', onGroupClick))\n\n  return () => {\n    for (const fn of cleanups) fn()\n    detachTrap?.()\n    detachEsc?.()\n    pendingOpenFocus?.kill()\n    if (state.activeEntry()) {\n      // Mid-open destroy: drop the lock count and let the body resume.\n      unlockBodyScroll()\n    }\n    animation.cleanup(state.entries, state.backdrop)\n    state.group.removeAttribute(MODAL_GROUP_STATUS_ATTR)\n    state.group.style.removeProperty('visibility')\n    for (const entry of state.entries) entry.card.removeAttribute(MODAL_STATUS_ATTR)\n  }\n}\n\nconst modalFeature: FeatureModule = {\n  name: 'modal',\n  init(ctx: FeatureContext): () => void {\n    bindRootFeature(ctx, 'aa-modal-group', setupOne)\n    return () => {\n      // Belt-and-suspenders in case a setupOne died without running its own\n      // cleanup (e.g. ResponsiveController revertAll already torched it).\n      resetScrollLock()\n    }\n  },\n}\n\nexport default modalFeature\n\n// Suppress the \"imported but never used\" warning for state types when the\n// barrel is consumed externally — re-export them as a type-only surface.\nexport type { ModalEntry, ModalState }\n","export type Edge = 'top' | 'bottom' | 'left' | 'right'\n\nexport type DirectionMode =\n  | 'all'\n  | 'vertical'\n  | 'horizontal'\n  | Edge\n\nconst VALID_MODES: ReadonlySet<string> = new Set([\n  'all',\n  'vertical',\n  'horizontal',\n  'top',\n  'bottom',\n  'left',\n  'right',\n])\n\nexport function parseDirectionMode(tokens: Iterable<string>): DirectionMode {\n  for (const t of tokens) {\n    if (VALID_MODES.has(t)) return t as DirectionMode\n  }\n  return 'all'\n}\n\nexport function defaultEdge(mode: DirectionMode): Edge {\n  if (mode === 'all' || mode === 'vertical') return 'bottom'\n  if (mode === 'horizontal') return 'left'\n  return mode\n}\n\nexport function detectEdge(event: MouseEvent, el: Element, mode: DirectionMode): Edge {\n  if (mode === 'top' || mode === 'bottom' || mode === 'left' || mode === 'right') return mode\n\n  const rect = el.getBoundingClientRect()\n  const x = event.clientX - rect.left\n  const y = event.clientY - rect.top\n  const w = rect.width\n  const h = rect.height\n\n  if (mode === 'vertical') return y < h / 2 ? 'top' : 'bottom'\n  if (mode === 'horizontal') return x < w / 2 ? 'left' : 'right'\n\n  // 'all' — closest edge to the cursor (Osmo-style 4-direction).\n  let edge: Edge = 'top'\n  let min = y\n  if (h - y < min) {\n    edge = 'bottom'\n    min = h - y\n  }\n  if (x < min) {\n    edge = 'left'\n    min = x\n  }\n  if (w - x < min) {\n    edge = 'right'\n  }\n  return edge\n}\n","/**\n * Hover hosts need `position: relative` + `overflow: hidden` so the injected\n * background/curve sits inside the element's box and is clipped to it, and\n * `isolation: isolate` so the injected element's `z-index: -1` resolves\n * inside the host's stacking context — placing it behind the host's own\n * content without falling through to the page background. We only touch\n * styles the host doesn't already provide, and remember what we set so\n * `restoreHost()` can put it back exactly on dispose.\n */\nexport interface HostRestore {\n  position?: string\n  overflow?: string\n  isolation?: string\n}\n\nexport function prepareHost(host: HTMLElement): HostRestore {\n  const restore: HostRestore = {}\n  const computed = getComputedStyle(host)\n\n  if (computed.position === 'static') {\n    restore.position = host.style.position\n    host.style.position = 'relative'\n  }\n  if (computed.overflow !== 'hidden' && computed.overflow !== 'clip') {\n    restore.overflow = host.style.overflow\n    host.style.overflow = 'hidden'\n  }\n  if (computed.isolation === 'auto') {\n    restore.isolation = host.style.isolation\n    host.style.isolation = 'isolate'\n  }\n  return restore\n}\n\nexport function restoreHost(host: HTMLElement, restore: HostRestore): void {\n  if (restore.position !== undefined) host.style.position = restore.position\n  if (restore.overflow !== undefined) host.style.overflow = restore.overflow\n  if (restore.isolation !== undefined) host.style.isolation = restore.isolation\n}\n\n/**\n * Like `prepareHost` but only ensures a positioning context, never touches\n * overflow. Also forces `isolation: isolate` so the host owns its stacking\n * context — letting the injected underline bar use `z-index: -1` to paint\n * behind the host's own text without falling through to the page background.\n * Used by effects that inject absolutely-positioned children but must coexist\n * with the author's own overflow value (e.g. underline bars inside hosts that\n * may already use overflow for other reasons).\n */\nexport function ensurePositioned(host: HTMLElement): HostRestore {\n  const restore: HostRestore = {}\n  const computed = getComputedStyle(host)\n  if (computed.position === 'static') {\n    restore.position = host.style.position\n    host.style.position = 'relative'\n  }\n  if (computed.isolation === 'auto') {\n    restore.isolation = host.style.isolation\n    host.style.isolation = 'isolate'\n  }\n  return restore\n}\n","import type { GsapHandle, GsapTimeline, GsapTween } from '../../core/gsap-detect'\nimport type { StaggerValue } from '../../core/stagger'\nimport { applySplit, type SplitMode } from '../../split/runtime'\nimport { defaultEdge, detectEdge, type DirectionMode, type Edge } from './direction'\nimport { ensurePositioned, prepareHost, restoreHost } from './host'\n\n// ===========================================================================\n// Block effect — solid panel sliding in from the entering edge\n// ===========================================================================\n\nconst BLOCK_TRANSFORM: Record<Edge, { x: number; y: number }> = {\n  top: { x: 0, y: -100 },\n  bottom: { x: 0, y: 100 },\n  left: { x: -100, y: 0 },\n  right: { x: 100, y: 0 },\n}\n\nexport interface BlockSettings {\n  duration: number\n  delay: number\n  ease: string\n  color: string\n  mode: DirectionMode\n}\n\nexport function setupBlockHover(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: BlockSettings,\n): () => void {\n  const restore = prepareHost(host)\n\n  const bg = document.createElement('span')\n  bg.setAttribute('aa-hover-bg', 'block')\n  bg.setAttribute('aria-hidden', 'true')\n  // Layout (position/inset/z-index/etc.) comes from the companion CSS rule\n  // on `[aa-hover-bg]`. Only the runtime-driven fill is set inline.\n  bg.style.background = settings.color\n  // Append rather than insert-first — `z-index: -1` (set by the CSS rule)\n  // combined with the host's `isolation: isolate` (set by prepareHost)\n  // puts the bg behind the host's other content regardless of DOM order,\n  // so we don't need the first-child trick anymore. Absolutely-positioned\n  // children don't consume grid/flex slots, so layout stays unaffected.\n  host.appendChild(bg)\n\n  const start = BLOCK_TRANSFORM[defaultEdge(settings.mode)]\n  gsap.gsap.set(bg, { xPercent: start.x, yPercent: start.y })\n\n  let active: GsapTween | null = null\n\n  // Edge detection runs against the trigger's rect, not the host's: when\n  // trigger !== host (composite buttons), the mouseenter fires from somewhere\n  // on the wrapper that may sit entirely outside the host's box — measuring\n  // against the host would produce negative-axis nonsense and pick the wrong\n  // edge. The block/curve still paints on the host; only the \"from\" edge is\n  // resolved relative to the composite hit region the author intends.\n  const onEnter = (event: MouseEvent): void => {\n    const t = BLOCK_TRANSFORM[detectEdge(event, trigger, settings.mode)]\n    active?.kill()\n    active = gsap.gsap.fromTo(\n      bg,\n      { xPercent: t.x, yPercent: t.y },\n      {\n        xPercent: 0,\n        yPercent: 0,\n        duration: settings.duration,\n        ease: settings.ease,\n        delay: settings.delay,\n        overwrite: true,\n      },\n    )\n  }\n\n  const onLeave = (event: MouseEvent): void => {\n    const t = BLOCK_TRANSFORM[detectEdge(event, trigger, settings.mode)]\n    active?.kill()\n    active = gsap.gsap.to(bg, {\n      xPercent: t.x,\n      yPercent: t.y,\n      duration: settings.duration,\n      ease: settings.ease,\n      overwrite: true,\n    })\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n  trigger.addEventListener('mouseleave', onLeave)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    trigger.removeEventListener('mouseleave', onLeave)\n    active?.kill()\n    bg.remove()\n    restoreHost(host, restore)\n  }\n}\n\n// ===========================================================================\n// Curve effect — SVG path with a sinusoidal scoop entering from an edge\n// ===========================================================================\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/**\n * Per-edge entry paths. Both `start` (degenerate, pinned to the entry edge,\n * zero-area) and `end` (covered, with a slight curve overshoot past the\n * opposite edge — clipped by the host's overflow:hidden, but it gives the\n * settle a bit of organic give) share the same `M L Q L L z` structure so\n * AttrPlugin's token-by-token interpolation works for the same-edge enter\n * tween. Cross-axis is never an issue here because `onEnter` uses fromTo\n * with an explicit start state, never reading the path's current `d`.\n */\nconst CURVE_FROM_PATHS: Record<Edge, { start: string; end: string }> = {\n  top: {\n    start: 'M 0 100 L 0 0 Q 50 0 100 0 L 100 0 L 0 0 z',\n    end: 'M 0 100 L 0 100 Q 50 125 100 100 L 100 0 L 0 0 z',\n  },\n  bottom: {\n    start: 'M 0 0 L 0 100 Q 50 100 100 100 L 100 100 L 0 100 z',\n    end: 'M 0 0 L 0 0 Q 50 -25 100 0 L 100 100 L 0 100 z',\n  },\n  left: {\n    start: 'M 0 0 L 0 0 Q 0 50 0 100 L 0 100 L 0 0 z',\n    end: 'M 0 0 L 100 0 Q 110 50 100 100 L 0 100 L 0 0 z',\n  },\n  right: {\n    start: 'M 100 0 L 100 0 Q 100 50 100 100 L 100 100 L 100 0 z',\n    end: 'M 100 0 L 0 0 Q -10 50 0 100 L 100 100 L 100 0 z',\n  },\n}\n\n/**\n * Compute the leave-path for a given edge and progress (0 → 1).\n *\n * Single-phase: the shape's receding edge moves linearly across the host\n * from \"fully covered\" to \"retracted to leave edge\", while the curve's\n * scoop magnitude peaks sinusoidally at the midpoint and returns to zero\n * at the endpoints — so the inside arc grows and disappears alongside the\n * retract instead of being two distinct stages.\n *\n * We compute `d` from a single scalar progress, so the leave tween only\n * interpolates one number (state.p) — AttrPlugin is bypassed entirely. That\n * matters because AttrPlugin's token-by-token interpolation garbles when\n * many of the path's twelve numbers change at once, which is what happens on\n * a cross-axis leave (enter from top, leave toward right) if you naively\n * tween between two whole `d` strings.\n */\nfunction computeLeavePath(edge: Edge, progress: number): string {\n  const p = Math.max(0, Math.min(1, progress))\n  const scoop = 35 * Math.sin(Math.PI * p)\n\n  if (edge === 'top') {\n    const fillY = 100 * (1 - p)\n    const ctrlY = fillY - scoop\n    return `M 0 100 L 0 ${fillY} Q 50 ${ctrlY} 100 ${fillY} L 100 0 L 0 0 z`\n  }\n  if (edge === 'bottom') {\n    const fillY = 100 * p\n    const ctrlY = fillY + scoop\n    return `M 0 100 L 0 ${fillY} Q 50 ${ctrlY} 100 ${fillY} L 100 100 L 0 100 z`\n  }\n  if (edge === 'left') {\n    const fillX = 100 * (1 - p)\n    const ctrlX = fillX - scoop\n    return `M 0 0 L ${fillX} 0 Q ${ctrlX} 50 ${fillX} 100 L 0 100 L 0 0 z`\n  }\n  // right\n  const fillX = 100 * p\n  const ctrlX = fillX + scoop\n  return `M 100 0 L ${fillX} 0 Q ${ctrlX} 50 ${fillX} 100 L 100 100 L 100 0 z`\n}\n\nexport interface CurveSettings {\n  duration: number\n  delay: number\n  ease: string\n  color: string\n  mode: DirectionMode\n}\n\nexport function setupCurveHover(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: CurveSettings,\n): () => void {\n  const restore = prepareHost(host)\n\n  const svg = document.createElementNS(SVG_NS, 'svg')\n  svg.setAttribute('aa-hover-bg', 'curve')\n  svg.setAttribute('aria-hidden', 'true')\n  svg.setAttribute('viewBox', '0 0 100 100')\n  svg.setAttribute('preserveAspectRatio', 'none')\n  // Layout (position/inset/width/height/z-index/etc.) comes from the\n  // companion CSS rule on `[aa-hover-bg]`. Only the runtime-driven fill\n  // is set inline.\n  svg.style.fill = settings.color\n\n  const path = document.createElementNS(SVG_NS, 'path')\n  path.setAttribute('d', CURVE_FROM_PATHS[defaultEdge(settings.mode)].start)\n  svg.appendChild(path)\n  // Append (not first-child) — z-index: -1 + host's isolation: isolate\n  // keep the curve behind content regardless of DOM order. See block.\n  host.appendChild(svg)\n\n  let active: GsapTween | null = null\n\n  // See setupBlockHover — edge detection runs against the trigger's rect to\n  // stay sane when trigger !== host (composite buttons).\n  const onEnter = (event: MouseEvent): void => {\n    const edge = detectEdge(event, trigger, settings.mode)\n    const p = CURVE_FROM_PATHS[edge]\n    active?.kill()\n    active = gsap.gsap.fromTo(\n      path,\n      { attr: { d: p.start } },\n      {\n        attr: { d: p.end },\n        duration: settings.duration,\n        ease: settings.ease,\n        delay: settings.delay,\n        overwrite: true,\n      },\n    )\n  }\n\n  const onLeave = (event: MouseEvent): void => {\n    const edge = detectEdge(event, trigger, settings.mode)\n    active?.kill()\n    const state = { p: 0 }\n    active = gsap.gsap.to(state, {\n      p: 1,\n      duration: settings.duration,\n      ease: settings.ease,\n      onUpdate: () => {\n        path.setAttribute('d', computeLeavePath(edge, state.p))\n      },\n      overwrite: true,\n    })\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n  trigger.addEventListener('mouseleave', onLeave)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    trigger.removeEventListener('mouseleave', onLeave)\n    active?.kill()\n    svg.remove()\n    restoreHost(host, restore)\n  }\n}\n\n// ===========================================================================\n// Icon effect — SVG icon clone(s) sliding through a clipped wrapper\n// ===========================================================================\n\nexport type IconDirection =\n  | 'up'\n  | 'down'\n  | 'left'\n  | 'right'\n  | 'up-right'\n  | 'up-left'\n  | 'down-right'\n  | 'down-left'\n\nexport const ICON_DIRECTIONS: ReadonlySet<string> = new Set<IconDirection>([\n  'up',\n  'down',\n  'left',\n  'right',\n  'up-right',\n  'up-left',\n  'down-right',\n  'down-left',\n])\n\ninterface IconAxis {\n  cloneOffset: { left: string; top: string }\n  motion: { xPercent?: number; yPercent?: number }\n}\n\nconst ICON_MAP: Record<IconDirection, IconAxis> = {\n  right: { cloneOffset: { left: '-100%', top: '0' }, motion: { xPercent: 100 } },\n  left: { cloneOffset: { left: '100%', top: '0' }, motion: { xPercent: -100 } },\n  up: { cloneOffset: { left: '0', top: '100%' }, motion: { yPercent: -100 } },\n  down: { cloneOffset: { left: '0', top: '-100%' }, motion: { yPercent: 100 } },\n  'up-right': {\n    cloneOffset: { left: '-100%', top: '100%' },\n    motion: { xPercent: 100, yPercent: -100 },\n  },\n  'down-right': {\n    cloneOffset: { left: '-100%', top: '-100%' },\n    motion: { xPercent: 100, yPercent: 100 },\n  },\n  'up-left': {\n    cloneOffset: { left: '100%', top: '100%' },\n    motion: { xPercent: -100, yPercent: -100 },\n  },\n  'down-left': {\n    cloneOffset: { left: '100%', top: '-100%' },\n    motion: { xPercent: -100, yPercent: 100 },\n  },\n}\n\nexport interface IconSettings {\n  direction: IconDirection\n  reverse: boolean\n  /**\n   * `triple` doubles the slide distance and inserts a second clone two\n   * \"from\" steps offscreen. The first clone passes through centre at the\n   * midpoint (visible briefly), the second clone lands at centre at the end.\n   */\n  triple: boolean\n  duration: number\n  delay: number\n  ease: string\n  /** Lag (in seconds) between each successive icon starting its slide. */\n  cloneLag: number\n  /**\n   * Color override for the clone(s). Default `currentColor` = no override\n   * (clone inherits the host's color, matching the original). Any other\n   * value is set inline as the clone's `color`, which feeds the cloned\n   * SVG's `stroke=\"currentColor\"` paths — giving the \"swap-in\" icon a\n   * distinct colour against a coloured hover background (e.g. white clone\n   * over a black `curve` fill in a composite button).\n   */\n  color: string\n}\n\n/**\n * Scale a percentage offset (e.g. `-100%`, `0`) by an integer multiplier so\n * the second clone sits two units along the \"from\" axis instead of one.\n */\nfunction scaleOffset(value: string, multiplier: number): string {\n  if (value === '0' || value === '0%') return value\n  const match = value.match(/^(-?[\\d.]+)(%?)$/)\n  if (!match) return value\n  return `${parseFloat(match[1]) * multiplier}${match[2]}`\n}\n\nfunction scaleMotion(\n  motion: IconAxis['motion'],\n  multiplier: number,\n): IconAxis['motion'] {\n  const out: IconAxis['motion'] = {}\n  if (motion.xPercent !== undefined) out.xPercent = motion.xPercent * multiplier\n  if (motion.yPercent !== undefined) out.yPercent = motion.yPercent * multiplier\n  return out\n}\n\nexport function setupIconHover(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: IconSettings,\n): () => void {\n  const icon = host.querySelector('svg')\n  if (!icon) return () => {}\n\n  const map = ICON_MAP[settings.direction]\n  const parent = icon.parentNode\n  if (!parent) return () => {}\n\n  // Wrap the original SVG so the clip box is exactly the icon's size — both\n  // the original and the absolutely-positioned clones resolve their offsets\n  // (left: -100% / top: 100% / etc.) against this wrapper, not the host.\n  const wrap = document.createElement('span')\n  wrap.setAttribute('aa-hover-icon-clip', '')\n  Object.assign(wrap.style, {\n    display: 'inline-flex',\n    position: 'relative',\n    overflow: 'hidden',\n    verticalAlign: 'middle',\n  })\n  parent.insertBefore(wrap, icon)\n  wrap.appendChild(icon)\n\n  // Standard mode = 1 clone, triple mode = 2 clones. Each clone N sits at\n  // N \"from\"-direction units offscreen; the motion delta is scaled to\n  // (cloneCount) units so the trailing clone always lands exactly at centre.\n  const cloneCount = settings.triple ? 2 : 1\n  const motion = scaleMotion(map.motion, cloneCount)\n\n  const clones: SVGElement[] = []\n  for (let i = 1; i <= cloneCount; i++) {\n    const clone = icon.cloneNode(true) as SVGElement\n    clone.setAttribute('aria-hidden', 'true')\n    Object.assign(clone.style, {\n      position: 'absolute',\n      left: scaleOffset(map.cloneOffset.left, i),\n      top: scaleOffset(map.cloneOffset.top, i),\n    })\n    if (settings.color !== 'currentColor') clone.style.color = settings.color\n    wrap.appendChild(clone)\n    clones.push(clone)\n  }\n\n  const tl: GsapTimeline = gsap.gsap.timeline({\n    paused: true,\n    defaults: { duration: settings.duration, ease: settings.ease, delay: settings.delay },\n  })\n  tl.to(icon, motion, 0)\n  for (let i = 0; i < clones.length; i++) {\n    tl.to(clones[i], motion, settings.cloneLag * (i + 1))\n  }\n\n  const onEnter = (): void => {\n    tl.timeScale(1).play(0)\n  }\n  const onLeave = (): void => {\n    // 1.5× faster on reverse. `tl.reverse()` plays the timeline mirrored,\n    // which means the trailing clone's `cloneLag` becomes a LEAD lag on\n    // exit — the original is the last thing to return. Without a speed-up\n    // it reads as \"the icon is late.\" Speeding the reverse keeps the\n    // forward chain effect intact while bringing the icon back into sync\n    // with the other effects' flat-duration leaves (block/text).\n    tl.timeScale(1.5).reverse()\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n  if (settings.reverse) trigger.addEventListener('mouseleave', onLeave)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    if (settings.reverse) trigger.removeEventListener('mouseleave', onLeave)\n    tl.kill()\n    for (const clone of clones) clone.remove()\n    // Unwrap: drop the icon back to its original parent and remove the wrapper.\n    parent.insertBefore(icon, wrap)\n    wrap.remove()\n    gsap.gsap.set(icon, { clearProps: 'transform' })\n  }\n}\n\n// ===========================================================================\n// Underline effect — animated underline bar(s) at the host's bottom edge\n// ===========================================================================\n\nexport interface UnderlineSettings {\n  duration: number\n  delay: number\n  ease: string\n  color: string\n  /** `underline` → bar is always visible; on hover it collapses to the right\n   *  edge then re-grows from the left in a two-phase sweep. `underline-in` →\n   *  bar is off by default, sweeps in on hover and out on leave. */\n  variant: 'underline' | 'underline-in'\n}\n\nfunction createUnderlineBar(color: string): HTMLSpanElement {\n  const bar = document.createElement('span')\n  bar.setAttribute('aa-hover-underline', '')\n  bar.setAttribute('aria-hidden', 'true')\n  // Companion CSS supplies layout (position, width, height, default offset,\n  // currentColor background, transform-origin). Inline backgroundColor only\n  // when the author overrode aa-color away from currentColor.\n  if (color !== 'currentColor') bar.style.backgroundColor = color\n  return bar\n}\n\n/**\n * `underline` — bar always visible. Hover plays a single sweep-out / sweep-in\n * cycle (collapse to the right edge, then re-grow from the left). Mouseleave\n * is a no-op because the cycle already lands back in the always-on state.\n * A second mouseenter mid-cycle is ignored so the bar never re-enters\n * partway through itself — two bars tiling each other's gap would render\n * a simultaneous cross-fade visually static, hence the sequenced sweep.\n */\nfunction setupUnderlineSweep(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: UnderlineSettings,\n): () => void {\n  const restore = ensurePositioned(host)\n  const bar = createUnderlineBar(settings.color)\n  host.appendChild(bar)\n  gsap.gsap.set(bar, { scaleX: 1, transformOrigin: 'left center' })\n\n  let active: GsapTimeline | null = null\n  const half = settings.duration / 2\n\n  const onEnter = (): void => {\n    if (active) return\n    active = gsap.gsap\n      .timeline({ delay: settings.delay, onComplete: () => (active = null) })\n      .set(bar, { transformOrigin: 'right center' })\n      .to(bar, { scaleX: 0, duration: half, ease: settings.ease })\n      .set(bar, { transformOrigin: 'left center' })\n      .to(bar, { scaleX: 1, duration: half, ease: settings.ease })\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    active?.kill()\n    bar.remove()\n    restoreHost(host, restore)\n  }\n}\n\n/**\n * `underline-in` — bar invisible at rest. Mouseenter grows it from the left,\n * mouseleave shrinks it toward the right. Quick re-entry mid-OUT accelerates\n * the in-flight tween to land within ~FINISH_SECONDS, then chains the IN tween\n * — so direction stays correct (OUT rightward, IN leftward) with no snap.\n * Quick re-leave mid-IN is queued: the full IN runs first, then OUT.\n */\nfunction setupUnderlineIn(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: UnderlineSettings,\n): () => void {\n  const FINISH_SECONDS = 0.1\n\n  const restore = ensurePositioned(host)\n  const bar = createUnderlineBar(settings.color)\n  host.appendChild(bar)\n  gsap.gsap.set(bar, { scaleX: 0, transformOrigin: 'left center' })\n\n  let inActive: GsapTween | null = null\n  let outActive: GsapTween | null = null\n  let pendingLeave = false\n  let pendingEnter = false\n\n  const runIn = (): void => {\n    inActive = gsap.gsap.fromTo(\n      bar,\n      { scaleX: 0, transformOrigin: 'left center' },\n      {\n        scaleX: 1,\n        duration: settings.duration,\n        ease: settings.ease,\n        delay: settings.delay,\n        onComplete: () => {\n          inActive = null\n          if (pendingLeave) {\n            pendingLeave = false\n            runOut()\n          }\n        },\n      },\n    )\n  }\n\n  const runOut = (): void => {\n    outActive = gsap.gsap.fromTo(\n      bar,\n      { transformOrigin: 'right center' },\n      {\n        scaleX: 0,\n        duration: settings.duration,\n        ease: settings.ease,\n        onComplete: () => {\n          outActive = null\n          if (pendingEnter) {\n            pendingEnter = false\n            runIn()\n          }\n        },\n      },\n    )\n  }\n\n  const onEnter = (): void => {\n    if (inActive) {\n      // User flicked back over while IN is still growing — cancel the queued\n      // OUT so the bar doesn't immediately retract when IN completes.\n      pendingLeave = false\n      return\n    }\n    if (outActive) {\n      // Accelerate the in-flight OUT to land within FINISH_SECONDS wall-clock,\n      // then let its onComplete chain into runIn. Preserves directional\n      // integrity (OUT shrinks rightward; IN grows from left) without a snap.\n      pendingEnter = true\n      pendingLeave = false\n      const remainingAt1x = settings.duration * (1 - outActive.progress())\n      outActive.timeScale(Math.max(1, remainingAt1x / FINISH_SECONDS))\n      return\n    }\n    pendingLeave = false\n    runIn()\n  }\n\n  const onLeave = (): void => {\n    if (inActive) {\n      pendingLeave = true\n      return\n    }\n    if (outActive) {\n      // User pulled out mid-accelerated-finish. Cancel the queued IN and\n      // restore 1× playback so the bar shrinks at its natural pace.\n      pendingEnter = false\n      outActive.timeScale(1)\n      return\n    }\n    runOut()\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n  trigger.addEventListener('mouseleave', onLeave)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    trigger.removeEventListener('mouseleave', onLeave)\n    inActive?.kill()\n    outActive?.kill()\n    bar.remove()\n    restoreHost(host, restore)\n  }\n}\n\nexport function setupUnderlineHover(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: UnderlineSettings,\n): () => void {\n  return settings.variant === 'underline'\n    ? setupUnderlineSweep(host, trigger, gsap, settings)\n    : setupUnderlineIn(host, trigger, gsap, settings)\n}\n\n// ===========================================================================\n// Text effect — chars/words translate up; text-shadow at original baseline\n// renders the \"incoming\" letter underneath. No DOM clones; pure shadow trick.\n// ===========================================================================\n\nexport interface TextSettings {\n  duration: number\n  delay: number\n  ease: string\n  color: string\n  splitMode: SplitMode\n  stagger: StaggerValue\n  /** false (default) = one-shot: tween up, then instantly snap back to rest.\n   * The animation always plays to completion; re-hovers mid-tween are ignored.\n   * true = transition: chars stay up while hovered, return on leave, and either\n   * direction can be interrupted mid-tween (CSS-transition-like behaviour). */\n  reverse: boolean\n}\n\n/**\n * Force the host into the layout invariant the shadow trick requires:\n * `line-height: 1`, zero vertical padding, and a clip-path reference box.\n * `display: inline` is upgraded to `inline-block` because clip-path on a\n * raw inline element resolves percentages against a degenerate box and\n * clips the chars to nothing (visible when the host sits inside another\n * inline element). `block` / `inline-block` / `flex` etc. are left alone.\n * With these guarantees the element box equals the font's em-box and the\n * text-shadow trick lands cleanly. Authors who need vertical breathing\n * room should wrap the host or use margin — padding on the host itself\n * is what causes the shadow to leak.\n */\ninterface TextHostRestore {\n  lineHeight: string\n  paddingTop: string\n  paddingBottom: string\n  clipPath: string\n  display: string\n}\n\nfunction prepareTextHost(host: HTMLElement): TextHostRestore {\n  const restore: TextHostRestore = {\n    lineHeight: host.style.lineHeight,\n    paddingTop: host.style.paddingTop,\n    paddingBottom: host.style.paddingBottom,\n    clipPath: host.style.clipPath,\n    display: host.style.display,\n  }\n  host.style.lineHeight = '1'\n  host.style.paddingTop = '0'\n  host.style.paddingBottom = '0'\n  if (getComputedStyle(host).display === 'inline') host.style.display = 'inline-block'\n  return restore\n}\n\nfunction restoreTextHost(host: HTMLElement, restore: TextHostRestore): void {\n  host.style.lineHeight = restore.lineHeight\n  host.style.paddingTop = restore.paddingTop\n  host.style.paddingBottom = restore.paddingBottom\n  host.style.clipPath = restore.clipPath\n  host.style.display = restore.display\n}\n\nexport function setupTextHover(\n  host: HTMLElement,\n  trigger: HTMLElement,\n  gsap: GsapHandle,\n  settings: TextSettings,\n): () => void {\n  const restoreState = prepareTextHost(host)\n\n  // Matches Osmo's button-032 defaults — battle-tested in production. The 0%\n  // top means ascenders at rest may clip slightly at the box top (accepted\n  // trade-off). The -15% bottom extends the visible region 15% below the box\n  // so descenders (g, p, q, y) render unclipped; combined with a 1.1em shift\n  // this leaves a sliver (~0.05em) where the shadow's top ascenders are\n  // technically visible, which is hidden in practice by the actual glyph\n  // ascent of typical fonts. Override per-host via `--aa-hover-text-clip`.\n  const clipOverride = getComputedStyle(host).getPropertyValue('--aa-hover-text-clip').trim()\n  host.style.clipPath = clipOverride || 'inset(0% 0% -15%)'\n\n  // Shift = how far chars translate AND how far the text-shadow sits below\n  // the original baseline. 1.1em (Osmo default) — chars at y=-1.1em are\n  // entirely above the box (char top at -1.1em, char bottom at -0.1em),\n  // making the one-shot's snap-back invisible. Override per-host via\n  // `--aa-hover-text-shift`. Use a length ≥ box height (1em).\n  const shift =\n    getComputedStyle(host).getPropertyValue('--aa-hover-text-shift').trim() || '1.1em'\n\n  let units: HTMLElement[] = []\n  let tl: GsapTimeline | null = null\n\n  const applyShadows = (els: HTMLElement[]): void => {\n    for (const u of els) u.style.textShadow = `0 ${shift} ${settings.color}`\n  }\n  const clearShadows = (els: HTMLElement[]): void => {\n    for (const u of els) u.style.textShadow = ''\n  }\n\n  const pickUnits = (split: {\n    words: HTMLElement[]\n    chars: HTMLElement[]\n    lines: HTMLElement[]\n  }): HTMLElement[] => {\n    if (settings.splitMode === 'words') return split.words\n    // `lines` mode + the companion CSS `white-space: nowrap` on hover-text\n    // hosts collapses the text to a single line — so SplitText('lines')\n    // produces one line wrapper, and tweening that wrapper lifts the whole\n    // text as a single block (no per-char/word stagger). The host itself\n    // stays put, so the text-shadow trick still reveals at the rest position.\n    if (settings.splitMode === 'lines') return split.lines\n    return split.chars\n  }\n\n  /**\n   * Build a paused timeline that lifts the chars to `y: -shift` with stagger.\n   * Reverse mode plays forward on enter / reverse on leave (resumes from\n   * current time, so fast flicks interrupt cleanly). One-shot mode plays\n   * forward then snaps back to y=0 via onComplete — the snap is invisible\n   * because chars at y=-shift sit above the clip-path's top edge.\n   *\n   * Using a timeline (rather than fresh `gsap.to` tweens per enter/leave)\n   * keeps the stagger naturally mirrored on reverse — the last char to lift\n   * is the first to drop, reading as a wave that goes up then back down\n   * instead of two same-direction waves.\n   */\n  const buildTimeline = (): void => {\n    tl?.kill()\n    tl = gsap.gsap.timeline({ paused: true })\n    tl.fromTo(\n      units,\n      { y: 0 },\n      {\n        y: `-${shift}`,\n        duration: settings.duration,\n        ease: settings.ease,\n        delay: settings.delay,\n        stagger: settings.stagger,\n      },\n    )\n    if (!settings.reverse) {\n      tl.eventCallback('onComplete', () => {\n        gsap.gsap.set(units, { y: 0 })\n      })\n    }\n  }\n\n  const split = applySplit(host, settings.splitMode, gsap, {\n    onResplit: (newSplit) => {\n      units = pickUnits(newSplit)\n      applyShadows(units)\n      buildTimeline()\n    },\n  })\n  units = pickUnits(split)\n  if (units.length === 0) {\n    split.revert()\n    restoreTextHost(host, restoreState)\n    return () => {}\n  }\n  applyShadows(units)\n  buildTimeline()\n\n  const onEnter = (): void => {\n    if (settings.reverse) {\n      // play() resumes forward from current time, so an enter mid-reverse\n      // picks up wherever the chars are and tweens back up smoothly.\n      // timeScale(1) resets the 1.5× speed-up applied on the previous leave.\n      tl!.timeScale(1).play()\n    } else {\n      // One-shot: replay from the start, but ignore re-entries while the\n      // animation is still in flight so the run always finishes.\n      if (tl!.isActive()) return\n      tl!.restart()\n    }\n  }\n\n  const onLeave = (): void => {\n    // Reverse mode only. 1.5× speed-up on exit matches the icon hover —\n    // the entrance gets to read at its full ease, the exit gets out of the\n    // way faster so quick flicks don't feel laggy. reverse() plays the\n    // timeline backward from current time, interrupting a partial enter\n    // cleanly.\n    tl!.timeScale(1.5).reverse()\n  }\n\n  trigger.addEventListener('mouseenter', onEnter)\n  if (settings.reverse) trigger.addEventListener('mouseleave', onLeave)\n\n  return () => {\n    trigger.removeEventListener('mouseenter', onEnter)\n    if (settings.reverse) trigger.removeEventListener('mouseleave', onLeave)\n    tl?.kill()\n    clearShadows(units)\n    restoreTextHost(host, restoreState)\n    split.revert()\n  }\n}\n","import { parseNum } from '../../core/parse'\nimport type { FeatureContext, FeatureModule } from '../../core/registry'\nimport { readAttrs, type Config } from '../../core/settings'\nimport { buildStagger, defaultStaggerFor, parseStaggerSpec } from '../../core/stagger'\nimport { parseSplit, type SplitMode } from '../../split/runtime'\nimport { parseDirectionMode } from './direction'\nimport {\n  ICON_DIRECTIONS,\n  setupBlockHover,\n  setupCurveHover,\n  setupIconHover,\n  setupTextHover,\n  setupUnderlineHover,\n  type IconDirection,\n} from './effects'\n\ninterface ParsedHover {\n  type: 'block' | 'curve' | 'icon' | 'underline' | 'underline-in' | 'text' | null\n  direction?: IconDirection\n  flags: string[]\n}\n\nfunction parseHoverValue(value: string): ParsedHover {\n  const tokens = value.trim().split(/\\s+/).filter(Boolean)\n  if (tokens.length === 0) return { type: null, flags: [] }\n  const head = tokens[0]\n  const flags = tokens.slice(1)\n\n  if (head === 'block') return { type: 'block', flags }\n  if (head === 'curve') return { type: 'curve', flags }\n  if (head === 'underline') return { type: 'underline', flags }\n  if (head === 'underline-in') return { type: 'underline-in', flags }\n  if (head === 'text') return { type: 'text', flags }\n  if (head.startsWith('icon-')) {\n    const dir = head.slice('icon-'.length)\n    if (ICON_DIRECTIONS.has(dir)) {\n      return { type: 'icon', direction: dir as IconDirection, flags }\n    }\n  }\n  return { type: null, flags }\n}\n\nfunction elementMatches(el: Element): boolean {\n  const value = el.getAttribute('aa-hover')\n  if (!value) return false\n  for (const part of value.split('|')) {\n    if (parseHoverValue(part.trim()).type) return true\n  }\n  for (const bp of ['sm', 'md', 'lg', 'xl']) {\n    const v = el.getAttribute(`aa-hover-${bp}`)\n    if (v && parseHoverValue(v.trim()).type) return true\n  }\n  return false\n}\n\nconst HOVER_DEFAULTS = {\n  delay: 0,\n  /**\n   * Base time lag between each successive hover-icon starting its slide.\n   * `aa-intensity` is a multiplier on this value, so `aa-intensity=\"2\"` doubles\n   * the gap between icons (slower trail), `aa-intensity=\"0.5\"` halves it\n   * (tighter packing). Default multiplier = 1.\n   */\n  cloneLagBase: 0.05,\n} as const\n\n/**\n * Scan for [aa-hover-trigger] elements once at init and map every aa-hover\n * descendant to its owning trigger. Top-down so authors can reason: \"the\n * trigger wraps these children.\" Iteration is document-order, so nested\n * triggers correctly hand ownership to the innermost (later writes win).\n */\nfunction buildTriggerMap(): WeakMap<Element, HTMLElement> {\n  const map = new WeakMap<Element, HTMLElement>()\n  if (typeof document === 'undefined') return map\n  const triggers = document.querySelectorAll<HTMLElement>('[aa-hover-trigger]')\n  for (const trigger of triggers) {\n    if (trigger.hasAttribute('aa-hover')) map.set(trigger, trigger)\n    for (const desc of trigger.querySelectorAll<HTMLElement>('[aa-hover]')) {\n      map.set(desc, trigger)\n    }\n  }\n  return map\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  triggerMap: WeakMap<Element, HTMLElement>,\n  element: Element,\n  config: Config,\n): (() => void) | undefined {\n  const value = config['aa-hover']\n  if (!value) return\n  const parsed = parseHoverValue(value)\n  if (!parsed.type) return\n\n  const host = element as HTMLElement\n  // Either an ancestor (or the host itself) tagged aa-hover-trigger, or the\n  // host listens to its own events when no trigger applies.\n  const trigger = triggerMap.get(host) ?? host\n  const duration = parseNum(config['aa-duration'], ctx.options.duration)\n  const delay = parseNum(config['aa-delay'], HOVER_DEFAULTS.delay)\n  const ease = config['aa-ease'] ?? ctx.options.ease\n  const color = config['aa-color'] ?? 'currentColor'\n\n  if (parsed.type === 'block') {\n    return setupBlockHover(host, trigger, ctx.gsap, {\n      duration,\n      delay,\n      ease,\n      color,\n      mode: parseDirectionMode(parsed.flags),\n    })\n  }\n  if (parsed.type === 'curve') {\n    return setupCurveHover(host, trigger, ctx.gsap, {\n      duration,\n      delay,\n      ease,\n      color,\n      mode: parseDirectionMode(parsed.flags),\n    })\n  }\n  if (parsed.type === 'icon' && parsed.direction) {\n    const intensity = parseNum(config['aa-intensity'], 1)\n    return setupIconHover(host, trigger, ctx.gsap, {\n      direction: parsed.direction,\n      reverse: parsed.flags.includes('reverse'),\n      triple: parsed.flags.includes('triple'),\n      duration,\n      delay,\n      ease,\n      cloneLag: HOVER_DEFAULTS.cloneLagBase * intensity,\n      color,\n    })\n  }\n  if (parsed.type === 'underline' || parsed.type === 'underline-in') {\n    return setupUnderlineHover(host, trigger, ctx.gsap, {\n      duration,\n      delay,\n      ease,\n      color,\n      variant: parsed.type,\n    })\n  }\n  if (parsed.type === 'text') {\n    const splitMode: SplitMode = parseSplit(config['aa-split'])?.mode ?? 'chars'\n    const staggerSpec = parseStaggerSpec(\n      config['aa-stagger'],\n      defaultStaggerFor(splitMode === 'lines' ? undefined : splitMode, ctx.options),\n    )\n    return setupTextHover(host, trigger, ctx.gsap, {\n      duration,\n      delay,\n      ease,\n      color,\n      splitMode,\n      stagger: buildStagger(staggerSpec.unit, staggerSpec.flags),\n      reverse: parsed.flags.includes('reverse'),\n    })\n  }\n  return undefined\n}\n\nconst hoverFeature: FeatureModule = {\n  name: 'hover',\n  init(ctx: FeatureContext): () => void {\n    // Skip touch-only devices entirely — hover events are unreliable there.\n    if (typeof window !== 'undefined' && !window.matchMedia('(hover: hover)').matches) {\n      return () => {}\n    }\n    const triggerMap = buildTriggerMap()\n    const subjects = ctx.elements.filter(elementMatches)\n    for (const element of subjects) {\n      const attrs = readAttrs(element)\n      ctx.responsive.bind(element, attrs, ({ config }) =>\n        setupOne(ctx, triggerMap, element, config),\n      )\n    }\n    return () => {}\n  },\n}\n\nexport default hoverFeature\n","import type { GsapInstance } from '../../core/gsap-detect'\nimport type { FeatureContext, FeatureModule } from '../../core/registry'\n\ntype QuickTo = (value: number) => void\ntype QuickToFactory = (target: Element, prop: string, vars?: Record<string, unknown>) => QuickTo\ntype GsapWithQuickTo = GsapInstance & { quickTo: QuickToFactory }\n\nconst DEFAULT_X_OFFSET = 6\nconst DEFAULT_Y_OFFSET = -140\nconst X_EDGE_OFFSET = -100\nconst Y_EDGE_OFFSET = -120\nconst EDGE_BUFFER = 16\n\nconst RESERVED_TRIGGER_PARTS = new Set(['offset'])\n\nconst SHOW_DURATION = 0.3\nconst HIDE_DURATION = 0.4\nconst FOLLOW_EASE = 'power3'\nconst SHOW_EASE = 'power2.out'\nconst HIDE_EASE = 'power2.in'\nconst OFFSET_EASE = 'power3'\nconst OFFSET_DURATION = 0.9\n\ninterface StyleSnapshot {\n  position: string\n  left: string\n  top: string\n  opacity: string\n  visibility: string\n  pointerEvents: string\n  transform: string\n}\n\nfunction snapshot(el: HTMLElement): StyleSnapshot {\n  return {\n    position: el.style.position,\n    left: el.style.left,\n    top: el.style.top,\n    opacity: el.style.opacity,\n    visibility: el.style.visibility,\n    pointerEvents: el.style.pointerEvents,\n    transform: el.style.transform,\n  }\n}\n\nfunction restore(el: HTMLElement, snap: StyleSnapshot): void {\n  el.style.position = snap.position\n  el.style.left = snap.left\n  el.style.top = snap.top\n  el.style.opacity = snap.opacity\n  el.style.visibility = snap.visibility\n  el.style.pointerEvents = snap.pointerEvents\n  el.style.transform = snap.transform\n}\n\nfunction getCursorAttributes(trigger: Element): Record<string, string> {\n  const result: Record<string, string> = {}\n  for (const attr of Array.from(trigger.attributes)) {\n    if (!attr.name.startsWith('aa-cursor-') || attr.name === 'aa-cursor-trigger') continue\n    const part = attr.name.slice('aa-cursor-'.length)\n    if (!part || RESERVED_TRIGGER_PARTS.has(part)) continue\n    result[part] = attr.value\n  }\n  return result\n}\n\nfunction parseCursorOffset(\n  value: string | null,\n  cursorName: string,\n  debug: boolean,\n): [number, number] {\n  if (!value) return [DEFAULT_X_OFFSET, DEFAULT_Y_OFFSET]\n  const parts = value.trim().split(/\\s+/)\n  const warn = (reason: string): [number, number] => {\n    if (debug) {\n      console.warn(\n        `[alrdy-animate] aa-cursor-offset on [aa-cursor${cursorName ? `=\"${cursorName}\"` : ''}] ${reason}. Got \"${value}\". Falling back to defaults.`,\n      )\n    }\n    return [DEFAULT_X_OFFSET, DEFAULT_Y_OFFSET]\n  }\n  if (parts.length !== 2) return warn('must be two space-separated numbers (xPercent yPercent)')\n  const x = Number(parts[0])\n  const y = Number(parts[1])\n  if (!Number.isFinite(x) || !Number.isFinite(y)) return warn('values must be finite numbers')\n  return [x, y]\n}\n\ninterface CursorInstance {\n  el: HTMLElement\n  inner: HTMLElement\n  cursorSnap: StyleSnapshot\n  innerSnap: StyleSnapshot\n  slotCache: Map<string, Element>\n  lastAttributes: Record<string, string>\n  currentTarget: Element | null\n  isHiding: boolean\n  pendingShowTrigger: HTMLElement | null\n  xTo: QuickTo\n  yTo: QuickTo\n  applyEdgeOffsets: (x: number, y: number) => void\n  updateContent: (trigger: Element) => void\n  resetContent: () => void\n  showCursor: () => void\n  hideCursor: () => void\n  destroy: () => void\n}\n\nfunction createCursorInstance(\n  cursorEl: HTMLElement,\n  cursorInner: HTMLElement,\n  gsap: GsapWithQuickTo,\n  xOffset: number,\n  yOffset: number,\n): CursorInstance {\n  const cursorSnap = snapshot(cursorEl)\n  const innerSnap = snapshot(cursorInner)\n  const slotCache = new Map<string, Element>()\n\n  const inst: CursorInstance = {\n    el: cursorEl,\n    inner: cursorInner,\n    cursorSnap,\n    innerSnap,\n    slotCache,\n    lastAttributes: {},\n    currentTarget: null,\n    isHiding: false,\n    pendingShowTrigger: null,\n    xTo: () => {},\n    yTo: () => {},\n    applyEdgeOffsets: () => {},\n    updateContent: () => {},\n    resetContent: () => {},\n    showCursor: () => {},\n    hideCursor: () => {},\n    destroy: () => {},\n  }\n\n  const getSlot = (part: string): Element | null => {\n    const cached = slotCache.get(part)\n    if (cached) return cached\n    const found = cursorEl.querySelector(`[aa-cursor-${part}]`)\n    if (found) slotCache.set(part, found)\n    return found\n  }\n\n  inst.updateContent = (trigger: Element): void => {\n    const next = getCursorAttributes(trigger)\n    const nextKeys = Object.keys(next)\n    const sameAsLast =\n      inst.currentTarget === trigger &&\n      nextKeys.length === Object.keys(inst.lastAttributes).length &&\n      nextKeys.every((k) => inst.lastAttributes[k] === next[k])\n    if (sameAsLast) return\n\n    for (const part of nextKeys) {\n      const slot = getSlot(part)\n      if (!slot) continue\n      const value = next[part]\n      if (part === 'image' || slot.tagName === 'IMG') {\n        const img = slot as HTMLImageElement\n        img.src = value\n        img.alt = ''\n      } else {\n        slot.textContent = value\n      }\n    }\n\n    inst.lastAttributes = next\n    inst.currentTarget = trigger\n  }\n\n  inst.resetContent = (): void => {\n    for (const part of Object.keys(inst.lastAttributes)) {\n      const slot = getSlot(part)\n      if (!slot) continue\n      if (part === 'image' || slot.tagName === 'IMG') {\n        slot.removeAttribute('src')\n        slot.removeAttribute('alt')\n      } else {\n        slot.textContent = ''\n      }\n    }\n    inst.lastAttributes = {}\n    inst.currentTarget = null\n  }\n\n  gsap.set(cursorEl, {\n    position: 'fixed',\n    left: 0,\n    top: 0,\n    xPercent: xOffset,\n    yPercent: yOffset,\n    opacity: 0,\n    pointerEvents: 'none',\n  })\n  gsap.set(cursorInner, { opacity: 0 })\n\n  inst.xTo = gsap.quickTo(cursorEl, 'x', { ease: FOLLOW_EASE })\n  inst.yTo = gsap.quickTo(cursorEl, 'y', { ease: FOLLOW_EASE })\n\n  inst.applyEdgeOffsets = (x: number, y: number): void => {\n    if (inst.isHiding) return\n    const cursorEdgeThreshold = cursorEl.offsetWidth + EDGE_BUFFER\n    const xPercent = x > window.innerWidth - cursorEdgeThreshold ? X_EDGE_OFFSET : xOffset\n    const yPercent = y > window.innerHeight * 0.9 ? Y_EDGE_OFFSET : yOffset\n    gsap.to(cursorEl, {\n      xPercent,\n      yPercent,\n      duration: OFFSET_DURATION,\n      ease: OFFSET_EASE,\n    })\n  }\n\n  inst.showCursor = (): void => {\n    gsap.to(cursorEl, { opacity: 1, duration: SHOW_DURATION, ease: SHOW_EASE })\n    gsap.fromTo(\n      cursorInner,\n      { y: 0, rotation: 0, opacity: 0 },\n      { y: 0, rotation: 0, opacity: 1, duration: SHOW_DURATION, ease: SHOW_EASE },\n    )\n  }\n\n  inst.hideCursor = (): void => {\n    inst.isHiding = true\n    gsap.killTweensOf(cursorInner)\n    const fallDistance = cursorInner.offsetHeight * 1.5\n    const randomRotation = Math.random() * 20 - 10\n    gsap.to(cursorEl, { opacity: 0, duration: HIDE_DURATION, ease: HIDE_EASE })\n    gsap.to(cursorInner, {\n      y: fallDistance,\n      rotation: randomRotation,\n      opacity: 0,\n      duration: HIDE_DURATION,\n      ease: HIDE_EASE,\n      onComplete: () => {\n        gsap.set(cursorInner, { y: 0, rotation: 0 })\n        inst.resetContent()\n        inst.isHiding = false\n        const queued = inst.pendingShowTrigger\n        if (queued) {\n          inst.pendingShowTrigger = null\n          const elUnderMouse = document.elementFromPoint(currentPointerX, currentPointerY)\n          const stillOver =\n            !!elUnderMouse && (queued === elUnderMouse || queued.contains(elUnderMouse))\n          if (stillOver) {\n            inst.currentTarget = queued\n            inst.updateContent(queued)\n            inst.showCursor()\n          }\n        }\n      },\n    })\n  }\n\n  inst.destroy = (): void => {\n    gsap.killTweensOf(cursorEl)\n    gsap.killTweensOf(cursorInner)\n    inst.resetContent()\n    restore(cursorEl, cursorSnap)\n    restore(cursorInner, innerSnap)\n  }\n\n  return inst\n}\n\nlet currentPointerX = 0\nlet currentPointerY = 0\n\nconst cursorFeature: FeatureModule = {\n  name: 'cursor',\n  init(ctx: FeatureContext): () => void {\n    if (typeof window === 'undefined') return () => {}\n\n    const cursorEls = Array.from(document.querySelectorAll<HTMLElement>('[aa-cursor]'))\n    if (cursorEls.length === 0) return () => {}\n\n    if (!window.matchMedia('(hover: hover)').matches) {\n      for (const el of cursorEls) {\n        el.style.opacity = '0'\n        el.style.visibility = 'hidden'\n        el.style.pointerEvents = 'none'\n      }\n      return () => {\n        for (const el of cursorEls) {\n          el.style.opacity = ''\n          el.style.visibility = ''\n          el.style.pointerEvents = ''\n        }\n      }\n    }\n\n    const gsap = ctx.gsap.gsap as GsapWithQuickTo\n    const cursors = new Map<string, CursorInstance>()\n\n    for (const el of cursorEls) {\n      const name = el.getAttribute('aa-cursor') ?? ''\n      if (cursors.has(name)) {\n        if (ctx.debug) {\n          console.warn(\n            `[alrdy-animate] Multiple [aa-cursor${name ? `=\"${name}\"` : ''}] elements found. Using the first.`,\n          )\n        }\n        continue\n      }\n      const inner = el.querySelector<HTMLElement>(':scope > div')\n      if (!inner) {\n        if (ctx.debug) {\n          console.warn(\n            `[alrdy-animate] Cursor element [aa-cursor${name ? `=\"${name}\"` : ''}] must contain a nested <div>. Skipping.`,\n          )\n        }\n        continue\n      }\n      const [xOffset, yOffset] = parseCursorOffset(\n        el.getAttribute('aa-cursor-offset'),\n        name,\n        ctx.debug,\n      )\n      cursors.set(name, createCursorInstance(el, inner, gsap, xOffset, yOffset))\n    }\n\n    if (cursors.size === 0) return () => {}\n\n    let rafId: number | null = null\n    const onMouseMove = (event: MouseEvent): void => {\n      currentPointerX = event.clientX\n      currentPointerY = event.clientY\n      if (rafId !== null) return\n      rafId = requestAnimationFrame(() => {\n        rafId = null\n        for (const inst of cursors.values()) {\n          inst.applyEdgeOffsets(currentPointerX, currentPointerY)\n          inst.xTo(currentPointerX)\n          inst.yTo(currentPointerY)\n        }\n      })\n    }\n    window.addEventListener('mousemove', onMouseMove, { passive: true })\n\n    const triggers = Array.from(document.querySelectorAll<HTMLElement>('[aa-cursor-trigger]'))\n    const triggerHandlers = new WeakMap<\n      HTMLElement,\n      { enter: () => void; leave: () => void }\n    >()\n\n    for (const trigger of triggers) {\n      const name = trigger.getAttribute('aa-cursor-trigger') ?? ''\n      const inst = cursors.get(name)\n      if (!inst) continue\n\n      const onEnter = (): void => {\n        if (inst.isHiding) {\n          inst.pendingShowTrigger = trigger\n          return\n        }\n        inst.currentTarget = trigger\n        inst.updateContent(trigger)\n        inst.showCursor()\n      }\n      const onLeave = (): void => {\n        inst.hideCursor()\n      }\n      trigger.addEventListener('mouseenter', onEnter)\n      trigger.addEventListener('mouseleave', onLeave)\n      triggerHandlers.set(trigger, { enter: onEnter, leave: onLeave })\n    }\n\n    return () => {\n      window.removeEventListener('mousemove', onMouseMove)\n      if (rafId !== null) {\n        cancelAnimationFrame(rafId)\n        rafId = null\n      }\n      for (const trigger of triggers) {\n        const handlers = triggerHandlers.get(trigger)\n        if (!handlers) continue\n        trigger.removeEventListener('mouseenter', handlers.enter)\n        trigger.removeEventListener('mouseleave', handlers.leave)\n      }\n      for (const inst of cursors.values()) {\n        inst.pendingShowTrigger = null\n        inst.destroy()\n      }\n      cursors.clear()\n    }\n  },\n}\n\nexport default cursorFeature\n","import type { GsapInstance } from '../../core/gsap-detect'\nimport { parseNum } from '../../core/parse'\nimport { bindRootFeature, type FeatureContext, type FeatureModule } from '../../core/registry'\nimport type { Config } from '../../core/settings'\nimport { emitTrigger } from '../../core/trigger'\n\nconst IN_FLAGS = new Set([\n  'fade',\n  'scale',\n  'rotate',\n  'rotate-cw',\n  'rotate-ccw',\n  'tilt',\n  'tilt-cw',\n  'tilt-ccw',\n])\nconst LOCK_FLAGS = new Set(['bounce', 'pulse'])\nconst OUT_FLAGS = new Set(['fade', 'scale', 'perspective', 'blur', 'left', 'right'])\n\ntype Vars = Record<string, number | string>\n\nfunction parseFlags(value: string | undefined, valid: Set<string>): Set<string> {\n  if (!value) return new Set()\n  const out = new Set<string>()\n  for (const t of value.trim().split(/\\s+/)) {\n    if (t && t !== 'none' && valid.has(t)) out.add(t)\n  }\n  return out\n}\n\ntype RotationMode = 'default' | 'cw' | 'ccw'\n\n// Per-card rotation value for the `rotate` and `tilt` flag families. Both\n// families use the same per-index curve; the difference is timing — `rotate`\n// applies the value as the from-state (cards arrive tilted, settle flat),\n// `tilt` applies it as the to-state (cards arrive flat, build up by lock).\n//\n// - `default`: `(0°, -5°, +5°, -5°, +5°, …)` — balanced fan around centre,\n//   first card flat. Osmo's standard splay aesthetic.\n// - `cw`: incremental clockwise ramp `(0°, +1°, +2°, +3°, …)`. First card\n//   flat; each subsequent card adds one more degree of clockwise rotation.\n//   (CSS rotation is positive-clockwise.)\n// - `ccw`: mirror of `cw` — `(0°, -1°, -2°, -3°, …)`.\nfunction rotationForIndex(index: number, intensity: number, mode: RotationMode): number {\n  if (mode === 'cw') return index * intensity\n  if (mode === 'ccw') return -index * intensity\n  if (index === 0) return 0\n  return (index % 2 === 1 ? -1 : 1) * 5 * intensity\n}\n\n// Resolve the active mode for one of the two rotation families. Each family\n// has a default flag (`rotate` / `tilt`) and two directional variants\n// (`-cw` / `-ccw`). Directional variants win over the default within a family.\nfunction modeFor(flags: Set<string>, prefix: 'rotate' | 'tilt'): RotationMode | null {\n  if (flags.has(`${prefix}-cw`)) return 'cw'\n  if (flags.has(`${prefix}-ccw`)) return 'ccw'\n  if (flags.has(prefix)) return 'default'\n  return null\n}\n\n/**\n * Per-card rotation pair for the in-tween. The `rotate*` family applies the\n * angle as the from-state (card arrives tilted, settles flat). The `tilt*`\n * family applies it as the to-state (card arrives flat, builds up by lock).\n * The two families share the same per-card curve via `rotationForIndex` —\n * only the timing differs. When both are listed `tilt*` wins.\n */\nfunction rotationPair(\n  rotateMode: RotationMode | null,\n  tiltMode: RotationMode | null,\n  index: number,\n  intensity: number,\n): { from?: number; to?: number } {\n  if (tiltMode !== null) {\n    return { from: 0, to: rotationForIndex(index, intensity, tiltMode) }\n  }\n  if (rotateMode !== null) {\n    return { from: rotationForIndex(index, intensity, rotateMode), to: 0 }\n  }\n  return {}\n}\n\n// Scale / rotation from- and to-states for the in-tween. `fade` is deliberately\n// *not* handled here — it gets its own tween that finishes halfway to the lock\n// (see the in block), so it can't share this full-range tween.\nfunction buildInFrom(flags: Set<string>, intensity: number, rotation: number | undefined): Vars {\n  const v: Vars = {}\n  if (flags.has('scale')) v.scale = Math.max(0, 1 - 0.2 * intensity)\n  if (rotation !== undefined) v.rotation = rotation\n  return v\n}\n\nfunction buildInTo(flags: Set<string>, rotation: number | undefined): Vars {\n  const v: Vars = {}\n  if (flags.has('scale')) v.scale = 1\n  if (rotation !== undefined) v.rotation = rotation\n  return v\n}\n\nfunction buildOutTo(flags: Set<string>, intensity: number): Vars {\n  const v: Vars = {}\n  // Order matters where flags share a property — later writes win, so the\n  // composite flags (`perspective`, `blur`, `left`, `right`) override plain\n  // `fade` / `scale` when combined.\n  if (flags.has('fade')) v.opacity = 0\n  if (flags.has('scale')) v.scale = Math.max(0, 1 - 0.15 * intensity)\n  if (flags.has('perspective')) {\n    v.rotationX = 10 * intensity\n    v.scale = 0.92\n    // Lift as a percentage of the card's *own height* (`translateY(%)` resolves\n    // against element height). A fixed `rem` lift gets swallowed on tall cards:\n    // the `scale: 0.92` pulls the top edge down by ~4% of height, which on a\n    // large screen (tall cards) outgrows a fixed lift and the card vanishes\n    // behind the next one. A height-relative lift keeps the peek proportional\n    // across screen sizes. Scaled by intensity like the rest of the preset.\n    v.y = `${-7 * intensity}%`\n  }\n  if (flags.has('blur')) {\n    v.filter = `blur(${8 * intensity}px)`\n    v.y = `${-3.5 * intensity}%`\n  }\n  if (flags.has('left')) {\n    v.x = `${-4 * intensity}rem`\n    v.opacity = 0\n  }\n  if (flags.has('right')) {\n    v.x = `${4 * intensity}rem`\n    v.opacity = 0\n  }\n  return v\n}\n\nfunction playLock(gsap: GsapInstance, card: HTMLElement, flags: Set<string>): void {\n  if (flags.has('bounce')) {\n    gsap\n      .timeline({ overwrite: 'auto' })\n      .to(card, { scaleX: 1.06, scaleY: 0.94, duration: 0.1, ease: 'power1.out' })\n      .to(card, { scaleX: 1, scaleY: 1, duration: 0.8, ease: 'elastic.out(1, 0.3)' })\n  } else if (flags.has('pulse')) {\n    gsap\n      .timeline({ overwrite: 'auto' })\n      .to(card, { scale: 1.03, duration: 0.15, ease: 'power1.out' })\n      .to(card, { scale: 1, duration: 0.3, ease: 'back.out(2)' })\n  }\n}\n\ninterface StackGeometry {\n  tops: number[]\n  stickyTop: number\n}\n\n/**\n * Capture each card's natural in-flow top in document coordinates, plus the\n * sticky-top offset, in a single layout pass.\n *\n * Why this exists: Chrome (and Webkit) inflate a sticky element's `offsetTop`\n * by the sticky offset while the element is currently \"stuck\", so neither\n * `offsetTop` nor `getBoundingClientRect().top` give us the natural in-flow\n * position once any card is locked. To measure correctly we read sticky-top\n * first (from the un-mutated computed style), then temporarily strip\n * `position: sticky`, force a synchronous layout, read each card's offsetTop\n * chain, and restore the original inline values. The strip is a single tick —\n * no paint happens between the style mutations and the synchronous read.\n *\n * Called on setup and on every ScrollTrigger refresh (resize, etc.) so the\n * cached geometry stays correct as the layout evolves.\n */\nfunction captureGeometry(cards: HTMLElement[]): StackGeometry {\n  // Read sticky-top first, *before* we strip `position: sticky`. After\n  // stripping, `top` resolves to `auto` and parseFloat returns NaN.\n  const stickyTop = parseFloat(getComputedStyle(cards[0]).top) || 0\n  const saved: string[] = []\n  for (let i = 0; i < cards.length; i++) {\n    saved.push(cards[i].style.position)\n    cards[i].style.position = 'static'\n  }\n  // Force a layout flush so `offsetTop` reflects the stripped state.\n  void cards[0].offsetHeight\n  const tops = cards.map((c) => {\n    let top = 0\n    let cur: HTMLElement | null = c\n    while (cur) {\n      top += cur.offsetTop\n      cur = cur.offsetParent as HTMLElement | null\n    }\n    return top\n  })\n  for (let i = 0; i < cards.length; i++) {\n    cards[i].style.position = saved[i]\n  }\n  return { tops, stickyTop }\n}\n\ninterface ScrollTriggerCtorWithEvents {\n  create: (vars: Record<string, unknown>) => { kill: () => void }\n  addEventListener: (event: string, fn: () => void) => void\n  removeEventListener: (event: string, fn: () => void) => void\n}\n\n/**\n * Parse the second token of a ScrollTrigger position string as a viewport\n * fraction. Accepts `'top 85%'`, `'top bottom'`, `'top center'`, `'top top'`,\n * plain `'85%'`, etc. Defaults to 0.85 (i.e. the lib's default scroll-start).\n *\n * Only the second token is parsed — the first (`'top'` / `'center'` / etc.)\n * is implicitly the element's top edge for stack, since each card is anchored\n * by its top in the sticky lock model.\n */\nfunction parseViewportFraction(value: string | undefined): number {\n  if (!value) return 0.85\n  const parts = value.trim().split(/\\s+/)\n  const second = parts.length > 1 ? parts[1] : parts[0]\n  if (!second) return 0.85\n  if (second === 'bottom') return 1\n  if (second === 'center') return 0.5\n  if (second === 'top') return 0\n  const m = second.match(/^([\\d.]+)%?$/)\n  if (!m) return 0.85\n  const n = parseFloat(m[1])\n  return Number.isFinite(n) ? (n > 1 ? n / 100 : n) : 0.85\n}\n\nfunction setupOne(\n  ctx: FeatureContext,\n  root: HTMLElement,\n  config: Config,\n): (() => void) | undefined {\n  if ((config['aa-stack'] ?? '').trim() === 'none') return undefined\n\n  const cards = Array.from(root.querySelectorAll<HTMLElement>('[aa-stack-card]'))\n  if (cards.length === 0) return undefined\n\n  const ScrollTrigger = ctx.gsap.plugins.ScrollTrigger as ScrollTriggerCtorWithEvents | undefined\n  if (!ScrollTrigger) return undefined\n\n  const gsap = ctx.gsap.gsap\n\n  const inFlags = parseFlags(config['aa-stack-in'], IN_FLAGS)\n  const lockFlags = parseFlags(config['aa-stack-lock'], LOCK_FLAGS)\n  const outFlags = parseFlags(config['aa-stack-out'], OUT_FLAGS)\n\n  const intensity = parseNum(config['aa-intensity'], ctx.options.intensity)\n  // Scrub is hardcoded true (direct, no smoothing). The cards themselves move\n  // with scroll instantly via CSS `position: sticky` — only the JS-driven\n  // transforms (rotate / scale / blur) are scrubbed. Adding smoothing would\n  // desync the visual transforms from the (instant) card position, producing\n  // a \"rotation lags behind card position\" mismatch. Out of scope for stack;\n  // users who need scrub smoothing should use the `scroll` feature instead.\n  const scrub: true = true\n\n  // Resolve the active rotation mode for each family once — the flag set is\n  // constant per setup, so per-card lookups inside the build helpers would\n  // just repeat work.\n  const rotateMode = modeFor(inFlags, 'rotate')\n  const tiltMode = modeFor(inFlags, 'tilt')\n\n  // Two separate scroll positions:\n  //  - `eventFraction` drives the card-active / card-inactive events that\n  //    fire the inner `aa-animate` children. Honors `aa-scroll-start`\n  //    (default `top 85%`) just like every other content animation.\n  //  - The in / out visual tweens always scrub from `top bottom` (the card\n  //    first peeking into the viewport from below) to the lock point. Not\n  //    user-configurable — the visual choreography is tied to the layout.\n  const eventFraction = parseViewportFraction(\n    config['aa-scroll-start'] ?? ctx.options.scrollStart,\n  )\n\n  // Cached layout geometry — naturals + sticky-top offset captured in a\n  // single strip-and-measure pass. Recaptured on every ScrollTrigger refresh\n  // so resizes and mid-scroll inits stay correct. Function-form trigger\n  // positions below read from this object, never from live offsetTop /\n  // getComputedStyle, both of which inflate by the sticky offset whenever a\n  // card is currently locked.\n  let geometry = captureGeometry(cards)\n\n  const reduceMotion = ctx.reducedMotion !== null\n\n  // Last-card cover finisher: when the exit preset includes `perspective`, the\n  // final card rises at the end of the stack so it re-covers the receded card\n  // behind it (instead of unsticking the instant it locks and scrolling off with\n  // a permanent gap). It needs trailing scroll room to stay stuck while it\n  // lifts; we add it as the last card's own `margin-bottom` rather than touching\n  // the root's padding — writing onto the root would clobber the author's (often\n  // responsive) padding and any class-set value. The margin extends the root's\n  // content box below the last card, lengthening its sticky range, without\n  // shifting any card's `offsetTop` (so `captureGeometry` is unaffected).\n  //\n  // The cover lift is *half* the perspective out lift (`7%` → `3.5%` of the\n  // card's height): the receding card also scales to 0.92, which pulls its top\n  // edge back down, so its visible peek above the last card is less than the\n  // full lift — a half lift covers it without over-shooting (which would expose\n  // it below the last card as it scrolls off). It's a percentage of card height\n  // (like the out lift) so the cover stays proportional across screen sizes; the\n  // runway margin and the ScrollTrigger end need that in px (margin-% and scroll\n  // offsets aren't height-relative), so we recompute it from `offsetHeight` on\n  // every refresh. Skipped under reduced motion and for a single-card stack.\n  const COVER_PCT = 3.5\n  const lastCard = cards[cards.length - 1]\n  const coverEnabled =\n    !reduceMotion && cards.length > 1 && outFlags.has('perspective') && lastCard !== undefined\n  const coverLiftPx = (): number => (lastCard.offsetHeight * COVER_PCT * intensity) / 100\n  const savedMargin = lastCard !== undefined ? lastCard.style.marginBottom : ''\n  const applyCoverRunway = (): void => {\n    if (coverEnabled) lastCard.style.marginBottom = `${coverLiftPx()}px`\n  }\n  applyCoverRunway()\n\n  const onRefreshInit = (): void => {\n    geometry = captureGeometry(cards)\n    applyCoverRunway()\n  }\n  ScrollTrigger.addEventListener('refreshInit', onRefreshInit)\n\n  const cleanups: Array<() => void> = []\n  cleanups.push(() => ScrollTrigger.removeEventListener('refreshInit', onRefreshInit))\n  if (coverEnabled) cleanups.push(() => (lastCard.style.marginBottom = savedMargin))\n  const again = ctx.options.again !== false\n\n  cards.forEach((card, index) => {\n    // z-index ladder: later cards sit on top so each new card visibly\n    // overlays the previous one as it slides up to its lock point. Without\n    // this the next card would slot in *behind* the locked previous card\n    // and disappear from view.\n    gsap.set(card, { zIndex: index + 1 })\n\n    // Absolute scroll positions read from the geometry cache. ScrollTrigger\n    // re-evaluates these on every refresh, picking up the freshly-captured\n    // values from `onRefreshInit` above.\n    const entryStart = (): number => geometry.tops[index] - window.innerHeight\n    const lockPoint = (): number => geometry.tops[index] - geometry.stickyTop\n    const eventActiveAt = (): number =>\n      geometry.tops[index] - eventFraction * window.innerHeight\n    const eventResetAt = (): number =>\n      geometry.tops[index] - window.innerHeight\n\n    // Per-card state gate. Event-mode child animations (`subscribeWithPair`\n    // path in setupTriggeredAnimation) call `.play(0)` on every forward\n    // dispatch, which would replay every time the user scrolls back across\n    // the active threshold without ever fully leaving. Matching the standard\n    // scroll-feature's aa-again semantics (\"replay only after full reset\")\n    // means we dispatch `card-active` only on the inactive→active edge and\n    // `card-inactive` only on the active→inactive edge.\n    let isActive = false\n    const setActive = (next: boolean, name: 'card-active' | 'card-inactive'): void => {\n      if (isActive === next) return\n      isActive = next\n      emitTrigger(card, name)\n    }\n\n    // Card-active trigger. Fires only on the leading edge — the trigger sits\n    // dormant on subsequent forward crossings until card-inactive has reset\n    // the gate (full leaveback past the reset threshold).\n    const activeTrigger = ScrollTrigger.create({\n      trigger: card,\n      start: eventActiveAt,\n      onEnter: () => setActive(true, 'card-active'),\n    })\n    cleanups.push(() => activeTrigger.kill())\n\n    // Card-inactive trigger (full-leaveback reset) — only when `again` is\n    // enabled, mirroring the lib's standard `bindAgainTrigger` semantics.\n    if (again) {\n      const inactiveTrigger = ScrollTrigger.create({\n        trigger: card,\n        start: eventResetAt,\n        onLeaveBack: () => setActive(false, 'card-inactive'),\n      })\n      cleanups.push(() => inactiveTrigger.kill())\n    }\n\n    // Bootstrap dispatch: if the page is loaded mid-scroll past the active\n    // threshold, fire card-active so already-on-screen content animates.\n    // Deferred so the dispatch happens after this init loop completes and\n    // child subscribers from other features are registered. Set the gate\n    // synchronously so the deferred fire doesn't fail the edge check, and\n    // so subsequent forward crossings (e.g. after a small scroll-up) don't\n    // re-dispatch before a full inactive reset. Tracked so `destroy()` mid-\n    // tick cancels the pending dispatch before it hits a torn-down DOM.\n    if (window.scrollY >= eventActiveAt()) {\n      isActive = true\n      const bootstrap = gsap.delayedCall(0, () => emitTrigger(card, 'card-active'))\n      cleanups.push(() => bootstrap.kill())\n    }\n\n    // Visual transforms are skipped under reduced motion; the event triggers\n    // above still fire so children's own animations (which honour reduced\n    // motion themselves) run on schedule.\n    if (reduceMotion) return\n\n    // Fade scrubs only over the *first half* of the entry travel, so the card\n    // reads as fully arrived well before it reaches its sticky lock — the\n    // remaining scale / rotation then settle it the rest of the way. Split into\n    // its own tween because a single scrubbed fromTo maps every property to the\n    // same progress; opacity needs to finish earlier than scale / rotation.\n    if (inFlags.has('fade')) {\n      const fadeEnd = (): number => (entryStart() + lockPoint()) / 2\n      const fadeTween = gsap.fromTo(\n        card,\n        { opacity: 0 },\n        {\n          opacity: 1,\n          ease: 'power1.in',\n          immediateRender: false,\n          scrollTrigger: { trigger: card, start: entryStart, end: fadeEnd, scrub },\n        },\n      )\n      cleanups.push(() => fadeTween.kill())\n    }\n\n    const rot = rotationPair(rotateMode, tiltMode, index, intensity)\n    const inFrom = buildInFrom(inFlags, intensity, rot.from)\n    if (Object.keys(inFrom).length > 0) {\n      const tween = gsap.fromTo(card, inFrom, {\n        ...buildInTo(inFlags, rot.to),\n        ease: 'power1.in',\n        // Defer the from-state until ScrollTrigger's first refresh tick.\n        // Without this, gsap.fromTo applies `rotation: ±15°` synchronously\n        // during this feature's init — and the text feature, which inits\n        // afterward in the same tick, then runs SplitText against a rotated\n        // card. SplitText measures per-character positions to group lines;\n        // on a rotated element each character sits at a different rotated\n        // y-coordinate, so every word ends up on its own line. ScrollTrigger\n        // refreshes after init completes, so this only postpones the visual\n        // by one tick — no perceptible flash.\n        immediateRender: false,\n        scrollTrigger: {\n          trigger: card,\n          start: entryStart,\n          end: lockPoint,\n          scrub,\n        },\n      })\n      cleanups.push(() => tween.kill())\n    }\n\n    if (lockFlags.size > 0) {\n      const trigger = ScrollTrigger.create({\n        trigger: card,\n        start: lockPoint,\n        onEnter: () => playLock(gsap, card, lockFlags),\n      })\n      cleanups.push(() => trigger.kill())\n    }\n\n    // Out tween: scrubbed over the *next* card's entry window. The last card\n    // has nothing to be overlaid by, so it holds its settled state. The start\n    // is clamped to this card's lock point so out never begins while the in\n    // is still scrubbing — when D >= innerHeight - stickyTop the clamp is\n    // inert (behavior unchanged); when cards are closer than that, out\n    // begins exactly when in finishes, so the in's target value and the\n    // out's recorded from-state agree at the handoff. Without the clamp,\n    // pairings that share a property (e.g. `stack-in=\"scale\"` +\n    // `stack-out=\"perspective\"`, which both write `scale`) fight for the\n    // property on every scroll tick and snap visibly at activation.\n    if (outFlags.size > 0 && index < cards.length - 1) {\n      const nextCard = cards[index + 1]\n      const outStart = (): number =>\n        Math.max(\n          geometry.tops[index + 1] - window.innerHeight,\n          geometry.tops[index] - geometry.stickyTop,\n        )\n      const outEnd = (): number => geometry.tops[index + 1] - geometry.stickyTop\n      const tween = gsap.to(card, {\n        ...buildOutTo(outFlags, intensity),\n        ease: 'power1.in',\n        scrollTrigger: {\n          trigger: nextCard,\n          start: outStart,\n          end: outEnd,\n          scrub,\n          // The perspective / blur `y` lift is a percentage of card height;\n          // re-resolve it to px on refresh so it tracks the card as it resizes.\n          invalidateOnRefresh: true,\n        },\n      })\n      cleanups.push(() => tween.kill())\n    }\n\n    // Last-card cover finisher (see the `coverEnabled` setup above). Scrubs the\n    // final card up by half the perspective lift over the trailing margin\n    // runway, 1:1 with scroll so it reads as natural continued scrolling. The\n    // last card has no out tween and its in tween never writes `y`, so this owns\n    // `y` exclusively — no property fight. The z-index ladder already puts it on\n    // top, so the lift cleanly covers the receded card behind it.\n    if (coverEnabled && index === cards.length - 1) {\n      const coverStart = (): number => geometry.tops[index] - geometry.stickyTop\n      const coverEnd = (): number => geometry.tops[index] - geometry.stickyTop + coverLiftPx()\n      const tween = gsap.to(card, {\n        y: `${-COVER_PCT * intensity}%`,\n        ease: 'none',\n        scrollTrigger: {\n          trigger: card,\n          start: coverStart,\n          end: coverEnd,\n          scrub,\n          // `y` is a height percentage and the margin runway / end are px from\n          // `offsetHeight`; re-resolve all of them together on refresh.\n          invalidateOnRefresh: true,\n        },\n      })\n      cleanups.push(() => tween.kill())\n    }\n  })\n\n  return () => {\n    try {\n      for (const fn of cleanups) fn()\n    } catch {\n      // best-effort — partial teardown is acceptable since the feature is\n      // also reverted by the surrounding gsap.matchMedia scope on destroy.\n    }\n  }\n}\n\nconst stackFeature: FeatureModule = {\n  name: 'stack',\n  init(ctx: FeatureContext): () => void {\n    bindRootFeature(ctx, 'aa-stack', setupOne)\n    return () => {}\n  },\n}\n\nexport default stackFeature\n","import type { FeatureContext, FeatureModule } from '../core/registry'\nimport { readAttrs } from '../core/settings'\nimport { applySplit, parseSplit } from './runtime'\n\nfunction shouldSkip(el: Element): boolean {\n  // The text feature handles its own split.\n  const animate = el.getAttribute('aa-animate') ?? ''\n  for (const part of animate.split('|')) {\n    if (part.trim().startsWith('text-')) return true\n  }\n  for (const bp of ['sm', 'md', 'lg', 'xl']) {\n    const v = el.getAttribute(`aa-animate-${bp}`)\n    if (v && v.startsWith('text-')) return true\n  }\n  // The hover 'text' head owns its own split via applySplit inside\n  // setupTextHover. Skip those elements so the split feature doesn't\n  // double-split them. Match exactly `text` — the hover parser doesn't\n  // recognize any other text-* head, so over-matching would silently\n  // suppress aa-split on typo'd hover values.\n  const hover = el.getAttribute('aa-hover') ?? ''\n  for (const part of hover.split('|')) {\n    if (part.trim().split(/\\s+/)[0] === 'text') return true\n  }\n  for (const bp of ['sm', 'md', 'lg', 'xl']) {\n    const v = el.getAttribute(`aa-hover-${bp}`)\n    if (v && v.trim().split(/\\s+/)[0] === 'text') return true\n  }\n  return false\n}\n\nconst splitFeature: FeatureModule = {\n  name: 'split',\n  init(ctx: FeatureContext): () => void {\n    const subjects = ctx.elements.filter(\n      (el) => el.hasAttribute('aa-split') && !shouldSkip(el),\n    )\n    for (const element of subjects) {\n      const attrs = readAttrs(element)\n      ctx.responsive.bind(element, attrs, ({ config }) => {\n        const split = parseSplit(config['aa-split'])\n        if (!split) return\n        const result = applySplit(element, split.mode, ctx.gsap, {\n          mask: split.mask,\n          index: split.index,\n        })\n        return () => result.revert()\n      })\n    }\n    return () => {}\n  },\n}\n\nexport default splitFeature\n"],"names":["PLUGIN_GLOBAL_NAMES","detectGsap","requiredPlugins","debug","w","gsap","plugins","missing","name","globalName","plugin","n","VALUE_BEARING_ATTRS","SUFFIX_KEYS","readAttrs","el","presetEntry","buckets","bucket","k","b","getValue","real","attr","baseValue","parts","bp","v","ACCUM_KEYS","configsEqual","a","ak","bk","buildRangeQuery","from","to","resolveRanges","breakpoints","perRange","r","merged","groups","last","result","g","reduceBucket","baseBucket","bucketForWidth","width","resolveAttrAtWidth","value","createResponsiveController","gsapHandle","mm","element","attrs","run","ranges","query","config","cleanup","NAMED_EASES","VALID_BARE_KEYS","out","bare","ANIMATE_KEYS","normalise","warnUnknown","bareKey","hasAnyAaAttr","hasAnimate","resolved","resolvePresets","root","presets","seenUnknown","key","className","selector","matched","resolveAnimateValue","presetMap","matchAnimateValue","predicate","preset","base","part","resolveScrollStart","attrValue","opts","scrub","bindAgainTrigger","ScrollTrigger","triggers","rect","matrix","t","parseNum","fallback","parseScrub","parseBool","resolveAnchor","anchor","ANIMATE_ATTRS","hasAnimateAttribute","readAnimationConfig","LINE_DEFAULT_TEXT","textWantsLineMetrics","animateValue","splitValue","head","tokens","HOVER_ATTRS","hoverWantsSplitText","ANIMATE_TO_FEATURE","classifyAnimateValue","pattern","feature","ANCHOR_TO_FEATURE","scan","features","elements","needsHoverSplit","needsFontMetrics","combinedSelector","isLoadKind","kind","CUSTOM_EVENT_NAME","MODAL_CARD_SELECTOR","MODAL_STATUS_ATTR","REVERSE_TIME_SCALE","REVERSE_EASE","parseOne","token","parseTriggers","trimmed","parsed","INFERENCE_CONTAINERS","containerDisabled","container","def","resolveTriggers","explicit","best","match","listeners","attached","onCustomEvent","fn","ensureAttached","onCustomTrigger","emitTrigger","target","pairedReverseName","eventName","subscribeWithPair","forwardName","onForward","onReverse","reverseName","runFadeFallbackPass","deps","options","reducedMotion","firstInit","fadeFor","deferLoadStart","duration","ease","fromState","toState","listenerDisposers","getAttr","gsapCtx","classified","delay","scrollEnd","scrollStart","hasLoadOnce","hasLoad","tween","trigger","off","REDUCED_MOTION_REPLACED_FEATURES","REDUCED_MOTION_FADE_FEATURES","OPTIMIZE_MOBILE_REPLACED_FEATURES","OPTIMIZE_MOBILE_FADE_FEATURES","loaders","index$b","index$a","reveal","slices","index$9","index$8","index$7","index$6","index$5","index$4","index$3","index$2","index$1","index","loadFeature","loader","err","loadFeatures","names","m","bindFeature","ctx","matches","setupOne","subjects","bindRootFeature","resolveAttrs","subscribers","dispatch","sub","attach","detachIfEmpty","subscribe","debounce","clearAll","DIRECTION_THRESHOLD","STARTED_THRESHOLD","initScrollDirection","body","lastScrollTop","lastDirection","lastStarted","ticking","apply","currentScrollTop","direction","started","onScroll","initPlayStateObserver","observer","entries","entry","children","child","animations","animation","initScrollState","directionDispose","playStateDispose","QUART_EASE","x","DEFAULT_DURATION","initScrollTarget","e","targetSelector","offset","lenis","top","DEFAULT_BREAKPOINTS","DEFAULT_STAGGER","DEFAULT_AUTOPLAY","DEFAULT_REDUCED_MOTION","DEFAULT_OPTIMIZE_MOBILE_FADE","DEFAULT_OPTIONS","resolveReducedMotion","input","resolveOptions","state","resolveBreakpoints","readyDeferred","newReadyDeferred","resolve","getReadyPromise","resolveReady","addDisposer","runAllDisposers","initSmoothScroll","Lenis","updateScrollTrigger","tickerFn","time","activeHandles","FONT_METRICS_TIMEOUT_MS","detectReducedMotion","setting","detectOptimizeMobile","mdBreakpoint","deviceHasHover","registerCustomEases","handle","CustomEase","path","init","optimizeMobile","replacedFeatures","fadeFeatures","effectiveFeatures","needsFadePass","f","timedOut","smoothScrollOpt","responsive","loadGate","gateCancelled","fadeTiming","disposeFade","featureModules","featureCtx","subscribeResize","mod","dispose","lenisActive","loadedFeatures","droppedFeatures","replacedBy","featuresLabel","flush","destroy","clearResize","refresh","onResize","api","defaultStaggerFor","splitMode","VALID_FROM","defaultFlags","parseStaggerSpec","lineFallback","flags","numerics","unit","line","buildStagger","groupSize","ranks","_target","list","_","i","j","collectStaggerTargets","c","targets","staggerSpec","stagger","toTimelineVars","vars","easeReverse","rest","WILL_CHANGE_TRANSFORM_KEYS","cssWillChange","props","hasTransform","setupTriggeredAnimation","isLoadOneShot","persistentTrigger","triggerEl","loadDelay","currentAnim","currentExtraCleanup","triggerPlayed","loadFired","loadCompleted","wc","wcEls","collectTargets","anim","loose","setWillChange","clearWillChange","killCurrent","buildVars","rebuild","wasFired","prevProgress","built","resume","triggerCleanup","FROM_FOR","STATIC_SUPPORTED","ROTATE_PATTERN","CORNER_TO_ORIGIN","isRotateValue","buildRotateFromState","intensity","ccw","cornerMatch","corner","up","buildFromState","animate","builder","isSupportedValue","elementMatches","again","isLcp","ARIA_LABEL_ALLOWED","tagAllowsAriaLabel","FOCUSABLE_DESCENDANT_SELECTOR","hasFocusableDescendant","parseSplit","modeToken","mode","groupBy","mask","applySplit","SplitTextCtor","splitOpts","onResplit","initialFired","inst","allowAriaLabel","srSpan","priorAriaHidden","didHide","text","OVAL_LINE_STYLE","PERSPECTIVE_LINE_STYLE","wrapLines","lines","inlineStyle","perElement","wrappers","wrapper","unwrapLines","DIR_AXIS","fadeAnim","opacity","prop","sign","blurAnim","offsetProp","scaleAnim","origin","slideAnim","tiltAnim","ovalAnim","at","split","TEXT_ANIMS","perspective","BAR_DIRECTIONS","BAR_NAMES","dirName","parseBarName","resolveBarColor","buildBarLines","color","withTextWrapper","setups","bar","SUPPORTED","pickSimpleTargets","setupBarReveal","dir","isBlock","scaleProp","buildTimelineFromSetups","tl","lineTl","revealDur","shrinkDur","textDur","initialSplit","newSplit","userSplit","lineStagger","lineGrouped","extraCleanup","lineGroups","simple","inner","u","group","REVEAL_CLIPS","CLIP_VARIANTS","isSupported","DIRECTIONS","parseSlicesValue","dirToken","rows","AXIS","buildSlicesPanel","axis","cs","prevPosition","prevOverflow","panel","fragment","overlap","slice","params","fromScale","toScale","setup","startVal","endVal","parseAutoplay","raw","defaults","attrPresent","intervalDefault","baseInterval","interval","hoverPause","hoverSlow","hasVisualAnimation","visual","emitOnTargets","createAnimationController","pendingVisualOpen","openHeight","content","onComplete","startHeight","closeHeight","showVisual","hideVisual","visualEl","fireVisual","tabsInstanceCounter","shapeFor","instanceId","accordion","tab","toggleId","contentId","visualId","createAriaController","shapes","undo","setAttrTracked","had","prev","setAttrIfMissing","shape","parent","createProgressEntry","attrName","fallbackEase","set","circle","circumference","property","progressFromValues","progressToValues","progressSetFill","fraction","clamped","createProgressGroup","gsapLoose","activeIndex","durationFor","createViewportGate","modalCard","st","attachHoverPauseListener","setupAutoplay","autoplayCall","isPausedByHover","isHovering","currentIdx","progressByIdx","progress","dwellFor","tick","next","dwell","start","stop","sync","idx","pauseByHover","resumeFromHover","cleanups","onIdle","onActive","gateDispose","ACTIVATE_KEYS","NAV_KEYS","attachKeyboard","toggles","handlers","onKey","toggle","setupScroll","N","totalDistance","dummyProgress","dummyTween","p","newIdx","fill","distancePerSegment","targetY","proxy","parseTabsValue","isNone","STATUS_ATTR","autoAssignIds","id","readDuration","readEase","readInterval","createTabState","useWrapperPattern","byId","rootDuration","rootEase","rootInterval","toggleDuration","toggleEase","toggleInterval","contentDuration","visualDuration","hasContent","hasVisualOnly","statusEl","isActive","status","matchingToggle","wrapperToggle","TABS_STATUS_ATTR","defaultDuration","defaultEase","autoplay","aria","refreshCall","debouncedRefresh","openEntry","visualDelay","closeEntry","openEntrySnap","autoplayCtl","scrollCtrl","initialEntry","handleToggle","active","onClick","scrubAttr","parseMarqueeValue","CLONE_STRIPPED_ATTRS","CLONE_CLEARED_STYLES","clearFromState","sanitizeClone","clone","animated","desc","HOVER_SLOW_FACTOR","fillTrack","track","rootWidth","cycleDistance","scrubOvershootPx","clones","minRequiredWidth","safety","isPlaying","scroller","scrubValue","wantsScrub","isScrub","scrubTravelPct","Draggable","InertiaPlugin","measureCycle","activeLoop","builtCycle","buildInner","halfSweepPx","originalScrollerMarginLeft","wrapX","loop","baseDirection","timeScale","lastSwitchDirection","lastDirectionAttr","hoverFactor","applyTimeScale","ts","sweepPx","startX","endX","scrubTween","draggable","wrap","ratio","startProgress","throwDirection","cruiseVelPxPerS","prevThrowX","prevThrowT","handedOff","align","resumeLoop","now","dt","pausedByHover","rampTo","newDirection","mo","mutations","teardownInner","rebuildTimer","forceRebuild","scheduleRebuild","force","doForce","ro","offResize","mergeScrollerAttrs","scrollerAttrs","travel","parseNavValue","setupHideAndChange","navElement","hiddenY","shouldHide","hidden","threshold","hasClass","update","past","setupCurrentLinkTracking","navItems","navItem","section","setCurrent","item","clearCurrent","setupSectionClasses","sections","allClasses","cls","sectionClass","end","setActive","clearActive","readIndicatorConfig","indicator","getCurrentItem","items","setupCurrentIndicator","Flip","cfg","lastCurrentItem","mutation","setupHoverIndicator","animateTo","durationOverride","enterHandlers","onNavLeave","navElements","disposers","d","observeSize","onChange","lastWidth","timer","slider","advance","dragInProgress","progressEntries","syncProgress","reset","attachTouchScrollGuard","onStaticRelease","touchStartX","touchStartY","isDragInitialized","disabledForScroll","handleTouchStart","handleTouchMove","deltaX","handleTouchEnd","finiteTrack","rawItems","length","center","fallbackDuration","minX","maxX","curIndex","lastIndex","currentX","indexIsDirty","measuredHidden","clamp","min","max","getPropX","getClosestIndex","closest","xForIndex","populate","containerWidth","startLeft","contentWidth","slideLeft","applyX","fireChange","closestIndex","current","moveTween","toIndex","targetX","wasHidden","drag","seatIndex","wasThrowing","nativeKill","horizontalLoop","times","widths","spaceBefore","xPercents","pixelsPerSecond","snap","timeOffset","totalWidth","getTotalWidth","populateWidths","b1","b2","timeWrap","populateOffsets","_t","getClosest","values","populateTimeline","curX","distanceToStart","distanceToLoop","deep","newIndex","lastSnap","initChangeX","wasPlaying","syncIndex","wrappedTime","dif","HANDLED_KEYS","total","hadTabindex","sliderInstanceCounter","setupNav","sliderIdPrefix","nextButton","prevButton","currentEl","totalEl","internalThumbs","externalThumbs","thumbs","slide","btn","formatIndex","_item","rawIndex","wasActive","disabled","add","evt","parseSliderValue","firstItemParent","gap","nav","initialOnChange","handleChange","restartAutoplayAfterManualNav","isThrowing","afterManualNav","navHandlers","remeasure","BACKDROP_DURATION","cardHasAnimate","card","backdrop","cardDuration","cardWall","backdropDelay","totalWait","FOCUSABLE_SELECTOR","INPUT_SELECTOR","getFocusable","getFirstInput","trapFocus","onKeydown","focusable","first","focusFirst","firstInput","ACCESSIBLE_NAME_MAX","deriveAccessibleName","node","cut","applyDialogSemantics","markDialogTriggers","attachEsc","onEsc","LOCK_CLASS","lockCount","lockBodyScroll","unlockBodyScroll","resetScrollLock","MODAL_GROUP_STATUS_ATTR","createModalState","cards","byName","parseDuration","groupDuration","detachTrap","detachEsc","pendingOpenFocus","onDocClick","onGroupClick","closer","VALID_MODES","parseDirectionMode","defaultEdge","detectEdge","event","y","h","edge","prepareHost","host","restore","computed","restoreHost","ensurePositioned","BLOCK_TRANSFORM","setupBlockHover","settings","bg","onEnter","onLeave","SVG_NS","CURVE_FROM_PATHS","computeLeavePath","scoop","fillY","ctrlY","fillX","ctrlX","setupCurveHover","svg","ICON_DIRECTIONS","ICON_MAP","scaleOffset","multiplier","scaleMotion","motion","setupIconHover","icon","map","cloneCount","createUnderlineBar","setupUnderlineSweep","half","setupUnderlineIn","inActive","outActive","pendingLeave","pendingEnter","runIn","runOut","remainingAt1x","setupUnderlineHover","prepareTextHost","restoreTextHost","setupTextHover","restoreState","clipOverride","shift","units","applyShadows","els","clearShadows","pickUnits","buildTimeline","parseHoverValue","HOVER_DEFAULTS","buildTriggerMap","triggerMap","DEFAULT_X_OFFSET","DEFAULT_Y_OFFSET","X_EDGE_OFFSET","Y_EDGE_OFFSET","EDGE_BUFFER","RESERVED_TRIGGER_PARTS","SHOW_DURATION","HIDE_DURATION","FOLLOW_EASE","SHOW_EASE","HIDE_EASE","OFFSET_EASE","OFFSET_DURATION","snapshot","getCursorAttributes","parseCursorOffset","cursorName","warn","reason","createCursorInstance","cursorEl","cursorInner","xOffset","yOffset","cursorSnap","innerSnap","slotCache","getSlot","cached","found","nextKeys","slot","img","cursorEdgeThreshold","xPercent","yPercent","fallDistance","randomRotation","queued","elUnderMouse","currentPointerX","currentPointerY","cursorEls","cursors","rafId","onMouseMove","triggerHandlers","IN_FLAGS","LOCK_FLAGS","OUT_FLAGS","parseFlags","valid","rotationForIndex","modeFor","prefix","rotationPair","rotateMode","tiltMode","buildInFrom","rotation","buildInTo","buildOutTo","playLock","captureGeometry","stickyTop","saved","tops","cur","parseViewportFraction","second","inFlags","lockFlags","outFlags","eventFraction","geometry","reduceMotion","COVER_PCT","lastCard","coverEnabled","coverLiftPx","savedMargin","applyCoverRunway","onRefreshInit","entryStart","lockPoint","eventActiveAt","eventResetAt","activeTrigger","inactiveTrigger","bootstrap","fadeEnd","fadeTween","rot","inFrom","nextCard","outStart","outEnd","coverStart","coverEnd","shouldSkip","hover"],"mappings":"yOA+FA,MAAMA,GAA8C,CAClD,cAAe,gBACf,UAAW,YACX,UAAW,YACX,cAAe,gBACf,KAAM,OACN,WAAY,YACd,EAEO,SAASC,GACdC,EAA4B,GAC5BC,EAAQ,GACW,CACnB,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,MAAMC,EAAI,OACJC,EAAOD,EAAE,KACf,GAAI,CAACC,GAAQ,OAAOA,EAAK,gBAAmB,WAC1C,OAAIF,GACF,QAAQ,KACN,0FAAA,EAGG,KAET,MAAMG,EAAmC,CAAA,EACnCC,EAAoB,CAAA,EAC1B,UAAWC,KAAQN,EAAiB,CAClC,MAAMO,EAAaT,GAAoBQ,CAAI,GAAKA,EAC1CE,EAASN,EAAEK,CAAU,EAC3B,GAAIC,EAAQ,CACVJ,EAAQE,CAAI,EAAIE,EAChB,GAAI,CACFL,EAAK,eAAeK,CAAM,CAC5B,MAAQ,CAER,CACF,MACEH,EAAQ,KAAKC,CAAI,CAErB,CACA,OAAID,EAAQ,OAAS,GAAKJ,GACxB,QAAQ,KACN,yCAAyCI,EAAQ,KAAK,IAAI,CAAC,6DAAA,EAGxD,CACL,KAAAF,EACA,QAAAC,EACA,IAAMK,GAAcA,KAAKL,CAAA,CAE7B,CC/IO,MAAMM,GAAsB,CACjC,aACA,aACA,WACA,aACA,cACA,WACA,UACA,eACA,kBACA,gBACA,WACA,YACA,WACA,oBACA,kBACA,YACA,UACA,aACA,sBACA,cACA,SACA,WACA,WACA,WACA,cACA,gBACA,cACF,EAIaC,GAAwC,CAAC,KAAM,KAAM,KAAM,IAAI,EAUrE,SAASC,EACdC,EACAC,EACe,CACf,MAAMC,MAAc,IACdC,EAAUC,GAAyB,CACvC,IAAIC,EAAIH,EAAQ,IAAIE,CAAC,EACrB,OAAKC,IACHA,EAAI,CAAA,EACJH,EAAQ,IAAIE,EAAGC,CAAC,GAEXA,CACT,EAGMC,EAAYb,GAAgC,CAChD,MAAMc,EAAOP,EAAG,aAAaP,CAAI,EACjC,OAAIc,IAAS,KAAaA,EACnBN,GAAa,IAAIR,CAAI,GAAK,IACnC,EAEA,UAAWe,KAAQX,GAAqB,CACtC,MAAMY,EAAYH,EAASE,CAAI,EAC/B,GAAIC,IAAc,KAAM,CACtB,MAAMC,EAAQD,EAAU,MAAM,GAAG,EAC7BC,EAAM,SAAW,GACnBP,EAAO,MAAM,EAAEK,CAAI,EAAIE,EAAM,CAAC,EAAE,KAAA,EAChCP,EAAO,IAAI,EAAEK,CAAI,EAAIE,EAAM,CAAC,EAAE,KAAA,GAE9BP,EAAO,MAAM,EAAEK,CAAI,EAAIC,CAE3B,CACA,UAAWE,KAAMb,GAAa,CAC5B,MAAMc,EAAIN,EAAS,GAAGE,CAAI,IAAIG,CAAE,EAAE,EAC9BC,IAAM,OAAMT,EAAOQ,CAAE,EAAEH,CAAI,EAAII,EACrC,CACF,CAEA,MAAO,CAAE,QAAAV,CAAA,CACX,CAYA,MAAMW,GAA4C,CAChD,KAAM,CAAC,MAAM,EACb,GAAI,CAAC,OAAQ,IAAI,EACjB,GAAI,CAAC,OAAQ,KAAM,IAAI,EACvB,GAAI,CAAC,OAAQ,KAAM,KAAM,IAAI,EAC7B,GAAI,CAAC,OAAQ,KAAM,KAAM,KAAM,IAAI,CACrC,EAEA,SAASC,GAAaC,EAAWV,EAAoB,CACnD,MAAMW,EAAK,OAAO,KAAKD,CAAC,EAClBE,EAAK,OAAO,KAAKZ,CAAC,EACxB,GAAIW,EAAG,SAAWC,EAAG,OAAQ,MAAO,GACpC,UAAWb,KAAKY,EACd,GAAID,EAAEX,CAAc,IAAMC,EAAED,CAAc,EAAG,MAAO,GAEtD,MAAO,EACT,CAEA,SAASc,GAAgBC,EAAcC,EAAoB,CACzD,OAAID,GAAQ,GAAKC,IAAO,IAAiB,MACrCD,GAAQ,EAAU,eAAeC,EAAK,GAAI,MAC1CA,IAAO,IAAiB,eAAeD,CAAI,MACxC,eAAeA,CAAI,uBAAuBC,EAAK,GAAI,KAC5D,CAOO,SAASC,GACdnB,EACAoB,EACiB,CASjB,MAAMC,EAR6D,CACjE,CAAE,IAAK,OAAQ,KAAM,EAAG,GAAID,EAAY,EAAA,EACxC,CAAE,IAAK,KAAM,KAAMA,EAAY,GAAI,GAAIA,EAAY,EAAA,EACnD,CAAE,IAAK,KAAM,KAAMA,EAAY,GAAI,GAAIA,EAAY,EAAA,EACnD,CAAE,IAAK,KAAM,KAAMA,EAAY,GAAI,GAAIA,EAAY,EAAA,EACnD,CAAE,IAAK,KAAM,KAAMA,EAAY,GAAI,GAAI,GAAA,CAAS,EAG1B,IAAKE,GAAM,CACjC,MAAMC,EAAiB,CAAA,EACvB,UAAWrB,KAAKS,GAAWW,EAAE,GAAG,EAAG,CACjC,MAAMnB,EAAIH,EAAQ,IAAIE,CAAC,EACnBC,GAAG,OAAO,OAAOoB,EAAQpB,CAAC,CAChC,CACA,MAAO,CAAE,GAAGmB,EAAG,OAAQC,CAAA,CACzB,CAAC,EAEKC,EAA6E,CAAA,EACnF,UAAWF,KAAKD,EAAU,CACxB,MAAMI,EAAOD,EAAOA,EAAO,OAAS,CAAC,EACjCC,GAAQb,GAAaa,EAAK,OAAQH,EAAE,MAAM,EAC5CG,EAAK,GAAKH,EAAE,GAEZE,EAAO,KAAK,CAAE,GAAGF,EAAG,OAAQ,CAAE,GAAGA,EAAE,MAAA,EAAU,CAEjD,CAEA,MAAMI,EAA0BF,EAAO,IAAKG,IAAO,CACjD,OAAQA,EAAE,IACV,MAAOX,GAAgBW,EAAE,KAAMA,EAAE,EAAE,EACnC,OAAQA,EAAE,MAAA,EACV,EAEIC,EAAe5B,EAAQ,IAAI,QAAQ,EACzC,GAAI4B,EAAc,CAChB,MAAMC,EAAa7B,EAAQ,IAAI,MAAM,GAAK,CAAA,EAC1C0B,EAAO,KAAK,CACV,OAAQ,SACR,MAAO,mCACP,OAAQ,CAAE,GAAGG,EAAY,GAAGD,CAAA,CAAa,CAC1C,CACH,CAEA,OAAOF,CACT,CAEA,SAASI,GAAeC,EAAeX,EAAoC,CACzE,OAAIW,GAASX,EAAY,GAAW,KAChCW,GAASX,EAAY,GAAW,KAChCW,GAASX,EAAY,GAAW,KAChCW,GAASX,EAAY,GAAW,KAC7B,MACT,CAMO,SAASY,GACdlC,EACAQ,EACAyB,EACAX,EACoB,CACpB,KAAM,CAAE,QAAApB,CAAA,EAAYH,EAAUC,CAAE,EAChC,IAAImC,EACJ,UAAW/B,KAAKS,GAAWmB,GAAeC,EAAOX,CAAW,CAAC,EAAG,CAC9D,MAAMjB,EAAIH,EAAQ,IAAIE,CAAC,EACnBC,GAAKA,EAAEG,CAAI,IAAM,SAAW2B,EAAQ9B,EAAEG,CAAI,EAChD,CACA,OAAO2B,CACT,CC9KO,SAASC,GACdC,EACAf,EACsB,CACtB,MAAMgB,EAAqBD,EAAW,KAAK,WAAA,EAoB3C,MAAO,CAAE,KAlBkC,CAACE,EAASC,EAAOC,IAAQ,CAClE,MAAMC,EAASrB,GAAcmB,EAAM,QAASlB,CAAW,EACvD,SAAW,CAAE,OAAAnB,EAAQ,MAAAwC,EAAO,OAAAC,CAAA,IAAYF,EACtCJ,EAAG,IAAIK,EAAO,IAAM,CAClB,MAAME,EAAUJ,EAAI,CAAE,QAAAF,EAAS,OAAAK,EAAQ,OAAAzC,EAAQ,EAC/C,OAAO,OAAO0C,GAAY,WAAaA,EAAU,MACnD,CAAC,CAEL,EAUe,UARG,IAAY,CAC5BP,EAAG,OAAA,CACL,EAM0B,QAJV,IAAY,CAC1BA,EAAG,KAAA,CACL,CAE0B,CAC5B,CCnDO,MAAMQ,GAAsC,CACjD,KAAM,2BACN,OAAQ,0BACR,OAAQ,+BACR,MAAO,0BACP,QAAS,wBACT,KAAM,2BACN,IAAK,+BACL,QACE,yvBACF,WAAY,2BACZ,OACE,6IACF,KAAM,2BACR,ECPMC,IAAmB,IAAM,CAC7B,MAAMC,MAAU,IAChB,UAAWxC,KAAQX,GAAqB,CACtC,MAAMoD,EAAOzC,EAAK,MAAM,CAAC,EACzBwC,EAAI,IAAIC,CAAI,EACZ,UAAWtC,KAAMb,GAAakD,EAAI,IAAI,GAAGC,CAAI,IAAItC,CAAE,EAAE,CACvD,CACA,OAAOqC,CACT,GAAA,EAEME,IAAgB,IAAM,CAC1B,MAAMF,EAAM,CAAC,YAAY,EACzB,UAAWrC,KAAMb,GAAakD,EAAI,KAAK,cAAcrC,CAAE,EAAE,EACzD,OAAOqC,CACT,GAAA,EAEA,SAASG,GAAUhB,EAAoBiB,EAAqD,CAC1F,MAAMJ,MAA0B,IAChC,GAAI,OAAOb,GAAU,SACnB,OAAAa,EAAI,IAAI,aAAcb,CAAK,EACpBa,EAET,SAAW,CAACK,EAASzC,CAAC,IAAK,OAAO,QAAQuB,CAAK,EAAG,CAChD,GAAI,CAACY,GAAgB,IAAIM,CAAO,EAAG,CACjCD,IAAcC,CAAO,EACrB,QACF,CACIzC,GAAK,MACToC,EAAI,IAAI,MAAMK,CAAO,GAAI,OAAOzC,CAAC,CAAC,CACpC,CACA,OAAOoC,CACT,CAEA,SAASM,GAAatD,EAAsB,CAC1C,UAAWP,KAAQO,EAAG,oBACpB,GAAIP,EAAK,WAAW,KAAK,EAAG,MAAO,GAErC,MAAO,EACT,CAEA,SAAS8D,GAAWC,EAAmC,CACrD,UAAWpD,KAAK8C,GACd,GAAIM,EAAS,IAAIpD,CAAC,EAAG,MAAO,GAE9B,MAAO,EACT,CAEO,SAASqD,GACdC,EACAC,EACAvE,EAAQ,GACsB,CAC9B,MAAMwC,MAAa,IACnB,GAAI,CAAC+B,EAAS,OAAO/B,EAErB,MAAMgC,MAAkB,IAClBR,EAAchE,EACfyE,GAAgB,CACXD,EAAY,IAAIC,CAAG,IACvBD,EAAY,IAAIC,CAAG,EACnB,QAAQ,KACN,+BAA+BA,CAAG,0DAA0D,CAAC,GAAGd,EAAe,EAAE,KAAA,EAAO,KAAK,IAAI,CAAC,EAAA,EAEtI,EACA,OAEJ,SAAW,CAACe,EAAW3B,CAAK,IAAK,OAAO,QAAQwB,CAAO,EAAG,CACxD,MAAMH,EAAWL,GAAUhB,EAAOiB,CAAW,EAC7C,GAAII,EAAS,OAAS,EAAG,SACzB,GAAI,CAACD,GAAWC,CAAQ,EAAG,CACrBpE,GACF,QAAQ,KACN,2BAA2B0E,CAAS,qGAAA,EAGxC,QACF,CACA,IAAIC,EACJ,GAAI,CACFA,EAAW,IAAM,IAAI,OAAOD,CAAS,CACvC,MAAQ,CACN,QACF,CACA,IAAIE,EAAU,EACd,UAAWhE,KAAM0D,EAAK,iBAAiBK,CAAQ,EACzCnC,EAAO,IAAI5B,CAAE,GACbsD,GAAatD,CAAE,IACnB4B,EAAO,IAAI5B,EAAIwD,CAAQ,EACvBQ,KAEE5E,GAAS4E,IAAY,GACvB,QAAQ,KAAK,2BAA2BF,CAAS,uBAAuB,CAE5E,CACA,OAAOlC,CACT,CAEO,SAASqC,GACdjE,EACAkE,EACe,CACf,OAAOlE,EAAG,aAAa,YAAY,GAAKkE,EAAU,IAAIlE,CAAE,GAAG,IAAI,YAAY,GAAK,IAClF,CAQO,SAASmE,GACdnE,EACAkE,EACAE,EACS,CACT,MAAMC,EAASH,EAAU,IAAIlE,CAAE,EACzBsE,EAAOtE,EAAG,aAAa,YAAY,GAAKqE,GAAQ,IAAI,YAAY,GAAK,KAC3E,GAAIC,GACF,UAAWC,KAAQD,EAAK,MAAM,GAAG,EAC/B,GAAIF,EAAUG,EAAK,KAAA,CAAM,EAAG,MAAO,GAGvC,UAAW5D,KAAMb,GAAa,CAC5B,MAAM+D,EAAM,cAAclD,CAAE,GACtBC,EAAIZ,EAAG,aAAa6D,CAAG,GAAKQ,GAAQ,IAAIR,CAAG,GAAK,KACtD,GAAIjD,GAAKwD,EAAUxD,EAAE,KAAA,CAAM,EAAG,MAAO,EACvC,CACA,MAAO,EACT,CC/GO,SAAS4D,GACdC,EACAC,EACAC,EACQ,CACR,OAAIF,IAAc,OAAkBA,EAIhCE,GAASD,EAAK,aAAe,OAAkBA,EAAK,WACjDA,EAAK,WACd,CA4BO,SAASE,GAAiBF,EAAuC,CACtE,MAAMG,EAAgBH,EAAK,KAAK,QAAQ,cACxC,GAAI,CAACG,EAAe,MAAO,IAAM,CAAC,EAElC,MAAMC,EAAoC,CAAA,EAE1C,OAAAA,EAAS,KACPD,EAAc,OAAO,CACnB,QAASH,EAAK,QACd,MAAOA,EAAK,MACZ,QAAS,IAAMA,EAAK,OAAA,CAAO,CAC5B,CAAA,EAGCA,EAAK,OACPI,EAAS,KACPD,EAAc,OAAO,CACnB,QAASH,EAAK,QACd,MAAO,IAAM,CACX,MAAMK,EAAOL,EAAK,QAAQ,sBAAA,EACpBM,EAAS,IAAI,UAAU,iBAAiBN,EAAK,OAAO,EAAE,SAAS,EACrE,OAAOK,EAAK,IAAM,OAAO,QAAUC,EAAO,EAAI,OAAO,WACvD,EACA,YAAa,IAAMN,EAAK,QAAA,CAAQ,CACjC,CAAA,EAIE,IAAM,CACX,UAAWO,KAAKH,EAAUG,EAAE,KAAA,CAC9B,CACF,CClFO,SAASC,EAAS/C,EAAkCgD,EAA0B,CACnF,GAA2BhD,GAAU,KAAM,OAAOgD,EAClD,MAAM,EAAI,WAAWhD,CAAK,EAC1B,OAAO,OAAO,SAAS,CAAC,EAAI,EAAIgD,CAClC,CAaO,SAASC,GACdjD,EAC2B,CAC3B,GAA2BA,GAAU,KAAM,OAC3C,GAAIA,IAAU,IAAMA,IAAU,OAAQ,MAAO,GAC7C,MAAMvC,EAAI,WAAWuC,CAAK,EAC1B,OAAO,OAAO,SAASvC,CAAC,EAAIA,EAAI,EAClC,CAQO,SAASyF,GACdlD,EACAgD,EACS,CACT,OAA2BhD,GAAU,KAAagD,EAC3ChD,IAAU,OACnB,CAOO,SAASmD,GAAc/C,EAAkBgD,EAAqC,CACnF,GAAI,CAACA,EAAQ,OAAOhD,EACpB,MAAMmB,EAAOnB,EAAQ,QAAQgD,CAAM,EACnC,OAAI7B,IACU,SAAS,cAAc6B,CAAM,GAC3BhD,EAClB,CAEA,MAAMiD,GAAgB,CACpB,aACA,gBACA,gBACA,gBACA,eACF,EAQO,SAASC,GAAoBzF,EAA6B,CAC/D,GAAI,CAACA,EAAI,MAAO,GAChB,UAAWQ,KAAQgF,GACjB,GAAIxF,EAAG,aAAaQ,CAAI,EAAG,MAAO,GAEpC,MAAO,EACT,CAoBO,SAASkF,GAAoB9C,EAAgB8B,EAAwC,CAC1F,MAAMC,EAAQS,GAAWxC,EAAO,UAAU,CAAC,EAC3C,MAAO,CACL,SAAUsC,EAAStC,EAAO,aAAa,EAAG8B,EAAK,QAAQ,EACvD,MAAOQ,EAAStC,EAAO,UAAU,EAAG,CAAC,EACrC,KAAMA,EAAO,SAAS,GAAK8B,EAAK,KAChC,UAAWQ,EAAStC,EAAO,cAAc,EAAG8B,EAAK,SAAS,EAC1D,UAAW9B,EAAO,eAAe,GAAK8B,EAAK,UAC3C,MAAAC,EACA,YAAaH,GAAmB5B,EAAO,iBAAiB,EAAG8B,EAAMC,CAAK,EACtE,MAAOU,GAAUzC,EAAO,UAAU,EAAG8B,EAAK,KAAK,CAAA,CAEnD,CC5EA,MAAMiB,GAAoB,8CAK1B,SAASC,GAAqBC,EAA6BC,EAAoC,CAC7F,GAAI,CAACD,EAAc,MAAO,GAC1B,MAAME,EAAOF,EAAa,MAAM,GAAG,EAAE,CAAC,EAAE,KAAA,EACxC,GAAI,CAACE,EAAK,WAAW,OAAO,EAAG,MAAO,GACtC,GAAID,EAAY,CACd,MAAME,EAASF,EAAW,YAAA,EAAc,MAAM,QAAQ,EACtD,GAAIE,EAAO,SAAS,OAAO,EAAG,MAAO,GACrC,GAAIA,EAAO,SAAS,OAAO,GAAKA,EAAO,SAAS,OAAO,EAAG,MAAO,EACnE,CACA,OAAOL,GAAkB,KAAKI,CAAI,CACpC,CAEA,MAAME,GAAc,CAAC,WAAY,cAAe,cAAe,cAAe,aAAa,EAK3F,SAASC,GAAoBlG,EAAsB,CACjD,GAAI,CAACA,EAAG,aAAa,UAAU,EAAG,MAAO,GACzC,UAAWQ,KAAQyF,GAAa,CAC9B,MAAMrF,EAAIZ,EAAG,aAAaQ,CAAI,EAC9B,GAAII,GAAKA,EAAE,MAAM,GAAG,EAAE,KAAM2D,GAASA,EAAK,KAAA,EAAO,MAAM,KAAK,EAAE,CAAC,IAAM,MAAM,EAAG,MAAO,EACvF,CACA,MAAO,EACT,CAEA,MAAM4B,GAAmD,CACvD,CAAC,SAAU,MAAM,EACjB,CAAC,YAAa,UAAU,EACxB,CAAC,UAAW,QAAQ,EACpB,CAAC,UAAW,QAAQ,CACtB,EAEO,SAASC,GAAqBjE,EAAmC,CACtE,GAAI,CAACA,EAAO,MAAO,SACnB,MAAM4D,EAAO5D,EAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAA,EACjC,SAAW,CAACkE,EAASC,CAAO,IAAKH,GAC/B,GAAIE,EAAQ,KAAKN,CAAI,EAAG,OAAOO,EAEjC,MAAO,QACT,CAIA,MAAMC,GAA0D,CAC9D,CAAC,UAAW,MAAM,EAClB,CAAC,aAAc,SAAS,EACxB,CAAC,SAAU,KAAK,EAChB,CAAC,YAAa,QAAQ,EACtB,CAAC,iBAAkB,OAAO,EAC1B,CAAC,gBAAiB,OAAO,EACzB,CAAC,kBAAmB,OAAO,EAC3B,CAAC,WAAY,OAAO,EACpB,CAAC,WAAY,OAAO,EACpB,CAAC,YAAa,QAAQ,EACtB,CAAC,WAAY,OAAO,CACtB,EAEO,SAASC,GACd9C,EAAmB,SACnBQ,EAA0C,IAAI,IAClC,CACZ,MAAMuC,MAAe,IACfC,MAAe,IACrB,IAAIC,EAAkB,GAClBC,EAAmB,GAIvB,MAAMC,EAAmB,CACvB,GAAGhH,GAAoB,IAAKkB,GAAM,IAAIA,CAAC,GAAG,EAC1C,GAAGwF,GAAkB,IAAI,CAAC,CAACxF,CAAC,IAAM,IAAIA,CAAC,GAAG,CAAA,EAC1C,KAAK,GAAG,EAEV,UAAWf,KAAM0D,EAAK,iBAAiBmD,CAAgB,EAAG,CACxDH,EAAS,IAAI1G,CAAE,EACf,MAAM6F,EAAe7F,EAAG,aAAa,YAAY,EAC7C6F,IAAiB,MAAMY,EAAS,IAAIL,GAAqBP,CAAY,CAAC,EAC1E,SAAW,CAACrF,EAAM8F,CAAO,IAAKC,GACxBvG,EAAG,aAAaQ,CAAI,GAAGiG,EAAS,IAAIH,CAAO,EAE7C,CAACK,GAAmBT,GAAoBlG,CAAE,IAAG2G,EAAkB,IAC/D,CAACC,GAAoBhB,GAAqBC,EAAc7F,EAAG,aAAa,UAAU,CAAC,IACrF4G,EAAmB,GAEvB,CAKA,SAAW,CAAC5G,EAAIwD,CAAQ,IAAKU,EAAW,CACtCwC,EAAS,IAAI1G,CAAE,EACf,MAAM6F,EAAerC,EAAS,IAAI,YAAY,GAAK,KAC/CqC,IAAiB,MAAMY,EAAS,IAAIL,GAAqBP,CAAY,CAAC,EACtE,CAACe,GAAoBhB,GAAqBC,EAAcrC,EAAS,IAAI,UAAU,GAAK,IAAI,IAC1FoD,EAAmB,GAEvB,CAEA,MAAO,CAAE,SAAU,MAAM,KAAKF,CAAQ,EAAG,SAAAD,EAAU,gBAAAE,EAAiB,iBAAAC,CAAA,CACtE,CCjIO,SAASE,GAAWC,EAA4B,CACrD,OAAOA,IAAS,QAAUA,IAAS,KACrC,CAEO,MAAMC,GAAoB,aAKpBC,GAAsB,kBACtBC,GAAoB,kBAQpBC,GAAqB,EAOrBC,GAAe,eAE5B,SAASC,GAASC,EAAqC,CACrD,OAAIA,IAAU,SAAiB,CAAE,KAAM,QAAA,EACnCA,IAAU,QAAgB,CAAE,KAAM,OAAA,EAClCA,IAAU,YAAoB,CAAE,KAAM,WAAA,EACtCA,IAAU,OAAe,CAAE,KAAM,MAAA,EAKjCA,IAAU,MAAc,CAAE,KAAM,KAAA,EAChCA,EAAM,WAAW,QAAQ,EACpB,CAAE,KAAM,QAAS,UAAWA,EAAM,MAAM,CAAe,CAAA,EAEzD,IACT,CAUO,SAASC,GAAcpF,EAA4C,CACxE,GAAI,CAACA,EAAO,MAAO,CAAC,CAAE,KAAM,SAAU,EACtC,MAAMqF,EAAUrF,EAAM,KAAA,EACtB,GAAIqF,IAAY,GAAI,MAAO,CAAC,CAAE,KAAM,SAAU,EAC9C,MAAM9G,EAAQ8G,EAAQ,MAAM,KAAK,EAC3B1C,EAA4B,CAAA,EAClC,UAAWP,KAAQ7D,EAAO,CACxB,MAAM+G,EAASJ,GAAS9C,CAAI,EACxBkD,GAAQ3C,EAAS,KAAK2C,CAAM,CAClC,CACA,OAAO3C,EAAS,OAAS,EAAIA,EAAW,CAAC,CAAE,KAAM,SAAU,CAC7D,CAoBA,MAAM4C,GAKD,CACH,CAAE,SAAUT,GAAqB,UAAW,cAAA,EAC5C,CAAE,SAAU,oBAAqB,UAAW,aAAc,aAAc,YAAa,WAAY,SAAA,EACjG,CAAE,SAAU,mBAAoB,UAAW,aAAc,aAAc,YAAa,WAAY,SAAA,EAChG,CAAE,SAAU,mBAAoB,UAAW,eAAgB,aAAc,cAAe,WAAY,WAAA,EACpG,CAAE,SAAU,kBAAmB,UAAW,cAAe,aAAc,aAAc,WAAY,UAAA,CACnG,EAWA,SAASU,GACPC,EACAC,EACAvG,EACS,CACT,GAAI,CAACuG,EAAI,aAAc,MAAO,GAC9B,MAAMnE,EAAOkE,EAAU,QAAQC,EAAI,YAAY,EAC/C,GAAI,CAACnE,EAAM,MAAO,GAClB,GAAI,CAACpC,GAAe,CAACuG,EAAI,WAAY,MAAO,GAC5C,MAAM1F,EAAQD,GAAmBwB,EAAMmE,EAAI,WAAY,OAAO,WAAYvG,CAAW,EACrF,OAAOa,IAAU,QAAaA,EAAM,KAAA,EAAO,MAAM,KAAK,EAAE,SAAS,MAAM,CACzE,CAgBO,SAAS2F,GACdvF,EACAwF,EACAzG,EACiB,CACjB,GAAIyG,IAAa,QAAaA,EAAS,KAAA,IAAW,GAAI,OAAOR,GAAcQ,CAAQ,EAMnF,IAAIC,EAAyD,KAC7D,UAAWH,KAAOH,GAAsB,CACtC,MAAMO,EAAQ1F,EAAQ,QAAQsF,EAAI,QAAQ,EACrCI,IACDN,GAAkBM,EAAOJ,EAAKvG,CAAW,IACzC,CAAC0G,GAAQA,EAAK,UAAU,SAASC,CAAK,KACxCD,EAAO,CAAE,UAAWC,EAAO,UAAWJ,EAAI,SAAA,GAE9C,CAEA,OAAIG,EAAa,CAAC,CAAE,KAAM,QAAS,UAAWA,EAAK,UAAW,EACvD,CAAC,CAAE,KAAM,SAAU,CAC5B,CAYA,MAAME,OAAgB,IACtB,IAAIC,GAAW,GAEf,SAASC,GAAc,EAAgB,CACrC,GAAI,EAAE,aAAa,cAAgB,CAAC,EAAE,OAAQ,OAE9C,MAAM3I,EADS,EAAE,QACI,KACrB,GAAKA,EACL,UAAW4I,KAAMH,GAAWG,EAAG,EAAE,OAAmB5I,CAAI,CAC1D,CAEA,SAAS6I,IAAuB,CAC1BH,IACA,OAAO,SAAa,MACxB,SAAS,iBAAiBnB,GAAmBoB,EAAa,EAC1DD,GAAW,GACb,CAEO,SAASI,GAAgBF,EAA0B,CACxD,OAAAC,GAAA,EACAJ,GAAU,IAAIG,CAAE,EACT,IAAM,CACXH,GAAU,OAAOG,CAAE,EACfH,GAAU,OAAS,GAAKC,IAAY,OAAO,SAAa,MAC1D,SAAS,oBAAoBnB,GAAmBoB,EAAa,EAC7DD,GAAW,GAEf,CACF,CAEO,SAASK,EAAYC,EAAqBhJ,EAAoB,CACnEgJ,EAAO,cAAc,IAAI,YAAYzB,GAAmB,CAAE,OAAQ,CAAE,KAAAvH,CAAA,EAAQ,QAAS,EAAA,CAAM,CAAC,CAC9F,CAOO,SAASiJ,GAAkBC,EAAkC,CAClE,OAAOA,EAAU,SAAS,SAAS,EAC/BA,EAAU,MAAM,EAAG,EAAiB,EAAI,YACxC,IACN,CAcO,SAASC,GAAkB,CAChC,QAAArG,EACA,YAAAsG,EACA,UAAAC,EACA,UAAAC,CACF,EAAsC,CACpC,MAAMC,EAAcD,EAAYL,GAAkBG,CAAW,EAAI,KACjE,OAAON,GAAgB,CAACE,EAAQhJ,IAAS,CACnCgJ,IAAWlG,GAAW,CAACkG,EAAO,SAASlG,CAAO,IAC9C9C,IAASoJ,EAAaC,EAAA,EACjBE,GAAevJ,IAASuJ,GAAeD,GAAWA,EAAA,EAC7D,CAAC,CACH,CC7LO,SAASE,GACdvC,EACAwC,EACY,CACZ,KAAM,CAAE,KAAM7G,EAAY,QAAA8G,EAAS,cAAAC,EAAe,UAAAC,EAAW,QAAAC,EAAS,UAAApF,EAAW,eAAAqF,CAAA,EAC/EL,EACI,CAAE,SAAAM,EAAU,KAAAC,CAAA,EAASL,EACrBM,EAAY,CAAE,QAAS,CAAA,EACvBC,EAAU,CAAE,QAAS,CAAA,EACrBC,EAAuC,CAAA,EAIvCC,EAAU,CAACtH,EAAkB9C,IAAgC,CACjE,MAAMc,EAAOgC,EAAQ,aAAa9C,CAAI,EACtC,OAAIc,IAAS,KAAaA,EACnB2D,EAAU,IAAI3B,CAAO,GAAG,IAAI9C,CAAI,GAAK,IAC9C,EAKMqK,EAAUzH,EAAW,KAAK,QAAQ,IAAM,CAC5C,UAAWE,KAAWmE,EAAU,CAC9B,MAAMb,EAAe5B,GAAoB1B,EAAS2B,CAAS,EAC3D,GAAI,CAAC2B,EAAc,SACnB,MAAMkE,EAAa3D,GAAqBP,CAAY,EACpD,GAAI,CAACyD,EAAQ,IAAIS,CAAU,EAAG,SAE9B,MAAMC,EAAQ9E,EAAS2E,EAAQtH,EAAS,UAAU,EAAG,CAAC,EAChD0H,EAAYJ,EAAQtH,EAAS,eAAe,GAAK4G,EAAQ,UACzDxE,EAAQS,GAAWyE,EAAQtH,EAAS,UAAU,CAAC,EAC/C2H,EAAc1F,GAClBqF,EAAQtH,EAAS,iBAAiB,GAAK,OACvC4G,EACAxE,CAAA,EAEIG,EAAWgD,GACfvF,EACAsH,EAAQtH,EAAS,YAAY,GAAK,OAClC4G,EAAQ,WAAA,EAEJgB,EAAcrF,EAAS,KAAMG,GAAMA,EAAE,OAAS,WAAW,EACzDmF,EAAUtF,EAAS,KAAMG,GAAM6B,GAAW7B,EAAE,IAAI,CAAC,EAEvD,GAAKkF,GAAed,GAAce,EAAS,CAKzC,GAAI,SAAS,gBAAgB,aAAa,aAAa,EAAG,SAI1D,MAAMC,EAAQhI,EAAW,KAAK,OAAOE,EAASmH,EAAW,CACvD,GAAGC,EACH,SAAAH,EACA,KAAAC,EACA,MAAOO,EAAQb,EAAQ,UACvB,OAAQ,EAAA,CACT,EACDI,EAAec,CAAK,EACpB,QACF,CAEA,MAAMC,EAAUxF,EAAS,KAAMG,GAAMA,EAAE,OAAS,aAAe,CAAC6B,GAAW7B,EAAE,IAAI,CAAC,EAClF,GAAKqF,EAEL,IAAIA,EAAQ,OAAS,SAAWA,EAAQ,UAAW,CACjDjI,EAAW,KAAK,IAAIE,EAASmH,CAAS,EACtC,MAAMf,EAAY2B,EAAQ,UACpBC,EAAMhC,GAAgB,CAACE,EAAQhJ,IAAS,CACxCA,IAASkJ,IACTF,IAAWlG,GAAW,CAACkG,EAAO,SAASlG,CAAO,GAClDF,EAAW,KAAK,GAAGE,EAAS,CAAE,GAAGoH,EAAS,SAAAH,EAAU,KAAAC,EAAM,MAAAO,EAAO,EACnE,CAAC,EACDJ,EAAkB,KAAKW,CAAG,EAC1B,QACF,CAEA,GAAI5F,IAAU,OAAW,CACvBtC,EAAW,KAAK,OAAOE,EAASmH,EAAW,CACzC,GAAGC,EACH,SAAAH,EACA,KAAAC,EACA,MAAAO,EACA,cAAe,CACb,QAASzH,EACT,MAAO2H,EACP,IAAKD,EACL,MAAAtF,CAAA,CACF,CACD,EACD,QACF,CAEAtC,EAAW,KAAK,OAAOE,EAASmH,EAAW,CACzC,GAAGC,EACH,SAAAH,EACA,KAAAC,EACA,MAAAO,EACA,cAAe,CACb,QAASzH,EACT,MAAO2H,EAGP,cAAe,qBAAA,CACjB,CACD,EACH,CACF,CAAC,EAED,MAAO,IAAM,CACX,UAAWK,KAAOX,EAChB,GAAI,CACFW,EAAA,CACF,MAAQ,CAER,CAEF,GAAI,CACFT,EAAQ,OAAA,CACV,MAAQ,CAER,CACF,CACF,CAMO,MAAMU,OAAiE,IAAI,CAChF,SACA,OACA,SACA,WACA,OACF,CAAC,EAOYC,OAA6D,IAAI,CAC5E,SACA,OACA,QACF,CAAC,EAQYC,OAAkE,IAAI,CACjF,OACA,WACA,OACF,CAAC,EASYC,OAA8D,IAAI,CAC7E,MACF,CAAC,EC7KKC,GAAuC,CAC3C,OAAQ,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACd,KAAM,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACZ,OAAQ,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACd,OAAQ,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACd,SAAU,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EAChB,KAAM,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACZ,QAAS,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACf,IAAK,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACX,OAAQ,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACd,MAAO,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACb,MAAO,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACb,OAAQ,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACd,MAAO,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACb,MAAO,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,CACf,EAEA,eAAsBC,GAAYlM,EAAkD,CAClF,MAAMmM,EAAShB,GAAQnL,CAAI,EAC3B,GAAI,CAACmM,EAAQ,OAAO,KACpB,GAAI,CAEF,OADY,MAAMA,EAAA,GACP,OACb,OAASC,EAAK,CACZ,eAAQ,MAAM,2CAA2CpM,CAAI,GAAIoM,CAAG,EAC7D,IACT,CACF,CAEA,eAAsBC,GAAaC,EAAwD,CAEzF,OADgB,MAAM,QAAQ,IAAI,CAAC,GAAGA,CAAK,EAAE,IAAIJ,EAAW,CAAC,GAC9C,OAAQK,GAA0BA,IAAM,IAAI,CAC7D,CAWO,SAASC,GACdC,EACAC,EACAC,EACM,CACN,MAAMC,EAAWH,EAAI,SAAS,OAAQlM,GAAOmM,EAAQnM,EAAIkM,EAAI,SAAS,CAAC,EACvE,UAAW3J,KAAW8J,EAAU,CAC9B,MAAM7J,EAAQzC,EAAUwC,EAAS2J,EAAI,UAAU,IAAI3J,CAAO,CAAC,EAC3D2J,EAAI,WAAW,KAAK3J,EAASC,EAAO,CAAC,CAAE,OAAAI,CAAA,IAAawJ,EAASF,EAAK3J,EAASK,CAAM,CAAC,CACpF,CACF,CAkBO,SAAS0J,GACdJ,EACA1L,EACA4L,EACAG,EAAqDxM,EAC/C,CACN,MAAMsM,EAAWH,EAAI,SAAS,OAC3BlM,GAA0BA,aAAc,aAAeA,EAAG,aAAaQ,CAAI,CAAA,EAE9E,UAAWkD,KAAQ2I,EAAU,CAC3B,MAAM7J,EAAQ+J,EAAa7I,CAAI,EAC/BwI,EAAI,WAAW,KAAKxI,EAAMlB,EAAO,CAAC,CAAE,OAAAI,CAAA,IAAawJ,EAASF,EAAKxI,EAAMd,CAAM,CAAC,CAC9E,CACF,CC1IA,MAAM4J,OAAkB,IACxB,IAAIrE,GAAW,GAEf,SAASsE,IAAiB,CACxB,UAAWC,KAAOF,GACZE,EAAI,OAAO,aAAaA,EAAI,KAAK,EACrCA,EAAI,MAAQ,WAAWA,EAAI,GAAIA,EAAI,QAAQ,CAE/C,CAEA,SAASC,IAAe,CAClBxE,IACA,OAAO,OAAW,MACtB,OAAO,iBAAiB,SAAUsE,GAAU,CAAE,QAAS,GAAM,EAC7DtE,GAAW,GACb,CAEA,SAASyE,IAAsB,CACzBJ,GAAY,OAAS,GAAKrE,KAC5B,OAAO,oBAAoB,SAAUsE,EAAQ,EAC7CtE,GAAW,GAEf,CAEO,SAAS0E,GAAUxE,EAAoByE,EAAW,IAAwB,CAC/E,MAAMJ,EAAkB,CAAE,GAAArE,EAAI,SAAAyE,EAAU,MAAO,MAAA,EAC/C,OAAAN,GAAY,IAAIE,CAAG,EACnBC,GAAA,EACO,IAAM,CACPD,EAAI,OAAO,aAAaA,EAAI,KAAK,EACrCF,GAAY,OAAOE,CAAG,EACtBE,GAAA,CACF,CACF,CAEO,SAASG,IAAiB,CAC/B,UAAWL,KAAOF,GACZE,EAAI,OAAO,aAAaA,EAAI,KAAK,EAEvCF,GAAY,MAAA,EACZI,GAAA,CACF,CC9BA,MAAMI,GAAsB,EACtBC,GAAoB,GAE1B,SAASC,IAAkC,CACzC,MAAMC,EAAO,SAAS,KACtB,IAAIC,EAAgB,EAChBC,EAAsC,KACtCC,EAAuC,KACvCC,EAAU,GAEd,MAAMC,EAAQ,IAAY,CACxB,MAAMC,EAAmB,OAAO,QAEhC,GADc,KAAK,IAAIA,EAAmBL,CAAa,GAC1CJ,GAAqB,CAChC,MAAMU,EAA2BD,EAAmBL,EAAgB,OAAS,KACvEO,EAA4BF,EAAmBR,GAAoB,OAAS,QAC9ES,IAAcL,IAChBF,EAAK,aAAa,sBAAuBO,CAAS,EAClDL,EAAgBK,GAEdC,IAAYL,IACdH,EAAK,aAAa,oBAAqBQ,CAAO,EAC9CL,EAAcK,GAEhBP,EAAgBK,CAClB,CACAF,EAAU,EACZ,EAEMK,EAAW,IAAY,CACvBL,IACJA,EAAU,GACV,sBAAsBC,CAAK,EAC7B,EAGA,6BAAsB,IAAM,CACrBL,EAAK,aAAa,qBAAqB,EAI1CE,EAAgBF,EAAK,aAAa,qBAAqB,GAHvDA,EAAK,aAAa,sBAAuB,MAAM,EAC/CE,EAAgB,QAIlB,MAAMM,EAA4B,OAAO,QAAUV,GAAoB,OAAS,QAChFE,EAAK,aAAa,oBAAqBQ,CAAO,EAC9CL,EAAcK,EACdP,EAAgB,OAAO,OACzB,CAAC,EAED,OAAO,iBAAiB,SAAUQ,EAAU,CAAE,QAAS,GAAM,EAEtD,IAAM,CACX,OAAO,oBAAoB,SAAUA,CAAQ,EAC7CT,EAAK,gBAAgB,qBAAqB,EAC1CA,EAAK,gBAAgB,mBAAmB,CAC1C,CACF,CAEA,SAASU,IAAoC,CAC3C,MAAMnH,EAAW,SAAS,iBAA8B,uBAAuB,EAC/E,GAAIA,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMoH,EAAW,IAAI,qBAAsBC,GAAY,CACrD,UAAWC,KAASD,EAAS,CAC3B,MAAME,EAAYD,EAAM,OAAuB,SAC/C,UAAWE,KAAS,MAAM,KAAKD,CAAQ,EAAG,CACxC,MAAME,EAAcD,EAAsB,gBAAA,GAAqB,CAAA,EAC/D,UAAWE,KAAaD,EAClBH,EAAM,eAAgBI,EAAU,KAAA,IACrB,MAAA,CAEnB,CACF,CACF,CAAC,EAED,UAAWpO,KAAM0G,EAAUoH,EAAS,QAAQ9N,CAAE,EAE9C,MAAO,IAAM8N,EAAS,WAAA,CACxB,CAEO,SAASO,IAA8B,CAC5C,GAAI,OAAO,OAAW,IAAa,MAAO,IAAM,CAAC,EACjD,MAAMC,EAAmBpB,GAAA,EACnBqB,EAAmBV,GAAA,EACzB,MAAO,IAAM,CACXS,EAAA,EACAC,EAAA,CACF,CACF,CC3FA,MAAMC,GAAcC,GAClBA,EAAI,GAAM,EAAIA,EAAIA,EAAIA,EAAIA,EAAI,EAAI,KAAK,IAAI,GAAKA,EAAI,EAAG,CAAC,EAAI,EAExDC,GAAmB,IAElB,SAASC,IAA+B,CAC7C,GAAI,OAAO,OAAW,IAAa,MAAO,IAAM,CAAC,EAEjD,MAAMjI,EAAW,SAAS,iBAA8B,oBAAoB,EAC5E,GAAIA,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMwB,EAAgE,CAAA,EAEtE,UAAWlI,KAAM0G,EAAU,CACzB,MAAM2B,EAAMuG,GAAmB,CAC7B,MAAMC,EAAiB7O,EAAG,aAAa,kBAAkB,EACzD,GAAI,CAAC6O,EAAgB,OACrB,MAAMpG,EAAS,SAAS,cAAcoG,CAAc,EACpD,GAAI,CAACpG,EAAQ,OACbmG,EAAE,eAAA,EACF,MAAMpF,EAAWtE,EAASlF,EAAG,aAAa,aAAa,EAAG0O,EAAgB,EACpEI,EAAS5J,EAASlF,EAAG,aAAa,kBAAkB,EAAG,CAAC,EACxD+O,EAAQ,OAAO,MACrB,GAAIA,EAAO,CACTA,EAAM,SAASF,EAAgB,CAAE,OAAAC,EAAQ,SAAAtF,EAAU,OAAQgF,GAAY,EACvE,MACF,CACA,MAAMQ,EAAOvG,EAAuB,sBAAA,EAAwB,IAAM,OAAO,QAAUqG,EACnF,OAAO,SAAS,CAAE,IAAAE,EAAK,SAAU,SAAU,CAC7C,EACAhP,EAAG,iBAAiB,QAASqI,CAAE,EAC/BH,EAAU,KAAK,CAAE,GAAAlI,EAAI,GAAAqI,CAAA,CAAI,CAC3B,CAEA,MAAO,IAAM,CACX,SAAW,CAAE,GAAArI,EAAI,GAAAqI,CAAA,IAAQH,EAAWlI,EAAG,oBAAoB,QAASqI,CAAE,CACxE,CACF,CC1CO,MAAM4G,GAAmC,CAC9C,GAAI,IACJ,GAAI,IACJ,GAAI,IACJ,GAAI,IACN,EAEMC,GAAkC,CACtC,MAAO,IACP,MAAO,IACP,MAAO,GACP,QAAS,EACX,EAEMC,GAAoC,CACxC,SAAU,EACV,WAAY,EACd,EAEaC,GAA+C,CAC1D,SAAU,GACV,KAAM,YACR,EAOaC,GAAqD,CAChE,SAAU,GACV,KAAM,YACR,EAQaC,GAAmC,CAC9C,SAAU,GACV,KAAM,aACN,UAAW,EACX,UAAW,EACX,YAAa,UACb,UAAW,aACX,MAAO,GACP,QAASJ,GACT,SAAUC,GACV,YAAaF,GACb,aAAc,GACd,YAAa,GACb,cAAe,GACf,eAAgB,EAClB,EAEA,SAASM,GACPC,EACgC,CAChC,OAAIA,IAAU,GAAc,GACxBA,IAAU,QAAaA,IAAU,GAAa,GAC3C,CAAE,GAAGJ,GAAwB,GAAGI,CAAA,CACzC,CAEO,SAASC,GAAe/K,EAAoC,CACjE,MAAO,CACL,GAAG4K,GACH,GAAG5K,EACH,QAAS,CAAE,GAAGwK,GAAiB,GAAGxK,EAAK,OAAA,EACvC,SAAU,CAAE,GAAGyK,GAAkB,GAAGzK,EAAK,QAAA,EACzC,YAAa,CAAE,GAAGuK,GAAqB,GAAGvK,EAAK,WAAA,EAC/C,cAAe6K,GAAqB7K,EAAK,aAAa,CAAA,CAE1D,CAoDO,MAAMgL,EAZyB,CACpC,YAAa,GACb,QAAS,CAAE,GAAGJ,EAAA,EACd,YAAa,CAAE,GAAGL,EAAA,EAClB,UAAW,CAAA,EACX,aAAc,KACd,mBAAoB,KACpB,oBAAqB,KACrB,kBAAmB,GACnB,cAAe,GACjB,EAIO,SAASU,GAAmBjL,EAA+C,CAChF,MAAO,CAAE,GAAGuK,GAAqB,GAAGvK,CAAA,CACtC,CAMA,IAAIkL,GAAwE,KAErE,SAASC,IAAyB,CACvC,IAAIC,EAIJF,GAAgB,CAAE,QAHF,IAAI,QAAepO,GAAM,CACvCsO,EAAUtO,CACZ,CAAC,EAC0B,QAAAsO,CAAA,CAC7B,CAEO,SAASC,IAAiC,CAC/C,OAAOH,GAAgBA,GAAc,QAAU,QAAQ,QAAA,CACzD,CAEO,SAASI,IAAqB,CACnCJ,IAAe,QAAA,CACjB,CAEO,SAASK,GAAY5H,EAAsB,CAChDqH,EAAM,UAAU,KAAKrH,CAAE,CACzB,CAEO,SAAS6H,IAAwB,CACtC,KAAOR,EAAM,UAAU,OAAS,GAAG,CACjC,MAAMrH,EAAKqH,EAAM,UAAU,IAAA,EAC3B,GAAKrH,EACL,GAAI,CACFA,EAAA,CACF,OAASwD,EAAK,CACZ,QAAQ,MAAM,iCAAkCA,CAAG,CACrD,CACF,CACF,CCrJA,MAAMyD,GAAiD,CACrD,KAAM,IACN,gBAAiB,EACjB,gBAAiB,EACjB,YAAa,GACb,UAAW,EACb,EAOO,SAASa,GACd9N,EACA8G,EACA/J,EAC2B,CAC3B,MAAMgR,EAAQ,OAAO,OAAW,IAAc,OAAO,MAAQ,OAC7D,GAAI,CAACA,EACH,OAAIhR,GACF,QAAQ,KACN,iOAAA,EAGG,KAIT,MAAMqC,EAAS,CAAE,GAAG6N,GAAiB,GADpBnG,IAAY,GAAO,CAAA,EAAKA,CACD,EAClC4F,EAAQ,IAAIqB,EAAM3O,CAA4C,EAE9DoD,EAAiBxC,EAAW,QAAQ,cACpCgO,EAAsBxL,EAAgB,IAAMA,EAAc,SAAW,KACvEwL,GAAqBtB,EAAM,GAAG,SAAUsB,CAAmB,EAE/D,MAAMC,EAAYC,GAAuB,CACvCxB,EAAM,IAAIwB,EAAO,GAAI,CACvB,EACA,OAAAlO,EAAW,KAAK,OAAO,IAAIiO,CAAQ,EAEnCjO,EAAW,KAAK,OAAO,aAAa,CAAC,EAErC,OAAO,MAAQ0M,EAYR,CAAE,MAAAA,EAAO,QAVA,IAAY,CAC1B1M,EAAW,KAAK,OAAO,OAAOiO,CAAQ,EACtC,GAAI,CACFvB,EAAM,QAAA,CACR,OAASlD,EAAK,CACRzM,GAAO,QAAQ,KAAK,wCAAyCyM,CAAG,CACtE,CACI,OAAO,QAAUkD,GAAO,OAAO,OAAO,KAC5C,CAEgB,CAClB,CC7CA,IAAIyB,GAA+E,KAMnF,MAAMC,GAA0B,IAEhC,SAASC,GACPC,EAC6B,CAG7B,OAFIA,IAAY,IACZ,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,YAC9D,CAAC,OAAO,WAAW,kCAAkC,EAAE,QAAgB,KACpEA,IAAY,GAAOvB,GAAyBuB,CACrD,CAEA,SAASC,GACPD,EACAE,EACuB,CAMvB,OALIF,IAAY,IAAQA,IAAY,QAChC,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,YAI9D,CAAC,OAAO,WAAW,eAAeE,EAAe,GAAI,KAAK,EAAE,QAAgB,GAGzEF,CACT,CAUA,SAASG,IAA0B,CACjC,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WAAmB,GAC9E,OAAO,WAAW,gBAAgB,EAAE,OAC7C,CAEA,SAASC,GAAoBC,EAAoB5R,EAAsB,CAErE,MAAM6R,EADI,OACW,WAGrB,GAAI,CAACA,EAAY,CACX7R,GACF,QAAQ,KACN,wDAAwD,OAAO,KAAK0D,EAAW,EAAE,KAAK,IAAI,CAAC,kIAAA,EAG/F,MACF,CACA,GAAI,CACFkO,EAAO,KAAK,eAAeC,CAAU,CACvC,MAAQ,CAER,CACA,SAAW,CAACxR,EAAMyR,CAAI,IAAK,OAAO,QAAQpO,EAAW,EACnD,GAAI,CACFmO,EAAW,OAAOxR,EAAMyR,CAAI,CAC9B,OAASrF,EAAK,CACRzM,GAAO,QAAQ,KAAK,kDAAkDK,CAAI,IAAKoM,CAAG,CACxF,CAEJ,CAEA,eAAsBsF,GAAKhI,EAAuB,GAAmB,CACnE,GAAIuG,EAAM,YAAa,OACvBG,GAAA,EAKI,OAAO,SAAa,KACtB,SAAS,gBAAgB,aAAa,YAAa,EAAE,EAEvDH,EAAM,QAAUD,GAAetG,CAAO,EACtCuG,EAAM,YAAcC,GAAmBxG,EAAQ,WAAW,EAC1DuG,EAAM,YAAc,GAEpB,MAAMtQ,EAAQ+J,EAAQ,OAAS,GACzBzF,EAAOyF,EAAQ,MAAQ,SAOvBjF,EAAYT,GAAeC,EAAMyF,EAAQ,QAAS/J,CAAK,EAC7DsQ,EAAM,UAAYxL,EAWlB,MAAMkF,EAAgBsH,GAAoBhB,EAAM,QAAQ,aAAa,EAC/D0B,EAAiB,CAAChI,GAAiBwH,GACvClB,EAAM,QAAQ,eACdA,EAAM,YAAY,EAAA,EAMpBA,EAAM,QAAQ,cAAgB,CAAC,CAACtG,EAChCsG,EAAM,QAAQ,eAAiB0B,EAE/B,KAAM,CAAE,SAAA1K,EAAU,SAAAD,EAAU,gBAAAE,EAAiB,iBAAAC,GAAqBJ,GAAK9C,EAAMQ,CAAS,EACtF,GAAIwC,EAAS,SAAW,EAAG,CACzBsJ,GAAA,EACA,MACF,CAEA,IAAIqB,EACAC,EACAlI,GACFiI,EAAmB7G,GACnB8G,EAAe7G,IACN2G,GAGTC,EAAmB3G,GACnB4G,EAAeF,IAAmB,OAASzG,GAAgC,IAAI,MAE/E0G,MAAuB,IACvBC,MAAmB,KAGrB,MAAMC,EAAoB,IAAI,IAAI9K,CAAQ,EAC1C,IAAI+K,EAAgB,GACpB,UAAWC,KAAKJ,EACTE,EAAkB,IAAIE,CAAC,IAC5BF,EAAkB,OAAOE,CAAC,EACtBH,EAAa,IAAIG,CAAC,IAAGD,EAAgB,KAS3C,MAAME,EACJ,OAAO,SAAa,KACpB,SAAS,gBAAgB,aAAa,YAAY,EAChDA,IACFH,EAAkB,OAAO,QAAQ,EACjCA,EAAkB,OAAO,MAAM,EAC/BA,EAAkB,OAAO,QAAQ,EACjCA,EAAkB,OAAO,UAAU,EACnCC,EAAgB,IAKdD,EAAkB,IAAI,OAAO,GAAK,CAACT,MACrCS,EAAkB,OAAO,OAAO,EAGlC,MAAMpS,MAAsB,IAC5B,UAAWsS,KAAKF,GAEZE,IAAM,UACNA,IAAM,QACNA,IAAM,UACNA,IAAM,UACNA,IAAM,YACNA,IAAM,OACNA,IAAM,YAENtS,EAAgB,IAAI,eAAe,GAEjCsS,IAAM,QAAUA,IAAM,UAAStS,EAAgB,IAAI,WAAW,EAK9DsS,IAAM,SAAW9K,GAAiBxH,EAAgB,IAAI,WAAW,GACjEsS,IAAM,UAAYA,IAAM,aAC1BtS,EAAgB,IAAI,WAAW,EAC/BA,EAAgB,IAAI,eAAe,GAEjCsS,IAAM,OAAOtS,EAAgB,IAAI,MAAM,EAEzCqS,GAAerS,EAAgB,IAAI,eAAe,EAEtD,MAAMkD,EAAanD,GAAW,CAAC,GAAGC,CAAe,EAAGC,CAAK,EACzD,GAAI,CAACiD,EAAY,CACf2N,GAAA,EACA,MACF,CAEAe,GAAoB1O,EAAYjD,CAAK,EACrC,GAAI,CACFiD,EAAW,KAAK,SAAS,CAAE,KAAMqN,EAAM,QAAQ,KAAM,CACvD,MAAQ,CAER,CAOA,MAAMiC,EAAkBjC,EAAM,QAAQ,aAClCiC,GAAmB,CAACjC,EAAM,eAC5BA,EAAM,aAAeS,GAAiB9N,EAAYsP,EAAiBvS,CAAK,GAWtEsQ,EAAM,QAAQ,cAChBA,EAAM,qBAAA,EACNA,EAAM,mBAAqBrB,GAAA,GAE7BqB,EAAM,sBAAA,EACNA,EAAM,oBAAsBf,GAAA,EAE5B,MAAMiD,EAAaxP,GAA2BC,EAAYqN,EAAM,WAAW,EAC3Ec,GAAgB,CAAE,KAAMnO,EAAY,WAAAuP,CAAA,EASpC,MAAMC,EAAwB,CAAA,EAC9B,IAAIC,EAAgB,GACpB,MAAMvI,EAAkBc,GAA2B,CAC5CyH,GAAeD,EAAS,KAAKxH,CAAK,CACzC,EAQA,GAPA4F,GAAY,IAAM,CAChB6B,EAAgB,EAClB,CAAC,EAKGN,EAAe,CAGjB,MAAMO,EAAa3I,GAAiBiG,GAC9B2C,EAAc/I,GAAoBvC,EAAU,CAChD,KAAMrE,EACN,QAASqN,EAAM,QACf,cAAeqC,EACf,UAAW,CAACrC,EAAM,kBAClB,QAAS4B,EACT,UAAApN,EACA,eAAAqF,CAAA,CACD,EACD0G,GAAY+B,CAAW,CACzB,CAmBA,GACEpL,GACA,OAAO,SAAa,KACpB,SAAS,OAAO,MAEhB,GAAI,CACF,MAAM,QAAQ,KAAK,CACjB,SAAS,MAAM,MACf,IAAI,QAAekJ,GAAY,WAAWA,EAASW,EAAuB,CAAC,CAAA,CAC5E,CACH,MAAQ,CAER,CAGF,MAAMwB,EAAiB,MAAMnG,GAAayF,CAAiB,EACrDW,EAA6B,CACjC,KAAM7P,EACN,WAAAuP,EACA,SAAAlL,EACA,QAASgJ,EAAM,QACf,MAAAtQ,EACA,UAAW,CAACsQ,EAAM,kBAClB,cAAAtG,EACA,UAAAlF,EACA,SAAU,CAACmE,EAAIyE,EAAW,MAAQqF,GAAgB9J,EAAIyE,CAAQ,EAC9D,eAAAvD,CAAA,EAEF,UAAW6I,KAAOH,EAChB,GAAI,CACF,MAAMI,EAAUD,EAAI,KAAKF,CAAU,EACnCjC,GAAYoC,CAAO,CACrB,OAASxG,EAAK,CACZ,QAAQ,MAAM,4BAA4BuG,EAAI,IAAI,mBAAoBvG,CAAG,CAC3E,CAUF,UAAW7L,KAAM0G,EACX1G,EAAG,aAAa,YAAY,GAAGA,EAAG,aAAa,WAAY,EAAE,EAkBnE,GAZA0P,EAAM,kBAAoB,GAOtB,OAAO,SAAa,MACtB,SAAS,gBAAgB,gBAAgB,aAAa,EACtD,SAAS,gBAAgB,gBAAgB,YAAY,GAGnDtQ,EAAO,CACT,MAAMkT,EAAc,OAAO,OAAW,KAAe,CAAC,CAAC,OAAO,MACxDC,EAAiB,CAAC,GAAGhB,CAAiB,EACtCiB,EAAkB,CAAC,GAAG/L,CAAQ,EAAE,OAAQgL,GAAM,CAACF,EAAkB,IAAIE,CAAC,CAAC,EACvEgB,EAAaf,EACf,oBACAtI,EACE,iBACAgI,EACE,oBAAoBA,IAAmB,OAAS,OAAS,SAAS,IAClE,KACFsB,EACJD,GAAcD,EAAgB,OAC1B,GAAGD,EAAe,KAAK,IAAI,GAAK,QAAQ,KAAKE,CAAU,aAAaD,EAAgB,KAAK,IAAI,CAAC,IAC9FD,EAAe,KAAK,IAAI,GAAK,SACnC,QAAQ,IACN,0CAA0CG,CAAa,cACzC,CAAC,GAAGvT,CAAe,EAAE,KAAK,IAAI,GAAK,QAAQ,eAC1CuH,EAAS,MAAM,mBACX4L,EAAc,QAAU,KAAK,oBAC5BlJ,EAAgB,SAAW,KAAK,qBAC/BgI,GAAkC,KAAK,EAAA,CAEhE,CAsBA,GApBApB,GAAA,EAoBI6B,EAAS,OAAS,EAAG,CACvB,MAAMc,EAAQ,IAAY,CACxB,GAAI,CAAAb,EACJ,UAAWzH,KAASwH,EAAS,OAAO,CAAC,EACnC,GAAI,CACFxH,EAAM,QAAQ,EAAI,CACpB,OAASwB,EAAK,CACZ,QAAQ,MAAM,qCAAsCA,CAAG,CACzD,CAEJ,EAEE,OAAO,uBAA0B,YAChC,OAAO,SAAa,KAAe,SAAS,kBAAoB,SAGjE8G,EAAA,EAEA,sBAAsB,IAAM,sBAAsBA,CAAK,CAAC,CAE5D,CACF,CAEO,SAASC,GAAQzJ,EAA6B,GAAU,CAC7D,GAAIqH,IAAe,WACjB,GAAI,CACErH,EAAQ,eAAgBqH,GAAc,WAAW,QAAA,EAChDA,GAAc,WAAW,UAAA,CAChC,OAAS3E,EAAK,CACZ,QAAQ,MAAM,sDAAuDA,CAAG,CAC1E,CAEFqE,GAAA,EACA2C,GAAA,EACArC,GAAgB,KAChBd,EAAM,YAAc,GACpBA,EAAM,cAAgB,IAEjBvG,EAAQ,cACXuG,EAAM,cAAc,QAAA,EACpBA,EAAM,aAAe,KACrBA,EAAM,qBAAA,EACNA,EAAM,mBAAqB,KAC3BA,EAAM,sBAAA,EACNA,EAAM,oBAAsB,MAG9BA,EAAM,QAAU,CAAE,GAAGJ,EAAA,CACvB,CAEA,eAAsBwD,IAAyB,CAC7CF,GAAA,EACA,MAAMzB,GAAKzB,EAAM,OAAO,CAC1B,CAEO,SAASqD,GAAS1K,EAAoB3D,EAAwB,GAAuB,CAC1F,OAAOyN,GAAgB9J,EAAI3D,EAAK,UAAY,GAAG,CACjD,CAIA,MAAMsO,GAAiB,CACrB,KAAA7B,GACA,QAAAyB,GACA,QAAAE,GACA,SAAAC,GACA,MAAOhD,GAGP,IAAI,SAAU,CACZ,OAAOL,EAAM,OACf,CACF,EAQI,OAAO,OAAW,MACpB,OAAO,aAAesD,IC7fjB,SAASC,GACdC,EACA/J,EACQ,CACR,OAAI+J,IAAc,QAAgB/J,EAAQ,QAAQ,MAC9C+J,IAAc,QAAgB/J,EAAQ,QAAQ,MAC9C+J,IAAc,QAAgB/J,EAAQ,QAAQ,MAC3CA,EAAQ,QAAQ,OACzB,CAoBA,MAAMgK,OAAiB,IAAiB,CAAC,QAAS,SAAU,MAAO,OAAO,CAAC,EAErEC,GAAe,KAAqB,CACxC,KAAM,QACN,OAAQ,GACR,UAAW,EACX,KAAM,EACR,GAiBO,SAASC,GACdlR,EACAgD,EACAmO,EAAuBnO,EACV,CACb,MAAMoO,EAAQH,GAAA,EACd,GAAI,CAACjR,EACH,MAAO,CAAE,KAAMgD,EAAU,KAAMmO,EAAc,MAAAC,CAAA,EAE/C,MAAMvN,EAAS7D,EAAM,KAAA,EAAO,MAAM,KAAK,EACjCqR,EAAqB,CAAA,EAC3B,UAAWlM,KAAStB,EAAQ,CAC1B,GAAI,QAAQ,KAAKsB,CAAK,EAAG,CACvB,MAAM1H,EAAI,WAAW0H,CAAK,EACtB,OAAO,SAAS1H,CAAC,GAAG4T,EAAS,KAAK5T,CAAC,EACvC,QACF,CACA,GAAIuT,GAAW,IAAI7L,CAAoB,EACrCiM,EAAM,KAAOjM,UACJA,IAAU,SACnBiM,EAAM,OAAS,WACNjM,EAAM,WAAW,SAAS,EAAG,CACtCiM,EAAM,OAAS,GACf,MAAM3T,EAAI,SAAS0H,EAAM,MAAM,CAAgB,EAAG,EAAE,EAChD,OAAO,SAAS1H,CAAC,GAAKA,EAAI,MAAS,UAAYA,EACrD,MAAW0H,IAAU,SACnBiM,EAAM,KAAO,GAEjB,CACA,MAAME,EAAOD,EAAS,CAAC,GAAKrO,EACtBuO,EAAOF,EAAS,CAAC,GAAKF,EAC5B,MAAO,CAAE,KAAAG,EAAM,KAAAC,EAAM,MAAAH,CAAA,CACvB,CAEO,SAASI,GAAaF,EAAcF,EAAmC,CAC5E,GAAIA,EAAM,OAAQ,CAEhB,GAAIA,EAAM,WAAa,EACrB,MAAO,CAAE,KAAME,EAAM,KAAM,QAAA,EAM7B,MAAMG,EAAYL,EAAM,UACxB,IAAIM,EAAyB,KAC7B,MAAO,CAACnI,EAAeoI,EAAkBC,IAAoB,CAC3D,GAAI,CAACF,EAAO,CACV,MAAMrS,EAAI,MAAM,KAAK,CAAE,OAAQuS,EAAK,QAAU,CAACC,EAAGC,IAAMA,CAAC,EACzD,QAAS7T,EAAIoB,EAAE,OAAS,EAAGpB,EAAI,EAAGA,IAAK,CACrC,MAAM8T,EAAI,KAAK,MAAM,KAAK,UAAY9T,EAAI,EAAE,EAC3C,CAACoB,EAAEpB,CAAC,EAAGoB,EAAE0S,CAAC,CAAC,EAAI,CAAC1S,EAAE0S,CAAC,EAAG1S,EAAEpB,CAAC,CAAC,CAC7B,CACAyT,EAAQrS,CACV,CACA,OAAO,KAAK,OAAOqS,EAAMnI,CAAK,GAAK,GAAKkI,CAAS,EAAIH,CACvD,CACF,CACA,GAAIF,EAAM,MAAQA,EAAM,OAAS,QAAS,CACxC,MAAMvQ,EAA+B,CAAE,KAAMyQ,EAAM,KAAMF,EAAM,IAAA,EAC/D,OAAIA,EAAM,OAAMvQ,EAAI,KAAO,QACpBA,CACT,CACA,OAAOyQ,CACT,CASO,SAASU,GACd5R,EACAK,EACAuG,EAC+C,CAE/C,MAAM8E,EADerL,EAAO,YAAY,IAAM,OAE1C,MAAM,KAAKL,EAAQ,QAAQ,EAAE,OAAQ6R,GAAoBA,EAAE,WAAa,CAAC,EACzE,CAAA,EACEC,EAAqBpG,EAAS,OAAS,EAAIA,EAAW,CAAC1L,CAAO,EAC9D+R,EAAcjB,GAAiBzQ,EAAO,YAAY,EAAGqQ,GAAkB,OAAW9J,CAAO,CAAC,EAC1FoL,EACJtG,EAAS,OAAS,EAAI0F,GAAaW,EAAY,KAAMA,EAAY,KAAK,EAAI,EAC5E,MAAO,CAAE,QAAAD,EAAS,QAAAE,CAAA,CACpB,CCrGO,SAASC,GAAeC,EAA4C,CACzE,KAAM,CAAE,YAAAC,EAAa,GAAGC,CAAA,EAASF,EACjC,OAAIC,IAAgB,OAAkBC,EAC/B,CAAE,GAAGA,EAAM,SAAU,CAAE,YAAAD,EAAY,CAC5C,CAEA,MAAME,OAAiC,IAAI,CACzC,IAAK,IAAK,IAAK,WAAY,WAAY,QAAS,SAAU,SAC1D,WAAY,SAAU,YAAa,YAAa,YAAa,QAAS,QACtE,YAAa,sBACf,CAAC,EAQM,SAASC,GAAcJ,EAAuC,CACnE,MAAMK,EAAkB,CAAA,EACxB,IAAIC,EAAe,GACnB,UAAWlR,KAAO,OAAO,KAAK4Q,CAAI,EAC5B5Q,IAAQ,WAAaA,IAAQ,YAC1BiR,EAAM,SAAS,SAAS,GAAGA,EAAM,KAAK,SAAS,EAC3CjR,IAAQ,SACZiR,EAAM,SAAS,QAAQ,GAAGA,EAAM,KAAK,QAAQ,EACzCjR,IAAQ,WACZiR,EAAM,SAAS,WAAW,GAAGA,EAAM,KAAK,WAAW,EAC/CF,GAA2B,IAAI/Q,CAAG,IAC3CkR,EAAe,IAGnB,OAAIA,GAAcD,EAAM,QAAQ,WAAW,EACpCA,EAAM,KAAK,IAAI,CACxB,CAgEO,SAASE,GACd9I,EACA3J,EACAmC,EACiC,CACjC,MAAMyF,EAAczF,EAAK,SAAS,KAAMO,GAAMA,EAAE,OAAS,WAAW,EAC9DmF,EAAU1F,EAAK,SAAS,KAAMO,GAAM6B,GAAW7B,EAAE,IAAI,CAAC,EACtDgQ,EAAiB9K,GAAe+B,EAAI,WAAc9B,EACxD,IAAI8K,EASJ,GARKD,IACHC,EAAoBxQ,EAAK,SAAS,KAC/BO,GAAMA,EAAE,OAAS,aAAe,CAAC6B,GAAW7B,EAAE,IAAI,CAAA,GAMnD,CAACgQ,GAAiB,CAACC,EAAmB,OAAO,KAEjD,MAAMC,EAAYzQ,EAAK,WAAanC,EAO9B6S,EAAYH,EAAgBvQ,EAAK,MAAQwH,EAAI,QAAQ,UAAYxH,EAAK,MAE5E,IAAI2Q,EAAgC,KAChCC,EACAC,EAAgB,GAChBC,EAAY,GACZC,EAAgB,GAOpB,MAAMC,EAAKhR,EAAK,WAChB,IAAIiR,EAAuB,CAAA,EAM3B,MAAMC,EAAkBC,GAA+B,CACrD,MAAMC,EAAQD,EAId,OAAI,OAAOC,EAAM,aAAgB,WACxBA,EAAM,YAAY,GAAM,GAAM,EAAK,EAAE,QAAS5H,GAAU,CAC7D,MAAMkG,EAAIlG,EACV,OAAO,OAAOkG,EAAE,SAAY,WAAcA,EAAE,QAAA,EAA0B,CAAA,CACxE,CAAC,EAEI,OAAO0B,EAAM,SAAY,WAAcA,EAAM,QAAA,EAA0B,CAAA,CAChF,EACMC,EAAgB,IAAY,CAChC,GAAI,GAACL,GAAM,CAACL,GACZ,CAAAM,EAAQC,EAAeP,CAAW,EAAE,OAAQpQ,GAAwBA,aAAa,WAAW,EAC5F,UAAWjF,KAAM2V,EAAO3V,EAAG,MAAM,WAAa0V,EAChD,EACMM,EAAkB,IAAY,CAClC,UAAWhW,KAAM2V,EAAO3V,EAAG,MAAM,WAAa,GAC9C2V,EAAQ,CAAA,CACV,EAEMM,EAAc,IAAY,CAE9B,GADAD,EAAA,EACIV,EAAqB,CACvB,GAAI,CACFA,EAAA,CACF,MAAQ,CAER,CACAA,EAAsB,MACxB,CACID,IAGFA,EAAY,KAAA,EACZA,EAAc,KAElB,EAEMa,EAAY,IAMZjB,EAAsB,CAAE,OAAQ,GAAM,MAAOG,CAAA,EAC7CF,GAAmB,OAAS,QACvB,CACL,OAAQ,GACR,MAAOxQ,EAAK,MACZ,YAAa0C,EAAA,EAGb1C,EAAK,QAAU,OACV,CACL,MAAOA,EAAK,MACZ,cAAe,CACb,QAASyQ,EACT,MAAOzQ,EAAK,YACZ,IAAKA,EAAK,UACV,MAAOA,EAAK,KAAA,CACd,EAGG,CAAE,OAAQ,GAAM,MAAOA,EAAK,KAAA,EAG/ByR,EAAU,IAAY,CAY1B,GAAIlB,GAAiBQ,EAAe,OAEpC,MAAMW,EAAWZ,EAMXa,EACJhB,GAAe3Q,EAAK,QAAU,OAAY2Q,EAAY,WAAa,KAgBrE,GAdAY,EAAA,EAcIhB,GAAiB,SAAS,gBAAgB,aAAa,aAAa,EAAG,CACzEO,EAAY,GACZC,EAAgB,GAChB,MACF,CAEA,MAAMa,EAAQ5R,EAAK,eAAewR,EAAA,CAAW,EAC7C,GAAKI,EAaL,IAZAjB,EAAciB,EAAM,UACpBhB,EAAsBgB,EAAM,QAExBZ,IAKFL,EAAY,cAAc,aAAcW,CAAe,EACvDX,EAAY,cAAc,oBAAqBW,CAAe,GAG5Df,EAAe,CAIjBI,EAAY,cAAc,aAAc,IAAM,CAC5CI,EAAgB,GAChBO,EAAA,CACF,CAAC,EAEDD,EAAA,EACIK,EAQFf,EAAY,QAAQ,EAAI,EAMpBA,GAAanJ,EAAI,eAAemJ,CAAW,EAEjDG,EAAY,GACZ,MACF,CAcA,GAAID,GAAiB7Q,EAAK,QAAU,OAAW,CAC7C,MAAM6R,EAASF,GAAgB,EAC/BhB,EAAY,SAASkB,CAAM,EACvBA,EAAS,GAIXR,EAAA,EACAV,EAAY,KAAA,GAEZA,EAAY,MAAA,CAEhB,EACF,EAEAc,EAAA,EAIA,IAAIK,EAA6B,IAAM,CAAC,EAExC,OAAItB,GAAmB,OAAS,SAAWA,EAAkB,UAC3DsB,EAAiB5N,GAAkB,CACjC,QAAArG,EACA,YAAa2S,EAAkB,UAC/B,UAAW,IAAM,CACfK,EAAgB,GAChBQ,EAAA,EASAV,GAAa,UAAU,CAAC,EAAE,QAAQ,EAAI,CACxC,EACA,UAAW,IAAM,CACfE,EAAgB,GAChBQ,EAAA,EACAV,GAAa,UAAUlO,EAAkB,EAAE,QAAA,CAC7C,CAAA,CACD,EACQ,CAAC8N,GAAiBvQ,EAAK,QAAU,QAAawQ,IACvDsB,EAAiB5R,GAAiB,CAChC,KAAMsH,EAAI,KACV,QAASiJ,EACT,MAAOzQ,EAAK,YACZ,MAAOA,EAAK,MACZ,OAAQ,IAAM,CACZ6Q,EAAgB,GAChBQ,EAAA,EACAV,GAAa,KAAA,CACf,EACA,QAAS,IAAM,CACbE,EAAgB,GAChBS,EAAA,EACAX,GAAa,SAAS,CAAC,EAAE,MAAA,CAC3B,CAAA,CACD,GAKI,CACL,QAAAc,EACA,QAAS,IAAM,CACbK,EAAA,EACAP,EAAA,CACF,CAAA,CAEJ,CCvaA,MAAMQ,GAA6D,CACjE,KAAM,KAAO,CAAE,QAAS,IACxB,UAAYxC,IAAO,CAAE,EAAG,GAAG,EAAIA,CAAC,MAAO,QAAS,CAAA,GAChD,YAAcA,IAAO,CAAE,EAAG,MAAQA,CAAC,MAAO,QAAS,CAAA,GACnD,YAAcA,IAAO,CAAE,EAAG,GAAG,EAAIA,CAAC,MAAO,QAAS,CAAA,GAClD,aAAeA,IAAO,CAAE,EAAG,MAAQA,CAAC,MAAO,QAAS,CAAA,GACpD,UAAYA,IAAO,CAAE,MAAO,KAAK,IAAI,EAAG,EAAI,IAAOA,CAAC,EAAG,QAAS,CAAA,GAChE,WAAaA,IAAO,CAAE,MAAO,EAAI,IAAOA,EAAG,QAAS,IACpD,WAAaA,IAAO,CAAE,SAAU,IAAMA,CAAA,GACtC,aAAeA,IAAO,CAAE,SAAU,KAAOA,CAAA,GACzC,aAAeA,IAAO,CAAE,SAAU,IAAMA,CAAA,GACxC,cAAgBA,IAAO,CAAE,SAAU,KAAOA,CAAA,GAC1C,KAAM,KAAO,CAAE,QAAS,EAAG,OAAQ,YAAA,EACrC,EAEMyC,GAAmB,IAAI,IAAI,OAAO,KAAKD,EAAQ,CAAC,EAEhDE,GAAiB,iDAEjBC,GAA2C,CAC/C,GAAI,WACJ,GAAI,YACJ,GAAI,cACJ,GAAI,cACN,EAEA,SAASC,GAAc1U,EAAwB,CAC7C,OAAOwU,GAAe,KAAKxU,CAAK,CAClC,CAEA,SAAS2U,GAAqB3U,EAAe4U,EAA8B,CACzE,MAAMC,EAAM7U,EAAM,SAAS,MAAM,EAC3B8U,EAAc9U,EAAM,MAAM,uBAAuB,EACjD+U,EAASD,EAAcA,EAAY,CAAC,EAAI,KACxCE,EAAK,oBAAoB,KAAKhV,CAAK,EAKnCuN,EAAmB,CAAE,SADX,EAAIqH,GAAaC,EAAM,EAAI,IACG,QAAS,CAAA,EACvD,OAAIG,IAAIzH,EAAM,EAAI,GAAG,EAAIqH,CAAS,OAC9BG,IAAQxH,EAAM,gBAAkBkH,GAAiBM,CAAM,GACpDxH,CACT,CAEA,SAAS0H,GAAeC,EAAiBN,EAA0C,CACjF,MAAMO,EAAUb,GAASY,CAAO,EAChC,GAAIC,EAAS,OAAOA,EAAQP,CAAS,EACrC,GAAIF,GAAcQ,CAAO,EAAG,OAAOP,GAAqBO,EAASN,CAAS,CAE5E,CAEA,SAASQ,GAAiBpV,EAAwB,CAChD,OAAOuU,GAAiB,IAAIvU,CAAK,GAAK0U,GAAc1U,CAAK,CAC3D,CAEA,SAASqV,GAAexX,EAAakE,EAAkD,CACrF,OAAOC,GAAkBnE,EAAIkE,EAAWqT,EAAgB,CAC1D,CAEA,SAASnL,GACPF,EACA3J,EACAK,EAC0B,CAC1B,MAAMyU,EAAUzU,EAAO,YAAY,EACnC,GAAI,CAACyU,EAAS,OAEd,MAAM3S,EAAOwH,EAAI,QACX,CAAE,SAAA1C,EAAU,MAAAQ,EAAO,KAAAP,EAAM,UAAAsN,EAAW,YAAA7M,EAAa,UAAAD,EAAW,MAAAtF,EAAO,MAAA8S,CAAA,EACvE/R,GAAoB9C,EAAQ8B,CAAI,EAE5BI,EAAWgD,GAAgBvF,EAASK,EAAO,YAAY,EAAGsJ,EAAI,QAAQ,WAAW,EAMjFwL,EAAQ5S,EAAS,KAAMG,GAAMA,EAAE,OAAS,KAAK,EAE7CyE,EAAY0N,GAAeC,EAASN,CAAS,EACnD,GAAI,CAACrN,EAAW,OAGZgO,GAAShO,EAAU,UAAY,MAAa,QAAU,KAE1D,KAAM,CAAE,QAAA2K,EAAS,QAAAE,CAAA,EAAYJ,GAAsB5R,EAASK,EAAQ8B,CAAI,EAElEyQ,EAAY7P,GAAc/C,EAASK,EAAO,WAAW,CAAC,EAMtDoO,EAASgE,GAAwB9I,EAAK3J,EAAS,CACnD,SAAAuC,EACA,MAAAkF,EACA,YAAAE,EACA,UAAAD,EACA,MAAAtF,EACA,MAAA8S,EACA,UAAAtC,EACA,WAAYN,GAAcnL,CAAS,EACnC,eAAiB+K,IAIXiD,KAAW,KAAK,KAAK,IAAIrD,EAAS,CAAE,QAAS,EAAG,EAQ7C,CAAE,UAPSnI,EAAI,KAAK,KAAK,KAAKmI,EAAS,CAC5C,GAAG3K,EACH,SAAAF,EACA,KAAAC,EACA,QAAA8K,EACA,GAAGE,CAAA,CACJ,CACQ,EACX,CACD,EAED,OAAOzD,EAAS,IAAMA,EAAO,QAAA,EAAY,MAC3C,sEAEqC,CACnC,KAAM,SACN,KAAK9E,EAAiC,CACpC,OAAAD,GAAYC,EAAKsL,GAAgBpL,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,yCCrGMuL,OAAyB,IAAI,CACjC,KAAM,KAAM,KAAM,KAAM,KAAM,KAC9B,IAAK,SAAU,QAAS,SAC1B,CAAC,EAED,SAASC,GAAmB5X,EAAsB,CAChD,OAAO2X,GAAmB,IAAI3X,EAAG,QAAQ,aAAa,CACxD,CAQA,MAAM6X,GACJ,sKAGF,SAASC,GAAuB9X,EAAsB,CACpD,OAAOA,EAAG,cAAc6X,EAA6B,IAAM,IAC7D,CAWO,SAASE,GAAW5V,EAA+C,CACxE,GAAI,CAACA,EAAO,OAAO,KACnB,MAAM4D,EAAO5D,EAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAA,EAAO,YAAA,EACxC,GAAI,CAAC4D,EAAM,OAAO,KAClB,MAAMC,EAASD,EAAK,MAAM,KAAK,EACzBiS,EAAYhS,EAAO,CAAC,EAC1B,IAAIiS,EAAyB,KACzBC,EAWJ,GAVIF,IAAc,SAAWA,IAAc,OAAQC,EAAO,QACjDD,IAAc,SAAWA,IAAc,OAAQC,EAAO,QACtDD,IAAc,SAAWA,IAAc,OAAQC,EAAO,QACtDD,IAAc,eAAiBA,IAAc,cACpDC,EAAO,QACPC,EAAU,UACDF,IAAc,eAAiBA,IAAc,gBACtDC,EAAO,QACPC,EAAU,SAER,CAACD,EAAM,OAAO,KAClB,MAAM1E,EAAQvN,EAAO,MAAM,CAAC,EACtBmS,EAAO5E,EAAM,SAAS,MAAM,EAC5B7H,EAAQ6H,EAAM,SAAS,OAAO,EACpC,OAAO2E,EAAU,CAAE,KAAAD,EAAM,QAAAC,EAAS,KAAAC,EAAM,MAAAzM,GAAU,CAAE,KAAAuM,EAAM,KAAAE,EAAM,MAAAzM,CAAA,CAClE,CAqBO,SAAS0M,GACd7V,EACA0V,EACA5V,EACAqC,EAAqB,CAAA,EACR,CACb,MAAM2T,EAAgBhW,GAAY,SAAS,UAC3C,GAAI,CAACgW,EACH,eAAQ,KAAK,8DAA8D,EACpE,CAAE,KAAAJ,EAAM,MAAO,CAAA,EAAI,MAAO,GAAI,MAAO,CAAC1V,CAAsB,EAAG,OAAQ,IAAM,CAAC,CAAA,EAYvF,MAAM+V,EAA8B,CAClC,KANAL,IAAS,QACL,QACAA,IAAS,QACP,cACA,oBAQN,IAAK,OAUL,UAAW,GACX,WAAY,UACZ,WAAY,UACZ,WAAY,SAAA,EAWd,GARIvT,EAAK,OAAM4T,EAAU,KAAO,SAC5B5T,EAAK,QAAO4T,EAAU,UAAY,IAOlC5T,EAAK,UAAW,CAClB,MAAM6T,EAAY7T,EAAK,UACvB,IAAI8T,EAAe,GACnBF,EAAU,QAAWG,GAAS,CAC5B,GAAI,CAACD,EAAc,CACjBA,EAAe,GACf,MACF,CACAD,EAAU,CACR,KAAAN,EACA,MAAOQ,EAAK,OAAS,CAAA,EACrB,MAAOA,EAAK,OAAS,CAAA,EACrB,MAAOA,EAAK,OAAS,CAAA,EAGrB,OAAQ,IAAM,CAAC,CAAA,CAChB,CACH,CACF,CAEA,MAAMC,EAAiBd,GAAmBrV,CAAO,EACjD,IAAIoW,EAAiC,KACjCC,EAAiC,KACjCC,EAAU,GACd,GAAIf,GAAuBvV,CAAO,EAMhC+V,EAAU,KAAO,eACRI,EACTJ,EAAU,KAAO,WACZ,CACLA,EAAU,KAAO,OACjBM,EAAkBrW,EAAQ,aAAa,aAAa,EACpDA,EAAQ,aAAa,cAAe,MAAM,EAC1CsW,EAAU,GACV,MAAMC,EAAOvW,EAAQ,aAAe,GAChCuW,EAAK,QAAUvW,EAAQ,gBACzBoW,EAAS,SAAS,cAAc,MAAM,EACtCA,EAAO,UAAY,aACnBA,EAAO,YAAcG,EACrBvW,EAAQ,cAAc,aAAaoW,EAAQpW,CAAO,EAEtD,CAEA,MAAMkW,EAAO,IAAIJ,EAAc9V,EAAS+V,CAAS,EACjD,MAAO,CACL,KAAAL,EACA,MAAOQ,EAAK,OAAS,CAAA,EACrB,MAAOA,EAAK,OAAS,CAAA,EACrB,MAAOA,EAAK,OAAS,CAAA,EACrB,OAAQ,IAAM,CACZ,GAAI,CACFA,EAAK,OAAA,CACP,MAAQ,CAER,CACIE,KAAe,OAAA,EACfE,IACED,IAAoB,KAAMrW,EAAQ,gBAAgB,aAAa,EAC9DA,EAAQ,aAAa,cAAeqW,CAAe,EAE5D,CAAA,CAEJ,CC1LA,MAAMG,GAAkB,kCAClBC,GAAyB,gDAE/B,SAASC,GACPC,EACApV,EACAqV,EACAC,EACe,CACf,MAAMC,EAA0B,CAAA,EAChC,UAAW3F,KAAQwF,EAAO,CACxB,MAAMI,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAU,IAAIxV,CAAS,EAC/BwV,EAAQ,aAAa,QAASH,CAAW,EACrCC,KAAuBE,CAAO,EAClC5F,EAAK,YAAY,aAAa4F,EAAS5F,CAAI,EAC3C4F,EAAQ,YAAY5F,CAAI,EACxB2F,EAAS,KAAKC,CAAO,CACvB,CACA,OAAOD,CACT,CAEA,SAASE,GAAYF,EAA+B,CAClD,UAAWha,KAAKga,EAAU,CACxB,MAAMnL,EAAQ7O,EAAE,kBACZ6O,GAAS7O,EAAE,aACbA,EAAE,WAAW,aAAa6O,EAAO7O,CAAC,EAClCA,EAAE,OAAA,EAEN,CACF,CAMA,MAAMma,GAA+E,CACnF,GAAI,CAAE,KAAM,WAAY,KAAM,CAAA,EAC9B,KAAM,CAAE,KAAM,WAAY,KAAM,EAAA,EAChC,KAAM,CAAE,KAAM,WAAY,KAAM,CAAA,EAChC,MAAO,CAAE,KAAM,WAAY,KAAM,EAAA,CACnC,EAEA,SAASC,EAASC,EAAiBhM,EAAiC,CAClE,GAAI,CAACA,EACH,MAAO,CACL,aAAc,QACd,UAAW,KAAO,CAAE,QAAAgM,IACpB,GAAI,CAAE,QAAS,CAAA,CAAE,EAGrB,KAAM,CAAE,KAAAC,EAAM,KAAAC,GAASJ,GAAS9L,CAAS,EACzC,MAAO,CACL,aAAc,QACd,UAAYuG,IAAO,CAAE,QAAAyF,EAAS,CAACC,CAAI,EAAG,GAAKC,EAAO3F,IAClD,GAAI,CAAE,QAAS,EAAG,CAAC0F,CAAI,EAAG,CAAA,CAAE,CAEhC,CAEA,SAASE,GAASnM,EAAiC,CACjD,GAAI,CAACA,EACH,MAAO,CACL,aAAc,QACd,UAAW,KAAO,CAAE,QAAS,EAAG,OAAQ,YAAA,GACxC,GAAI,CAAE,QAAS,EAAG,OAAQ,WAAA,CAAY,EAG1C,KAAM,CAAE,KAAAiM,EAAM,KAAAC,GAASJ,GAAS9L,CAAS,EACnCoM,EAAaH,IAAS,WAAa,IAAM,IAC/C,MAAO,CACL,aAAc,QACd,UAAY1F,IAAO,CAAE,QAAS,EAAG,OAAQ,aAAc,CAAC6F,CAAU,EAAG,GAAG,EAAIF,EAAO3F,CAAC,KAAA,GACpF,GAAI,CAAE,QAAS,EAAG,OAAQ,YAAa,CAAC6F,CAAU,EAAG,CAAA,CAAE,CAE3D,CAEA,SAASC,GAAUC,EAAqD,CACtE,MAAO,CACL,aAAc,QACd,UAAW,KAAO,CAAE,OAAQ,EAAG,gBAAiBA,CAAA,GAChD,GAAI,CAAE,OAAQ,CAAA,CAAE,CAEpB,CAEA,SAASC,GAAUvM,EAAoC,CACrD,MAAMkM,EAAOlM,IAAc,KAAO,EAAI,GACtC,MAAO,CACL,aAAc,QACd,UAAW,GACX,UAAW,KAAO,CAAE,SAAU,IAAMkM,CAAA,GACpC,GAAI,CAAE,SAAU,CAAA,CAAE,CAEtB,CAEA,SAASM,GAASxM,EAAoC,CACpD,MAAMkM,EAAOlM,IAAc,KAAO,EAAI,GACtC,MAAO,CACL,aAAc,QACd,UAAW,GACX,UAAW,KAAO,CAChB,SAAU,IAAMkM,EAChB,QAAS,EACT,SAAU,GAAKA,EACf,gBAAiBlM,IAAc,KAAO,cAAgB,UAAA,GAExD,GAAI,CAAE,SAAU,EAAG,QAAS,EAAG,SAAU,CAAA,CAAE,CAE/C,CAEA,SAASyM,GAASH,EAAoC,CACpD,MAAMI,EAAKJ,IAAW,SAAW,WAAa,SAC9C,MAAO,CACL,aAAc,QACd,MAAO,CAAC,CAAE,MAAAK,KAAY,CACpB,MAAMhB,EAAWJ,GAAUoB,EAAM,MAAO,eAAgBtB,EAAe,EACvE,MAAO,CACL,QAASM,EACT,UAAW,CAAE,SAAU,qBAAqBe,CAAE,GAAA,EAC9C,QAAS,CAAE,SAAU,wBAAwBA,CAAE,GAAA,EAC/C,QAAS,IAAMb,GAAYF,CAAQ,CAAA,CAEvC,CAAA,CAEJ,CAMA,MAAMiB,GAAuC,CAC3C,YAAab,EAAS,CAAC,EACvB,eAAgBA,EAAS,EAAG,EAC5B,eAAgBA,EAAS,EAAG,EAC5B,eAAgBA,EAAS,EAAG,IAAI,EAChC,iBAAkBA,EAAS,EAAG,MAAM,EACpC,iBAAkBA,EAAS,EAAG,MAAM,EACpC,kBAAmBA,EAAS,EAAG,OAAO,EAEtC,YAAaI,GAAA,EACb,eAAgBA,GAAS,IAAI,EAC7B,iBAAkBA,GAAS,MAAM,EACjC,iBAAkBA,GAAS,MAAM,EACjC,kBAAmBA,GAAS,OAAO,EAEnC,aAAcE,GAAU,SAAS,EACjC,gBAAiBA,GAAU,UAAU,EACrC,kBAAmBA,GAAU,QAAQ,EAErC,gBAAiBE,GAAU,IAAI,EAC/B,kBAAmBA,GAAU,MAAM,EAEnC,eAAgBC,GAAS,IAAI,EAC7B,iBAAkBA,GAAS,MAAM,EAEjC,eAAgBC,GAAS,QAAQ,EACjC,iBAAkBA,GAAS,KAAK,EAEhC,cAAe,CACb,aAAc,QACd,MAAO,CAAC,CAAE,QAAA5X,EAAS,MAAA8X,KAAY,CAE7B,MAAME,EAAc,IADH,WAAW,OAAO,iBAAiBhY,CAAO,EAAE,QAAQ,GAAK,IACxC,CAAC,KAC7B8W,EAAWJ,GACfoB,EAAM,MACN,sBACArB,GACC3Z,GAAM,CACLA,EAAE,MAAM,YAAckb,CACxB,CAAA,EAEF,UAAW7G,KAAQ2G,EAAM,MACvB3G,EAAK,MAAM,gBAAkB,SAE/B,MAAO,CACL,QAAS2G,EAAM,MACf,UAAW,CAAE,UAAW,EAAG,QAAS,IAAK,SAAU,IAAK,OAAQ,GAAA,EAChE,QAAS,CAAE,UAAW,EAAG,QAAS,EAAG,SAAU,EAAG,OAAQ,CAAA,EAC1D,QAAS,IAAMd,GAAYF,CAAQ,CAAA,CAEvC,CAAA,CAEJ,EAcMmB,GAA+C,CACnD,MAAO,CACL,KAAM,IACN,WAAY,cACZ,aAAc,eACd,SAAU,IACV,WAAY,QAAA,EAEd,KAAM,CACJ,KAAM,IACN,WAAY,eACZ,aAAc,cACd,SAAU,IACV,WAAY,OAAA,EAEd,GAAI,CACF,KAAM,IACN,WAAY,gBACZ,aAAc,aACd,SAAU,IACV,WAAY,OAAA,EAEd,KAAM,CACJ,KAAM,IACN,WAAY,aACZ,aAAc,gBACd,SAAU,IACV,WAAY,QAAA,CAEhB,EAEMC,OAAgB,IACtB,UAAWC,KAAW,OAAO,KAAKF,EAAc,EAC9CC,GAAU,IAAI,cAAcC,CAAO,EAAE,EACrCD,GAAU,IAAI,eAAeC,CAAO,EAAE,EAGxC,SAASC,GAAalb,EAAsE,CAC1F,MAAMuM,EAAIvM,EAAK,MAAM,4CAA4C,EACjE,OAAKuM,EACE,CAAE,KAAMA,EAAE,CAAC,EAAyB,IAAKwO,GAAexO,EAAE,CAAC,CAAC,CAAA,EADpD,IAEjB,CAEA,SAAS4O,GAAgBzY,EAA2BI,EAA0B,CAC5E,GAAI,CAACJ,EAAO,MAAO,eACnB,MAAMqF,EAAUrF,EAAM,KAAA,EACtB,OAAIqF,EAAQ,WAAW,IAAI,GACR,OAAO,iBAAiBjF,CAAO,EAAE,iBAAiBiF,CAAO,EAAE,KAAA,GACzDA,CAGvB,CAOA,SAASqT,GACP3B,EACA4B,EACAC,EACgB,CAChB,MAAMC,EAAyB,CAAA,EAC/B,UAAWtH,KAAQwF,EAAO,CAIxBxF,EAAK,MAAM,QAAU,eACrBA,EAAK,MAAM,SAAW,WACtBA,EAAK,MAAM,OAAS,aAEpB,IAAIoF,EAA2B,KAC/B,GAAIiC,EAAiB,CAKnB,IAJAjC,EAAO,SAAS,cAAc,MAAM,EACpCA,EAAK,UAAY,gBACjBA,EAAK,MAAM,QAAU,eACrBA,EAAK,MAAM,WAAa,qBACjBpF,EAAK,YAAYoF,EAAK,YAAYpF,EAAK,UAAU,EACxDA,EAAK,YAAYoF,CAAI,CACvB,CAEA,MAAMmC,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,UAAY,SAChBA,EAAI,MAAM,QACR,0FACFA,EAAI,MAAM,gBAAkBH,EAC5BpH,EAAK,YAAYuH,CAAG,EAEpBD,EAAO,KAAK,CAAE,IAAAC,EAAK,KAAAnC,CAAA,CAAM,CAC3B,CACA,OAAOkC,CACT,CAEA,MAAME,GAAY,IAAI,IAAI,CAAC,GAAG,OAAO,KAAKZ,EAAU,EAAG,GAAGG,EAAS,CAAC,EAEpE,SAASjD,GAAexX,EAAakE,EAAkD,CACrF,OAAOC,GAAkBnE,EAAIkE,EAAYtD,GAAMsa,GAAU,IAAIta,CAAC,CAAC,CACjE,CAEA,SAASua,GACPza,EACAuX,EACe,CACf,OAAIA,IAAS,QAAgBvX,EAAM,MAC/BuX,IAAS,QAAgBvX,EAAM,MAC5BA,EAAM,KACf,CAEA,SAAS0a,GACPlP,EACA3J,EACAK,EACA6E,EAC0B,CAC1B,KAAM,CAAE,KAAAwQ,EAAM,IAAAoD,CAAA,EAAQ5T,EAChB6T,EAAUrD,IAAS,QACnBvT,EAAOwH,EAAI,QACX,CAAE,SAAA1C,EAAU,MAAAQ,EAAO,KAAAP,EAAM,YAAAS,EAAa,UAAAD,EAAW,MAAAtF,EAAO,MAAA8S,CAAA,EAC5D/R,GAAoB9C,EAAQ8B,CAAI,EAC5B,CAAE,KAAM6P,CAAA,EAAYlB,GAAiBzQ,EAAO,YAAY,EAAGqQ,GAAkB,QAASvO,CAAI,CAAC,EAE3F6W,EAAY,QAAQF,EAAI,IAAI,GAK5BG,EAA0B,CAC9BR,EACAvG,IACiB,CACjB,MAAMgH,EAAKvP,EAAI,KAAK,KAAK,SAASsI,GAAeC,CAAI,CAAC,EACtDuG,OAAAA,EAAO,QAAQ,CAAC,CAAE,IAAAC,EAAK,KAAAnC,CAAA,EAAQ7E,IAAM,CACnC,MAAMyH,EAASxP,EAAI,KAAK,KAAK,SAAA,EAC7B,GAAIoP,EAAS,CACX,MAAMK,EAAYnS,EAAW,GACvBoS,EAAYpS,EAAW,GACvBqS,EAAUrS,EAAW,GAE3BkS,EAAO,OACLT,EACA,CAAE,CAACM,CAAS,EAAG,EAAG,gBAAiBF,EAAI,UAAA,EACvC,CAAE,CAACE,CAAS,EAAG,EAAG,SAAUI,EAAW,KAAAlS,CAAA,CAAK,EAQ9CiS,EAAO,IAAIT,EAAK,CAAE,gBAAiBI,EAAI,aAAc,EAErDK,EAAO,GAAGT,EAAK,CAAE,CAACM,CAAS,EAAG,EAAG,SAAUK,EAAW,KAAAnS,EAAM,EACxDqP,GAEF4C,EAAO,OACL5C,EACA,CAAE,QAAS,EAAG,CAACuC,EAAI,QAAQ,EAAGA,EAAI,UAAA,EAClC,CAAE,QAAS,EAAG,CAACA,EAAI,QAAQ,EAAG,EAAG,SAAUQ,EAAS,KAAApS,CAAA,EACpD,GAAA,CAGN,MACEiS,EAAO,OACLT,EACA,CAAE,CAACM,CAAS,EAAG,EAAG,gBAAiBF,EAAI,YAAA,EACvC,CAAE,CAACE,CAAS,EAAG,EAAG,SAAA/R,EAAU,KAAAC,CAAA,CAAK,EAGrCgS,EAAG,IAAIC,EAAQzH,EAAIM,CAAO,CAC5B,CAAC,EACMkH,CACT,EAMA,IAAIT,EAAyB,CAAA,EAEzBX,EAEJ,MAAMyB,EAAe1D,GAAW7V,EAAS,QAAS2J,EAAI,KAAM,CAC1D,UAAY6P,GAAa,CACvB1B,EAAQ0B,EACR/K,GAAQ,QAAA,CACV,CAAA,CACD,EACD,GAAI8K,EAAa,MAAM,SAAW,EAAG,CACnCA,EAAa,OAAA,EACb,MACF,CACAzB,EAAQyB,EAER,MAAM9K,EAASgE,GAAwB9I,EAAK3J,EAAS,CACnD,SAAUuF,GAAgBvF,EAASK,EAAO,YAAY,EAAGsJ,EAAI,QAAQ,WAAW,EAChF,MAAAlC,EACA,YAAAE,EACA,UAAAD,EACA,MAAAtF,EACA,MAAA8S,EACA,eAAiBhD,GAAS,CACxB,GAAI,CAAC4F,GAASA,EAAM,MAAM,SAAW,EAAG,OAAO,KAC/C,MAAMS,EAAQF,GAAgBhY,EAAO,UAAU,EAAGL,CAAO,EACzDyY,EAASH,GAAcR,EAAM,MAAOS,EAAOQ,CAAO,EAGlD,SAAW,CAAE,IAAAL,EAAK,KAAAnC,CAAA,IAAUkC,EAC1B9O,EAAI,KAAK,KAAK,IAAI+O,EAAK,CACrB,CAACM,CAAS,EAAGD,EAAU,EAAI,EAC3B,gBAAiBA,EAAUD,EAAI,WAAaA,EAAI,YAAA,CACjD,EACGvC,GACF5M,EAAI,KAAK,KAAK,IAAI4M,EAAM,CAAE,QAAS,EAAG,CAACuC,EAAI,QAAQ,EAAGA,EAAI,WAAY,EAI1E,MAAO,CAAE,UADSG,EAAwBR,EAAQvG,CAAI,CAC7C,CACX,CAAA,CACD,EAED,MAAO,IAAM,CACXzD,GAAQ,QAAA,EACR8K,EAAa,OAAA,CACf,CACF,CAEA,SAAS1P,GACPF,EACA3J,EACAK,EAC0B,CAC1B,MAAMyU,EAAUzU,EAAO,YAAY,EACnC,GAAI,CAACyU,GAAW,CAAC6D,GAAU,IAAI7D,CAAO,EAAG,OACzC,MAAM4D,EAAMN,GAAatD,CAAO,EAChC,GAAI4D,EAAK,OAAOG,GAAelP,EAAK3J,EAASK,EAAQqY,CAAG,EACxD,MAAMpF,EAAOyE,GAAWjD,CAAO,EAEzB3S,EAAOwH,EAAI,QACX,CAAE,SAAA1C,EAAU,MAAAQ,EAAO,KAAAP,EAAM,UAAAsN,EAAW,YAAA7M,EAAa,UAAAD,EAAW,MAAAtF,EAAO,MAAA8S,CAAA,EACvE/R,GAAoB9C,EAAQ8B,CAAI,EAE5BsX,EAAYjE,GAAWnV,EAAO,UAAU,CAAC,EACzCsQ,EAAY8I,GAAW,MAAQnG,EAAK,aACpCvB,EAAcjB,GAClBzQ,EAAO,YAAY,EACnBqQ,GAAkBC,EAAWxO,CAAI,EACjCuO,GAAkB,QAASvO,CAAI,CAAA,EAE3B6P,EAAwBZ,GAAaW,EAAY,KAAMA,EAAY,KAAK,EACxE2H,EAAc3H,EAAY,KAC1B4H,EAAcF,GAAW,UAAY,SAAW,CAACnG,EAAK,MAItDsC,EAAO6D,GAAW,MAAQnG,EAAK,WAAa,GAKlD,IAAIwE,EAEJ,MAAMyB,EAAe1D,GAAW7V,EAAS2Q,EAAWhH,EAAI,KAAM,CAC5D,KAAAiM,EACA,GAAI6D,GAAW,MAAQ,CAAE,MAAO,EAAA,EAAS,CAAA,EACzC,UAAYD,GAAa,CACvB1B,EAAQ0B,EACR/K,GAAQ,QAAA,CACV,CAAA,CACD,EACDqJ,EAAQyB,EAER,MAAM9K,EAASgE,GAAwB9I,EAAK3J,EAAS,CACnD,SAAUuF,GAAgBvF,EAASK,EAAO,YAAY,EAAGsJ,EAAI,QAAQ,WAAW,EAChF,MAAAlC,EACA,YAAAE,EACA,UAAAD,EACA,MAAAtF,EACA,MAAA8S,EAMA,WAAY,6BACZ,eAAiBhD,GAAS,CACxB,GAAI,CAAC4F,EAAO,OAAO,KACnB,IAAIhG,EACA3K,EACAC,EACAwS,EACAC,EACJ,GAAIvG,EAAK,MAAO,CAId,MAAMjU,EAASiU,EAAK,MAAM,CAAE,QAAAtT,EAAS,MAAA8X,EAAO,UAAAtD,EAAW,EACvD1C,EAAUzS,EAAO,QACjB8H,EAAY9H,EAAO,UACnB+H,EAAU/H,EAAO,QACbA,EAAO,UAASua,EAAeva,EAAO,QAC5C,KAAO,CACL,GAAI,CAACiU,EAAK,WAAa,CAACA,EAAK,GAAI,OAAO,KACxC,MAAMwG,EAASlB,GAAkBd,EAAOnH,CAAS,EACjD,GAAImJ,EAAO,SAAW,EAAG,OAAO,KAIhC,GAHAhI,EAAUgI,EACV3S,EAAYmM,EAAK,UAAUkB,CAAS,EACpCpN,EAAUkM,EAAK,GACXqG,EAAa,CACf,MAAMI,EAAQpJ,IAAc,QAAUmH,EAAM,MAAQA,EAAM,MAC1D+B,EAAa/B,EAAM,MAAM,IAAK3G,GAAS4I,EAAM,OAAQC,GAAM7I,EAAK,SAAS6I,CAAC,CAAC,CAAC,CAC9E,CACF,CACA,MAAMd,EAAKvP,EAAI,KAAK,KAAK,SAASsI,GAAeC,CAAI,CAAC,EAKtD,GADAvI,EAAI,KAAK,KAAK,IAAImI,EAAS3K,CAAS,EAChC0S,EACF,QAASnI,EAAI,EAAGA,EAAImI,EAAW,OAAQnI,IAAK,CAC1C,MAAMuI,EAAQJ,EAAWnI,CAAC,EACtBuI,EAAM,SAAW,GACrBf,EAAG,OAAOe,EAAO9S,EAAW,CAAE,GAAGC,EAAS,SAAAH,EAAU,KAAAC,EAAM,QAAA8K,GAAWN,EAAIgI,CAAW,CACtF,MAEAR,EAAG,OAAOpH,EAAS3K,EAAW,CAAE,GAAGC,EAAS,SAAAH,EAAU,KAAAC,EAAM,QAAA8K,EAAS,EAEvE,MAAM+B,EAA2D,CAAE,UAAWmF,CAAA,EAC9E,OAAIU,MAAoB,QAAUA,GAC3B7F,CACT,CAAA,CACD,EAED,MAAO,IAAM,CACXtF,GAAQ,QAAA,EACR8K,EAAa,OAAA,CACf,CACF,sEAEmC,CACjC,KAAM,OACN,KAAK5P,EAAiC,CACpC,OAAAD,GAAYC,EAAKsL,GAAgBpL,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,yCC3jBMqQ,GAA2C,CAC/C,YAAa,CAAE,KAAM,oBAAqB,GAAI,iBAAA,EAC9C,cAAe,CAAE,KAAM,oBAAqB,GAAI,iBAAA,EAChD,cAAe,CAAE,KAAM,oBAAqB,GAAI,iBAAA,EAChD,eAAgB,CAAE,KAAM,oBAAqB,GAAI,iBAAA,EACjD,gBAAiB,CACf,KAAM,wBACN,GAAI,0BACJ,aAAc,EAAA,EAEhB,iBAAkB,CAChB,KAAM,6BACN,GAAI,gCAAA,EAEN,mBAAoB,CAClB,KAAM,2BACN,GAAI,8BAAA,CAER,EAEMC,GAAgB,IAAI,IAAI,OAAO,KAAKD,EAAY,CAAC,EAEvD,SAASE,GAAYld,EAAuB,CAC1C,OAAOid,GAAc,IAAIjd,CAAI,CAC/B,CAEA,SAAS+X,GAAexX,EAAakE,EAAkD,CACrF,OAAOC,GAAkBnE,EAAIkE,EAAWyY,EAAW,CACrD,CAEA,SAASvQ,GACPF,EACA3J,EACAK,EAC0B,CAC1B,MAAMyU,EAAUzU,EAAO,YAAY,EACnC,GAAI,CAACyU,EAAS,OACd,MAAMtM,EAAS0R,GAAapF,CAAO,EACnC,GAAI,CAACtM,EAAQ,OAEb,MAAMrG,EAAOwH,EAAI,QACX,CAAE,SAAA1C,EAAU,MAAAQ,EAAO,KAAAP,EAAM,YAAAS,EAAa,UAAAD,EAAW,MAAAtF,EAAO,MAAA8S,CAAA,EAC5D/R,GAAoB9C,EAAQ8B,CAAI,EAE5BgF,EAA6CqB,EAAO,aACtD,CAAE,SAAUA,EAAO,KAAM,QAAS,CAAA,EAClC,CAAE,SAAUA,EAAO,IAAA,EACjBpB,EAA2CoB,EAAO,aACpD,CAAE,SAAUA,EAAO,GAAI,QAAS,CAAA,EAChC,CAAE,SAAUA,EAAO,EAAA,EAEjB,CAAE,QAAAsJ,EAAS,QAAAE,CAAA,EAAYJ,GAAsB5R,EAASK,EAAQ8B,CAAI,EAElEyQ,EAAY7P,GAAc/C,EAASK,EAAO,WAAW,CAAC,EAEtDoO,EAASgE,GAAwB9I,EAAK3J,EAAS,CACnD,SAAUuF,GAAgBvF,EAASK,EAAO,YAAY,EAAGsJ,EAAI,QAAQ,WAAW,EAChF,MAAAlC,EACA,YAAAE,EACA,UAAAD,EACA,MAAAtF,EACA,MAAA8S,EACA,UAAAtC,EACA,WAAYN,GAAcnL,CAAS,EACnC,eAAiB+K,IAQR,CAAE,UAPSvI,EAAI,KAAK,KAAK,OAAOmI,EAAS3K,EAAW,CACzD,GAAGC,EACH,SAAAH,EACA,KAAAC,EACA,QAAA8K,EACA,GAAGE,CAAA,CACJ,CACQ,EACX,CACD,EAED,OAAOzD,EAAS,IAAMA,EAAO,QAAA,EAAY,MAC3C,sEAEqC,CACnC,KAAM,SACN,KAAK9E,EAAiC,CACpC,OAAAD,GAAYC,EAAKsL,GAAgBpL,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,yCClFMwQ,GAAwC,CAC5C,GAAI,KACJ,GAAI,KACJ,KAAM,OACN,KAAM,OACN,MAAO,OACT,EAWO,SAASC,GAAiB1a,EAAoC,CACnE,MAAM6D,EAAS7D,EAAM,KAAA,EAAO,MAAM,KAAK,EACjC4D,EAAOC,EAAO,CAAC,EACrB,GAAID,IAAS,UAAY,CAACA,EAAK,WAAW,SAAS,EAAG,OAAO,KAC7D,MAAM+W,EAAW/W,IAAS,SAAW,GAAKA,EAAK,MAAM,CAAgB,EAC/D2H,EAAYkP,GAAWE,CAAQ,EACrC,GAAI,CAACpP,EAAW,OAAO,KAEvB,IAAIuK,EAAa,SACb8E,EAAO,EACX,UAAWzV,KAAStB,EAAO,MAAM,CAAC,EAAG,CACnC,GAAIsB,IAAU,SAAWA,IAAU,SAAU,CAC3C2Q,EAAO3Q,EACP,QACF,CACA,MAAM1H,EAAI,SAAS0H,EAAO,EAAE,EACxB,OAAO,SAAS1H,CAAC,GAAKA,EAAI,IAAGmd,EAAOnd,EAC1C,CACA,MAAO,CAAE,UAAA8N,EAAW,KAAAuK,EAAM,KAAA8E,CAAA,CAC5B,CAEA,SAASJ,GAAYxa,EAAwB,CAC3C,OAAO0a,GAAiB1a,CAAK,IAAM,IACrC,CAEA,SAASqV,GAAexX,EAAakE,EAAkD,CACrF,OAAOC,GAAkBnE,EAAIkE,EAAWyY,EAAW,CACrD,CAiBA,MAAMK,GAAsC,CAC1C,GAAI,CACF,cAAe,SACf,WAAY,gBACZ,UAAW,SACX,aAAc,aACd,YAAa,gBACb,YAAa,KAAA,EAEf,KAAM,CACJ,cAAe,SACf,WAAY,gBACZ,UAAW,SACX,aAAc,gBACd,YAAa,aACb,YAAa,OAAA,EAEf,KAAM,CACJ,cAAe,MACf,WAAY,eACZ,UAAW,SACX,aAAc,cACd,YAAa,eACb,YAAa,KAAA,EAEf,MAAO,CACL,cAAe,MACf,WAAY,eACZ,UAAW,SACX,aAAc,eACd,YAAa,cACb,YAAa,OAAA,CAEjB,EASA,SAASC,GACP1a,EACAwa,EACAG,EACa,CACb,MAAMC,EAAK,OAAO,iBAAiB5a,CAAO,EACpC6a,EAAeD,EAAG,WAAa,SAAW,GAAKA,EAAG,SAClDE,EAAeF,EAAG,SAEpBA,EAAG,WAAa,WAAU5a,EAAQ,MAAM,SAAW,YACnD4a,EAAG,WAAa,YAAW5a,EAAQ,MAAM,SAAW,UAExD,MAAM+a,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,kBAClBA,EAAM,aACJ,QACA,yDAAyDJ,EAAK,aAAa,gCAAA,EAG7E,MAAMlS,EAAwB,CAAA,EACxBuS,EAAW,SAAS,uBAAA,EAGpBC,EAAU,GAAGN,EAAK,UAAU,QAClC,QAASjJ,EAAI,EAAGA,EAAI8I,EAAM9I,IAAK,CAC7B,MAAMwJ,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,WAClBA,EAAM,aACJ,QACA,0FAA0FD,CAAO,EAAA,EAEnGD,EAAS,YAAYE,CAAK,EAC1BzS,EAAO,KAAKyS,CAAK,CACnB,CACA,OAAAH,EAAM,YAAYC,CAAQ,EAC1Bhb,EAAQ,YAAY+a,CAAK,EAElB,CAAE,MAAAA,EAAO,OAAAtS,EAAQ,aAAAoS,EAAc,aAAAC,CAAA,CACxC,CAEA,SAASjR,GACPF,EACA3J,EACAK,EAC0B,CAC1B,MAAMyU,EAAUzU,EAAO,YAAY,EACnC,GAAI,CAACyU,EAAS,OACd,MAAMqG,EAASb,GAAiBxF,CAAO,EACvC,GAAI,CAACqG,EAAQ,OAEb,MAAMhZ,EAAOwH,EAAI,QACX,CAAE,UAAAwB,EAAW,KAAAuK,EAAM,KAAA8E,CAAA,EAASW,EAC5BR,EAAOF,GAAKtP,CAAS,EACrB,CAAE,SAAAlE,EAAU,KAAAC,EAAM,YAAAS,EAAa,UAAAD,EAAW,MAAAtF,EAAO,MAAA8S,GACrD/R,GAAoB9C,EAAQ8B,CAAI,EAC5B6P,EAAUrP,EAAStC,EAAO,YAAY,EAAGqQ,GAAkB,OAAWvO,CAAI,CAAC,EAM3EiZ,EAAY1F,IAAS,QAAU,EAAI,EACnC2F,EAAU3F,IAAS,QAAU,EAAI,EACjC+B,EAAS/B,IAAS,QAAUiF,EAAK,YAAcA,EAAK,aAEpDW,EAAQZ,GAAiB1a,EAAwBwa,EAAMG,CAAI,EACjEhR,EAAI,KAAK,KAAK,IAAI2R,EAAM,OAAQ,CAAE,CAACX,EAAK,SAAS,EAAGS,EAAW,gBAAiB3D,EAAQ,EAExF,MAAMnX,EAAU,IAAY,CAC1BqJ,EAAI,KAAK,KAAK,aAAa2R,EAAM,MAAM,EACvCA,EAAM,MAAM,OAAA,EACZ,MAAM7d,EAAKuC,EACPsb,EAAM,eAAiB,IAAI7d,EAAG,MAAM,eAAe,UAAU,EAC7D6d,EAAM,eAAiB,WAAW7d,EAAG,MAAM,eAAe,UAAU,CAC1E,EAEMgR,EAASgE,GAAwB9I,EAAK3J,EAAS,CACnD,SAAUuF,GAAgBvF,EAASK,EAAO,YAAY,EAAGsJ,EAAI,QAAQ,WAAW,EAChF,MAAO,EACP,YAAAhC,EACA,UAAAD,EACA,MAAAtF,EACA,MAAA8S,EACA,WAAY,YACZ,eAAiBhD,IAQR,CAAE,UAPSvI,EAAI,KAAK,KAAK,GAAG2R,EAAM,OAAQ,CAC/C,CAACX,EAAK,SAAS,EAAGU,EAClB,SAAApU,EACA,KAAAC,EACA,QAAS,CAAE,KAAM8K,EAAS,KAAM2I,EAAK,WAAA,EACrC,GAAGzI,CAAA,CACJ,CACQ,EACX,CACD,EAED,MAAO,IAAM,CACXzD,GAAQ,QAAA,EACRnO,EAAA,CACF,CACF,sEAEqC,CACnC,KAAM,SACN,KAAKqJ,EAAiC,CACpC,OAAAD,GAAYC,EAAKsL,GAAgBpL,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,6DC/NM8O,GAAY,IAAI,IAAI,CAAC,WAAY,sBAAuB,mBAAmB,CAAC,EAElF,SAAS1D,GAAexX,EAAakE,EAAkD,CACrF,OAAOC,GAAkBnE,EAAIkE,EAAYtD,GAAMsa,GAAU,IAAIta,CAAC,CAAC,CACjE,CAEA,SAASwL,GAASF,EAAqB3J,EAAkBK,EAA2B,CAClF,MAAMyU,EAAUzU,EAAO,YAAY,EACnC,GAAI,CAACyU,GAAW,CAAC6D,GAAU,IAAI7D,CAAO,EAAG,OAGzC,MAAMsC,EADetC,IAAY,sBACL,WAAa,WAEnC3S,EAAOwH,EAAI,QACX6K,EAAY7R,EAAStC,EAAO,cAAc,EAAG8B,EAAK,SAAS,EAC3DoZ,EAAW5Y,EAAStC,EAAO,mBAAmB,EAAG,GAAKmU,CAAS,EAC/DgH,EAAS7Y,EAAStC,EAAO,iBAAiB,EAAG,IAAMmU,CAAS,EAE5DpS,EAAQS,GAAWxC,EAAO,UAAU,CAAC,GAAK,GAG1CsH,EAAc,SAAStH,EAAO,iBAAiB,GAAK,YAAY,IAChEqH,EAAY,SAASrH,EAAO,eAAe,GAAK,YAAY,IAC5DuS,EAAY7P,GAAc/C,EAASK,EAAO,WAAW,CAAC,EAE5DsJ,EAAI,KAAK,KAAK,OACZ3J,EACA,CAAE,CAACoX,CAAI,EAAGmE,CAAA,EACV,CACE,CAACnE,CAAI,EAAGoE,EACR,KAAM,OACN,cAAe,CACb,QAAS5I,EACT,MAAOjL,EACP,IAAKD,EACL,MAAAtF,CAAA,CACF,CACF,CAIJ,sEAEuC,CACrC,KAAM,WACN,KAAKuH,EAAiC,CACpC,OAAAD,GAAYC,EAAKsL,GAAgBpL,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,yCChCO,SAAS4R,GACdC,EACAC,EACAC,EACAC,EACgB,CAChB,MAAMC,EAAeD,GAAmBF,EAAS,SAC3C/Y,EAA2B,CAC/B,QAAS,GACT,SAAUkZ,EACV,WAAYH,EAAS,WACrB,UAAW,EAAA,EAEb,GAAI,CAACC,EAAa,OAAOhZ,EAEzB,MAAMa,GAAUiY,GAAO,IAAI,OAAO,MAAM,KAAK,EAAE,OAAO,OAAO,EAC7D,GAAIjY,EAAO,SAAS,MAAM,EAAG,OAAOb,EAEpC,IAAImZ,EAAWD,EACXE,EAAaL,EAAS,WACtBM,EAAY,GAChB,UAAWvZ,KAAKe,EACd,GAAIf,IAAM,cAAesZ,EAAa,WAC7BtZ,IAAM,aAAcuZ,EAAY,OACpC,CACH,MAAM5e,EAAI,WAAWqF,CAAC,EAClB,OAAO,SAASrF,CAAC,GAAKA,EAAI,IAAG0e,EAAW1e,EAC9C,CAEF,MAAO,CAAE,QAAS,GAAM,SAAA0e,EAAU,WAAAC,EAAY,UAAAC,CAAA,CAChD,CCZO,SAASC,GAAmBC,EAAqC,CACtE,OAAOjZ,GAAoBiZ,CAAM,CACnC,CAEA,SAASC,GAAc3Q,EAAiBvO,EAAoB,CAC1D+I,EAAYwF,EAAM,OAAQvO,CAAI,EAC1BuO,EAAM,SAASxF,EAAYwF,EAAM,QAASvO,CAAI,EAC9CuO,EAAM,QAAQxF,EAAYwF,EAAM,OAAQvO,CAAI,CAClD,CAEO,SAASmf,GAA0Bvc,EAA6C,CACrF,MAAM/C,EAAO+C,EAAW,KAIxB,IAAIwc,EAAiD,KAErD,MAAMC,EAAa,CAACC,EAAsBvV,EAAkBC,EAAcuV,IAAkC,CAC1G1f,EAAK,aAAayf,CAAO,EACzB,MAAME,EAAcF,EAAQ,sBAAA,EAAwB,OACpDzf,EAAK,IAAIyf,EAAS,CAAE,OAAQE,EAAa,EACzC3f,EAAK,GAAGyf,EAAS,CACf,OAAQ,OACR,SAAAvV,EACA,KAAAC,EACA,WAAY,IAAM,CAKhBnK,EAAK,IAAIyf,EAAS,CAAE,WAAY,SAAU,EAC1CC,IAAA,CACF,CAAA,CACD,CACH,EAEME,EAAc,CAACH,EAAsBvV,EAAkBC,EAAcuV,IAAkC,CAC3G1f,EAAK,aAAayf,CAAO,EACzB,MAAME,EAAcF,EAAQ,sBAAA,EAAwB,OACpDzf,EAAK,IAAIyf,EAAS,CAAE,OAAQE,EAAa,EACzC3f,EAAK,GAAGyf,EAAS,CAAE,OAAQ,EAAG,SAAAvV,EAAU,KAAAC,EAAM,WAAAuV,EAAY,CAC5D,EAEMG,EAAa,CAACT,EAAqBlV,EAAkBC,IAAuB,CAChFnK,EAAK,aAAaof,CAAM,EACxBpf,EAAK,GAAGof,EAAQ,CAAE,UAAW,EAAG,SAAAlV,EAAU,KAAAC,EAAM,CAClD,EAEM2V,EAAa,CAACV,EAAqBlV,EAAkBC,IAAuB,CAChFnK,EAAK,aAAaof,CAAM,EACxBpf,EAAK,GAAGof,EAAQ,CAAE,UAAW,EAAG,SAAAlV,EAAU,KAAAC,EAAM,CAClD,EA+EA,MAAO,CAAE,mBA7EmBsE,GAA8B,CACxD,UAAWa,KAAKb,EACVa,EAAE,SAAStP,EAAK,IAAIsP,EAAE,QAAS,CAAE,OAAQ,EAAG,EAC5CA,EAAE,QAAU,CAAC6P,GAAmB7P,EAAE,MAAM,GAC1CtP,EAAK,IAAIsP,EAAE,OAAQ,CAAE,UAAW,EAAG,CAGzC,EAsE6B,iBApEHZ,GAA0B,CAC9CA,EAAM,SAAS1O,EAAK,IAAI0O,EAAM,QAAS,CAAE,WAAY,SAAU,EAC/DA,EAAM,QAAU,CAACyQ,GAAmBzQ,EAAM,MAAM,GAClD1O,EAAK,IAAI0O,EAAM,OAAQ,CAAE,UAAW,EAAG,WAAY,UAAW,EAEhE2Q,GAAc3Q,EAAO,YAAY,CACnC,EA8D+C,KA5DlC,CAACA,EAAiBtJ,IAA6B,CAc1D,GAbAma,GAAmB,KAAA,EACnBA,EAAoB,KAIpBrW,EAAYwF,EAAM,OAAQ,YAAY,EAClCA,EAAM,SAASxF,EAAYwF,EAAM,QAAS,YAAY,EACtDA,EAAM,QACR8Q,EAAW9Q,EAAM,QAASA,EAAM,gBAAiBA,EAAM,KAAMtJ,GAAM,UAAU,EAE7EA,GAAM,aAAA,EAGJsJ,EAAM,OAAQ,CAChB,MAAMqR,EAAWrR,EAAM,OACjBsR,EAAa,IAAY,CAC7B9W,EAAY6W,EAAU,YAAY,EAC7BZ,GAAmBY,CAAQ,GAC9BF,EAAWE,EAAUrR,EAAM,eAAgBA,EAAM,IAAI,EAEvD6Q,EAAoB,IACtB,EACM7U,EAAQtF,GAAM,YAChBsF,GAASA,EAAQ,EACnB6U,EAAoBvf,EAAK,YAAY0K,EAAOsV,CAAU,EAEtDA,EAAA,CAEJ,CACF,EA8BqD,MA5BvC,CAACtR,EAAiBgR,IAAkC,CAChEL,GAAc3Q,EAAO,cAAc,EAC/BA,EAAM,QACRkR,EAAYlR,EAAM,QAASA,EAAM,gBAAiBA,EAAM,KAAMgR,CAAU,EAExEA,IAAA,EAEEhR,EAAM,QAAU,CAACyQ,GAAmBzQ,EAAM,MAAM,GAClDoR,EAAWpR,EAAM,OAAQA,EAAM,eAAgBA,EAAM,IAAI,CAE7D,EAkB4D,QAhB3CD,GAA8B,CAC7C8Q,GAAmB,KAAA,EACnBA,EAAoB,KACpB,UAAWjQ,KAAKb,EACVa,EAAE,UACJtP,EAAK,aAAasP,EAAE,OAAO,EAC3BtP,EAAK,IAAIsP,EAAE,QAAS,CAAE,WAAY,SAAU,GAE1CA,EAAE,SACJtP,EAAK,aAAasP,EAAE,MAAM,EAC1BtP,EAAK,IAAIsP,EAAE,OAAQ,CAAE,WAAY,qBAAsB,GAErDA,EAAE,UAAUtP,EAAK,aAAasP,EAAE,QAAQ,CAEhD,CAE4D,CAC9D,CAMA,IAAI2Q,GAAsB,EAmB1B,SAASC,GAASxR,EAAiByR,EAAoC,CACrE,MAAMC,EAAY,CAAC,CAAC1R,EAAM,QACpB2R,EAAM,CAACD,GAAa,CAAC,CAAC1R,EAAM,OAC5B4R,EAAW,WAAWH,CAAU,WAAWzR,EAAM,KAAK,GACtD6R,EAAY7R,EAAM,QAAU,WAAWyR,CAAU,YAAYzR,EAAM,KAAK,GAAK,KAC7E8R,EAAW9R,EAAM,OAAS,WAAWyR,CAAU,WAAWzR,EAAM,KAAK,GAAK,KAChF,MAAO,CAAE,UAAA0R,EAAW,IAAAC,EAAK,SAAAC,EAAU,UAAAC,EAAW,SAAAC,CAAA,CAChD,CAEO,SAASC,GAAqBrQ,EAAiC,CACpE,MAAM+P,EAAaF,KACbS,MAAa,IACnB,UAAWhS,KAAS0B,EAAM,QAASsQ,EAAO,IAAIhS,EAAOwR,GAASxR,EAAOyR,CAAU,CAAC,EAEhF,MAAMQ,EAA0B,CAAA,EAE1BC,EAAiB,CAAClgB,EAAaQ,EAAc2B,IAAwB,CACzE,MAAMge,EAAMngB,EAAG,aAAaQ,CAAI,EAC1B4f,EAAOD,EAAMngB,EAAG,aAAaQ,CAAI,EAAI,KAC3CR,EAAG,aAAaQ,EAAM2B,CAAK,EAC3B8d,EAAK,KAAK,IAAM,CACVE,GAAOC,IAAS,KAAMpgB,EAAG,aAAaQ,EAAM4f,CAAI,EAC/CpgB,EAAG,gBAAgBQ,CAAI,CAC9B,CAAC,CACH,EAEM6f,EAAmB,CAACrgB,EAAaQ,EAAc2B,IAAwB,CACvEnC,EAAG,aAAaQ,CAAI,IACxBR,EAAG,aAAaQ,EAAM2B,CAAK,EAC3B8d,EAAK,KAAK,IAAMjgB,EAAG,gBAAgBQ,CAAI,CAAC,EAC1C,EAyEA,MAAO,CAAE,aAvEY,IAAY,CAC/B,UAAWwN,KAAS0B,EAAM,QAAS,CACjC,MAAM4Q,EAAQN,EAAO,IAAIhS,CAAK,EACzBsS,IAGLD,EAAiBrS,EAAM,OAAQ,KAAMsS,EAAM,QAAQ,EACnDD,EAAiBrS,EAAM,OAAQ,WAAY,GAAG,EAE1CsS,EAAM,WACRJ,EAAelS,EAAM,OAAQ,OAAQ,QAAQ,EAC7CkS,EAAelS,EAAM,OAAQ,gBAAiB,OAAO,EACjDA,EAAM,SAAWsS,EAAM,YACzBJ,EAAelS,EAAM,OAAQ,gBAAiBsS,EAAM,SAAS,EAC7DD,EAAiBrS,EAAM,QAAS,KAAMsS,EAAM,SAAS,EACrDJ,EAAelS,EAAM,QAAS,OAAQ,QAAQ,EAC9CkS,EAAelS,EAAM,QAAS,kBAAmBsS,EAAM,QAAQ,GAE7DtS,EAAM,QAERkS,EAAelS,EAAM,OAAQ,cAAe,MAAM,GAE3CsS,EAAM,MACfJ,EAAelS,EAAM,OAAQ,OAAQ,KAAK,EAC1CkS,EAAelS,EAAM,OAAQ,gBAAiB,OAAO,EACjDA,EAAM,QAAUsS,EAAM,WACxBJ,EAAelS,EAAM,OAAQ,gBAAiBsS,EAAM,QAAQ,EAC5DD,EAAiBrS,EAAM,OAAQ,KAAMsS,EAAM,QAAQ,EACnDJ,EAAelS,EAAM,OAAQ,OAAQ,UAAU,EAC/CkS,EAAelS,EAAM,OAAQ,kBAAmBsS,EAAM,QAAQ,IAGpE,CAIA,GAAI5Q,EAAM,eAAiBA,EAAM,QAAQ,OAAS,EAAG,CACnD,MAAM6Q,EAAS7Q,EAAM,QAAQ,CAAC,EAAE,OAAO,cACnC6Q,GAAQL,EAAeK,EAAQ,OAAQ,SAAS,CACtD,CACF,EA+BuB,UA7BJvS,GAA0B,CAC3C,MAAMsS,EAAQN,EAAO,IAAIhS,CAAK,EACzBsS,IACDA,EAAM,WACRtS,EAAM,OAAO,aAAa,gBAAiB,MAAM,EAC7CA,EAAM,QAAQA,EAAM,OAAO,aAAa,cAAe,OAAO,GACzDsS,EAAM,KACftS,EAAM,OAAO,aAAa,gBAAiB,MAAM,EAErD,EAoBkC,YAlBbA,GAA0B,CAC7C,MAAMsS,EAAQN,EAAO,IAAIhS,CAAK,EACzBsS,IACDA,EAAM,WACRtS,EAAM,OAAO,aAAa,gBAAiB,OAAO,EAC9CA,EAAM,QAAQA,EAAM,OAAO,aAAa,cAAe,MAAM,GACxDsS,EAAM,KACftS,EAAM,OAAO,aAAa,gBAAiB,OAAO,EAEtD,EAS+C,QAP/B,IAAY,CAC1B,KAAOiS,EAAK,QAAQ,CAClB,MAAM5X,EAAK4X,EAAK,IAAA,EACZ5X,GAAIA,EAAA,CACV,CACF,CAE+C,CACjD,CC1QO,SAASmY,GACdxgB,EACAygB,EACAC,EACAC,EACsB,CACtB,MAAM1C,EAAMje,EAAG,aAAaygB,CAAQ,GAAG,eAAiB,QAClDhX,EAAOzJ,EAAG,aAAa,SAAS,GAAK0gB,EAE3C,GAAIzC,IAAQ,SAAU,CACpB,MAAM2C,EACJ5gB,EAAG,QAAQ,YAAA,IAAkB,SACxBA,EACAA,EAAG,cAAc,QAAQ,EAChC,GAAI,CAAC4gB,EACH,eAAQ,KACN,mBAAmBH,CAAQ,sEAC3BzgB,CAAA,EAEK,KAET,MAAMwB,EACJ,OAAOof,EAAO,GAAG,SAAS,OAAU,SAChCA,EAAO,EAAE,QAAQ,MACjB,WAAWA,EAAO,aAAa,GAAG,GAAK,GAAG,EAC1CC,EAAgB,EAAI,KAAK,GAAKrf,EACpC,OAAAmf,EAAIC,EAAQ,CAAE,gBAAiBC,EAAe,iBAAkBA,EAAe,EACxE,CAAE,OAAQD,EAAQ,KAAM,SAAU,cAAAC,EAAe,KAAApX,CAAA,CAC1D,CAEA,MAAMqX,EAA+B7C,IAAQ,SAAW,SAAW,QACnE,OAAA0C,EAAI3gB,EAAI,CAAE,CAAC8gB,CAAQ,EAAG,KAAM,EACrB,CAAE,OAAQ9gB,EAAI,KAAM8gB,EAAU,SAAAA,EAAU,KAAArX,CAAA,CACjD,CAEO,SAASsX,GAAmB/S,EAA+C,CAChF,OAAIA,EAAM,OAAS,SAAiB,CAAE,iBAAkBA,EAAM,aAAA,EACvD,CAAE,CAACA,EAAM,QAAkB,EAAG,IAAA,CACvC,CAEO,SAASgT,GAAiBhT,EAA+C,CAC9E,OAAIA,EAAM,OAAS,SAAiB,CAAE,iBAAkB,CAAA,EACjD,CAAE,CAACA,EAAM,QAAkB,EAAG,MAAA,CACvC,CASO,SAASiT,GACdjT,EACAkT,EACAP,EACM,CACN,MAAMQ,EAAU,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGD,CAAQ,CAAC,EACjD,GAAIlT,EAAM,OAAS,SAAU,CAC3B2S,EAAI3S,EAAM,OAAQ,CAChB,kBAAmBA,EAAM,eAAiB,IAAM,EAAImT,EAAA,CACrD,EACD,MACF,CACAR,EAAI3S,EAAM,OAAQ,CAAE,CAACA,EAAM,QAAkB,EAAG,GAAGmT,EAAU,GAAG,GAAA,CAAK,CACvE,CA8BO,SAASC,GAGdC,EACAtT,EACe,CACf,MAAMzO,EAAO+hB,EACb,MAAO,CACL,KAAKC,EAAaC,EAAmB,CACnCxT,EAAQ,QAAQ,CAACC,EAAOiG,IAAM,CACvBjG,IACL1O,EAAK,aAAa0O,EAAM,MAAM,EAC1BiG,IAAMqN,EACRhiB,EAAK,OAAO0O,EAAM,OAAQ+S,GAAmB/S,CAAK,EAAG,CACnD,GAAGgT,GAAiBhT,CAAK,EACzB,SAAUuT,EAAYtN,CAAC,EACvB,KAAMjG,EAAM,KACZ,UAAW,EAAA,CACZ,EAED1O,EAAK,IAAI0O,EAAM,OAAQ+S,GAAmB/S,CAAK,CAAC,EAEpD,CAAC,CACH,EACA,OAAc,CACZ,UAAWA,KAASD,EACbC,IACL1O,EAAK,aAAa0O,EAAM,MAAM,EAC9B1O,EAAK,IAAI0O,EAAM,OAAQ+S,GAAmB/S,CAAK,CAAC,EAEpD,EACA,OAAc,CACZ,UAAWA,KAASD,EAClB,GAAKC,EACL,UAAW/I,KAAK3F,EAAK,YAAY0O,EAAM,MAAM,IAAK,MAAA,CAEtD,EACA,QAAe,CACb,UAAWA,KAASD,EAClB,GAAKC,EACL,UAAW/I,KAAK3F,EAAK,YAAY0O,EAAM,MAAM,IAAK,OAAA,CAEtD,CAAA,CAEJ,CCzHO,SAASwT,GACdnf,EACAqC,EACqB,CACrB,MAAM+c,EAAY/c,EAAK,QAAQ,QAAqBuC,EAAmB,EACvE,GAAIwa,EAAW,CACb,MAAMpP,EAAUzJ,GAAkB,CAChC,QAASlE,EAAK,QACd,YAAa,eACb,UAAWA,EAAK,SAChB,UAAWA,EAAK,MAAA,CACjB,EAKD,OAAI+c,EAAU,aAAava,EAAiB,IAAM,WAAe,SAAA,IACvD,OAAA,EACHmL,CACT,CAEA,MAAMxN,EAAgBxC,EAAW,QAAQ,cACzC,GAAI,CAACwC,EAAe,OAAO,KAE3B,MAAM6c,EAAK7c,EAAc,OAAO,CAC9B,QAASH,EAAK,QACd,MAAO,aACP,IAAK,aACL,QAASA,EAAK,SACd,YAAaA,EAAK,SAClB,QAASA,EAAK,OACd,YAAaA,EAAK,MAAA,CACnB,EAQD,OAAIgd,EAAG,SAAUhd,EAAK,SAAA,IACZ,OAAA,EAEH,IAAMgd,EAAG,KAAA,CAClB,CAgBO,SAASC,GAAyBjd,EAAqC,CAC5E,OAAI,OAAO,OAAW,KAAe,OAAO,WAAW,eAAe,EAAE,QAC/D,IAAM,CAAC,GAEhBA,EAAK,KAAK,iBAAiB,aAAcA,EAAK,OAAO,EACrDA,EAAK,KAAK,iBAAiB,aAAcA,EAAK,OAAO,EAC9C,IAAM,CACXA,EAAK,KAAK,oBAAoB,aAAcA,EAAK,OAAO,EACxDA,EAAK,KAAK,oBAAoB,aAAcA,EAAK,OAAO,CAC1D,EACF,CCrGO,SAASkd,GACdvf,EACAqB,EACAsP,EACA7J,EACoB,CACpB,MAAM7J,EAAO+C,EAAW,KAClB,CAAE,WAAAkc,GAAepV,EACjB4E,EAAUiF,EAAI,MAAM,QAE1B,IAAI6O,EAEO,KACPC,EAAkB,GAClBC,EAAa,GACbC,EAAa,KAAK,IAAI,EAAGjU,EAAQ,UAAWa,GAAMoE,EAAI,MAAM,SAASpE,CAAC,CAAC,CAAC,EAG5E,MAAMqT,EAA6ClU,EAAQ,IAAKC,GAC9DA,EAAM,SACFwS,GAAoBxS,EAAM,SAAU,mBAAoBA,EAAM,KAAM1O,EAAK,GAAG,EAC5E,IAAA,EAEA4iB,EAAWd,GAAoB9hB,EAAM2iB,CAAa,EAElDE,EAAYlO,GAAsBlG,EAAQkG,CAAC,EAAE,SAE7CmO,EAAO,IAAY,CACvB,MAAMC,GAAQL,EAAa,GAAKjU,EAAQ,OACxCiU,EAAaK,EACbrP,EAAI,KAAKjF,EAAQsU,CAAI,CAAC,EACtBH,EAAS,KAAKG,EAAMF,CAAQ,EAC5B,MAAMG,EAAQvU,EAAQsU,CAAI,EAAE,SAC5BR,EAAeviB,EAAK,YAAYgjB,EAAOF,CAAI,CAC7C,EAEMG,EAAQ,IAAY,CACxB,GAAIV,EAAc,OAClBK,EAAS,KAAKF,EAAYG,CAAQ,EAClC,MAAMG,EAAQvU,EAAQiU,CAAU,EAAE,SAClCH,EAAeviB,EAAK,YAAYgjB,EAAOF,CAAI,CAC7C,EAEMI,EAAO,IAAY,CACnBX,IACFA,EAAa,KAAA,EACbA,EAAe,MAEjBK,EAAS,MAAA,EACTJ,EAAkB,EACpB,EAEMW,EAAQC,GAAsB,CAClC,GAAIA,EAAM,GAAKA,GAAO3U,EAAQ,OAAQ,OAWtC,GAVI8T,IACFA,EAAa,KAAA,EACbA,EAAe,MAEjBK,EAAS,MAAA,EACTF,EAAaU,EACb1P,EAAI,KAAKjF,EAAQ2U,CAAG,CAAC,EAIjBnE,GAAcwD,EAAY,CAC5BD,EAAkB,GAClB,MACF,CACAA,EAAkB,GAClBI,EAAS,KAAKQ,EAAKP,CAAQ,EAC3B,MAAMG,EAAQvU,EAAQ2U,CAAG,EAAE,SAC3Bb,EAAeviB,EAAK,YAAYgjB,EAAOF,CAAI,CAC7C,EAEMO,EAAe,IAAY,CAC3Bd,GAAgB,CAACA,EAAa,WAChCA,EAAa,MAAA,EACbK,EAAS,MAAA,EACTJ,EAAkB,GAEtB,EACMc,EAAkB,IAAY,CAC9Bf,GAAgBC,IAClBD,EAAa,OAAA,EACbK,EAAS,OAAA,EACTJ,EAAkB,GAEtB,EAEMe,EAA8B,CAAA,EAEhCtE,GACFsE,EAAS,KACPlB,GAAyB,CACvB,KAAAje,EACA,QAAS,IAAM,CACbqe,EAAa,GACTF,GAAgB,CAACA,EAAa,OAAA,GAAUc,EAAA,CAC9C,EACA,QAAS,IAAM,CACbZ,EAAa,GACRD,IAIDD,EACFe,EAAA,GAEAd,EAAkB,GAClBS,EAAA,GAEJ,CAAA,CACD,CAAA,EAOL,MAAMO,EAAS,IAAY,CACrBjB,IACFA,EAAa,KAAA,EACbA,EAAe,KAEnB,EACMkB,EAAW,IAAY,CAC3BzjB,EAAK,YAAY,GAAKijB,CAAK,CAC7B,EACMS,EAAcxB,GAAmBnf,EAAY,CAAE,QAASqB,EAAM,SAAAqf,EAAU,OAAAD,EAAQ,EACtF,OAAIE,EAAaH,EAAS,KAAKG,CAAW,EACrCD,EAAA,EAOE,CAAE,MAAAR,EAAO,KAAAC,EAAM,KAAAC,EAAM,QALZ,IAAY,CAC1BD,EAAA,EACA,UAAWna,KAAMwa,EAAUxa,EAAA,CAC7B,CAE4B,CAC9B,CC3JA,MAAM4a,GAAgB,IAAI,IAAI,CAAC,QAAS,GAAG,CAAC,EACtCC,GAAW,IAAI,IAAI,CAAC,UAAW,YAAa,YAAa,aAAc,OAAQ,KAAK,CAAC,EAEpF,SAASC,GACdzf,EACA0f,EACAC,EACY,CACZ,GAAID,EAAQ,SAAW,EAAG,MAAO,IAAM,CAAC,EAExC,MAAME,EAAS1U,GAA2B,CACxC,MAAMnG,EAASmG,EAAE,OACjB,GAAI,CAACnG,EAAQ,OACb,MAAM8a,EAAS9a,EAAO,QAAqB,kBAAkB,EAC7D,GAAI,CAAC8a,GAAU,CAAC7f,EAAK,SAAS6f,CAAM,EAAG,OAEvC,GAAIN,GAAc,IAAIrU,EAAE,GAAG,EAAG,CAC5BA,EAAE,eAAA,EACFyU,EAAS,SAASE,CAAM,EACxB,MACF,CAEA,GAAI,CAACL,GAAS,IAAItU,EAAE,GAAG,EAAG,OAE1B,MAAM8T,EAAMU,EAAQ,QAAQG,CAAM,EAClC,GAAIb,IAAQ,GAAI,OAEhB,IAAIL,EAAOK,EACX,OAAQ9T,EAAE,IAAA,CACR,IAAK,YACL,IAAK,aACHyT,GAAQK,EAAM,GAAKU,EAAQ,OAC3B,MACF,IAAK,UACL,IAAK,YACHf,GAAQK,EAAM,EAAIU,EAAQ,QAAUA,EAAQ,OAC5C,MACF,IAAK,OACHf,EAAO,EACP,MACF,IAAK,MACHA,EAAOe,EAAQ,OAAS,EACxB,KAAA,CAEAf,IAASK,IACX9T,EAAE,eAAA,EACFwU,EAAQf,CAAI,EAAE,MAAA,EAElB,EAEA,OAAA3e,EAAK,iBAAiB,UAAW4f,CAAK,EAC/B,IAAM5f,EAAK,oBAAoB,UAAW4f,CAAK,CACxD,CCvBO,SAASE,GACdnhB,EACAqB,EACAsP,EACA7J,EACyB,CACzB,MAAMtE,EAAgBxC,EAAW,QAAQ,cACzC,GAAI,CAACwC,EACH,eAAQ,KACN,4GAAA,EAEK,KAET,MAAMvF,EAAO+C,EAAW,KAClB0L,EAAUiF,EAAI,MAAM,QACpByQ,EAAI1V,EAAQ,OAClB,GAAI0V,IAAM,EAAG,OAAO,KAKpB,MAAMxB,EAA6ClU,EAAQ,IAAKC,GAC9DA,EAAM,SACFwS,GAAoBxS,EAAM,SAAU,mBAAoBA,EAAM,KAAM1O,EAAK,GAAG,EAC5E,IAAA,EAIAokB,EAAiBD,EAAIta,EAAQ,WAAa,OAAO,YAAe,IAKtE,IAAI6Y,EAAa,GAEjB,MAAM2B,EAAgB,CAAE,EAAG,CAAA,EACrBC,EAAyBtkB,EAAK,GAAGqkB,EAAe,CACpD,EAAG,EACH,SAAU,EACV,KAAM,OACN,OAAQ,GACR,SAAU,IAAM,CACd,MAAME,EAAIF,EAAc,EAClBG,EAAS,KAAK,IAAI,KAAK,IAAI,EAAG,KAAK,MAAMD,EAAIJ,CAAC,CAAC,EAAGA,EAAI,CAAC,EAEzDK,IAAW9B,IACTA,GAAc,GAAGhP,EAAI,MAAMjF,EAAQiU,CAAU,CAAC,EAClDhP,EAAI,KAAKjF,EAAQ+V,CAAM,CAAC,EACxB9B,EAAa8B,GAKf7B,EAAc,QAAQ,CAACjU,EAAOiG,IAAM,CAClC,GAAI,CAACjG,EAAO,OACZ,MAAM+V,EAAO9P,IAAM6P,EAASD,EAAIJ,EAAIxP,EAAI,EACxCgN,GAAgBjT,EAAO+V,EAAMzkB,EAAK,GAAG,CACvC,CAAC,CACH,CAAA,CACD,EAEKoiB,EAAK7c,EAAc,OAAO,CAC9B,QAASnB,EACT,MAAOyF,EAAQ,YACf,IAAK,KAAKua,CAAa,GACvB,IAAK,GACL,WAAY,GACZ,MAAOva,EAAQ,MACf,UAAWya,CAAA,CACZ,EAyCD,MAAO,CAAE,YAvCYlB,GAAsB,CACzC,GAAIA,EAAM,GAAKA,GAAOe,EAAG,OAIzB,MAAMO,GADYtC,EAAG,IAAMA,EAAG,OACS+B,EAEjCQ,EAAUvC,EAAG,MAAQgB,EAAMsB,EAAqBA,EAAqB,IAGrEjV,EADI,OACM,MAChB,GAAIA,GAAS,OAAOA,EAAM,UAAa,WAAY,CAIjDA,EAAM,SAASkV,EAAS,CAAE,SAAU,GAAK,OAAQ,EAAG,EACpD,MACF,CAKA,MAAMC,EAAQ,CAAE,EAAG,OAAO,OAAA,EAC1B5kB,EAAK,GAAG4kB,EAAO,CACb,EAAGD,EACH,SAAU,IACV,KAAM,eACN,UAAW,GACX,SAAU,IAAM,CACd,OAAO,SAAS,EAAGC,EAAM,CAAC,CAC5B,CAAA,CACD,CACH,EAOsB,QALN,IAAY,CAC1BN,EAAW,KAAA,EACXlC,EAAG,KAAA,CACL,CAEsB,CACxB,CClIO,SAASyC,GAAelG,EAA2C,CACxE,MAAMjY,GAAUiY,GAAO,IACpB,OACA,MAAM,KAAK,EACX,OAAO,OAAO,EACXmG,EAASpe,EAAO,SAAS,MAAM,EACrC,IAAIiS,EAAgB,UACpB,OAAIjS,EAAO,SAAS,QAAQ,EAAGiS,EAAO,SAC7BjS,EAAO,SAAS,OAAO,EAAGiS,EAAO,QACjCjS,EAAO,SAAS,QAAQ,IAAGiS,EAAO,UACpC,CAAE,KAAAA,EAAM,OAAAmM,CAAA,CACjB,CAyCA,MAAMC,GAAc,iBAEpB,SAASC,GAAc5gB,EAAyB,CAC9C,MAAM2V,EAAW3V,EAAK,iBAA8B,mBAAmB,EAGvE,GAFmB2V,EAAS,OAAS,EAErB,CACdA,EAAS,QAAQ,CAACC,EAASrF,IAAM,CAC/B,IAAIsQ,EAAKjL,EAAQ,aAAa,iBAAiB,EAC1CiL,IACHA,EAAK,WAAWtQ,CAAC,GACjBqF,EAAQ,aAAa,kBAAmBiL,CAAE,GAE5C,MAAMhB,EAASjK,EAAQ,cAA2B,kBAAkB,EAC9DyF,EAAUzF,EAAQ,cAA2B,mBAAmB,EAClEiK,GAAU,CAACA,EAAO,aAAa,gBAAgB,GACjDA,EAAO,aAAa,iBAAkBgB,CAAE,EAEtCxF,GAAW,CAACA,EAAQ,aAAa,iBAAiB,GACpDA,EAAQ,aAAa,kBAAmBwF,CAAE,CAE9C,CAAC,EACD7gB,EAAK,iBAA8B,kBAAkB,EAAE,QAAQ,CAACgb,EAAQzK,IAAM,CACvEyK,EAAO,aAAa,gBAAgB,GACvCA,EAAO,aAAa,iBAAkB,WAAWzK,CAAC,EAAE,CAExD,CAAC,EACD,MACF,CAEAvQ,EAAK,iBAA8B,kBAAkB,EAAE,QAAQ,CAAC1D,EAAIiU,IAAM,CACnEjU,EAAG,aAAa,gBAAgB,KAAM,aAAa,iBAAkB,WAAWiU,CAAC,EAAE,CAC1F,CAAC,EACDvQ,EAAK,iBAA8B,mBAAmB,EAAE,QAAQ,CAAC1D,EAAIiU,IAAM,CACpEjU,EAAG,aAAa,iBAAiB,KAAM,aAAa,kBAAmB,WAAWiU,CAAC,EAAE,CAC5F,CAAC,EACDvQ,EAAK,iBAA8B,kBAAkB,EAAE,QAAQ,CAAC1D,EAAIiU,IAAM,CACnEjU,EAAG,aAAa,gBAAgB,KAAM,aAAa,iBAAkB,WAAWiU,CAAC,EAAE,CAC1F,CAAC,CACH,CAEA,SAASuQ,GAAaxkB,EAAwBmF,EAA0B,CACtE,OAAKnF,EACEkF,EAASlF,EAAG,aAAa,aAAa,EAAGmF,CAAQ,EADxCA,CAElB,CAEA,SAASsf,GAASzkB,EAAwBmF,EAA0B,CAClE,GAAI,CAACnF,EAAI,OAAOmF,EAChB,MAAMvE,EAAIZ,EAAG,aAAa,SAAS,EACnC,OAAOY,GAAKA,EAAE,OAAS,EAAIA,EAAIuE,CACjC,CAQA,SAASuf,GAAa1kB,EAAwBmF,EAA0B,CACtE,GAAI,CAACnF,GAAM,CAACA,EAAG,aAAa,aAAa,EAAG,OAAOmF,EACnD,MAAM8Y,EAAMje,EAAG,aAAa,aAAa,GAAK,GAC9C,UAAWiF,KAAKgZ,EAAI,KAAA,EAAO,MAAM,KAAK,EAAG,CACvC,MAAMre,EAAI,WAAWqF,CAAC,EACtB,GAAI,OAAO,SAASrF,CAAC,GAAKA,EAAI,EAAG,OAAOA,CAC1C,CACA,OAAOuF,CACT,CAEO,SAASwf,GAAejhB,EAAmBwa,EAAsC,CACtFoG,GAAc5gB,CAAI,EAGlB,MAAMkhB,EADW,MAAM,KAAKlhB,EAAK,iBAA8B,mBAAmB,CAAC,EAChD,OAAS,EAEtC0f,EAAU,MAAM,KAAK1f,EAAK,iBAA8B,kBAAkB,CAAC,EAC3EqK,EAAsB,CAAA,EACtB8W,MAAW,IAMXC,EAAeN,GAAa9gB,EAAMwa,EAAS,QAAQ,EACnD6G,EAAWN,GAAS/gB,EAAMwa,EAAS,IAAI,EACvC8G,EAAeN,GAAahhB,EAAMwa,EAAS,QAAQ,EAEzDkF,EAAQ,QAAQ,CAACG,EAAQtP,IAAM,CAC7B,MAAMsQ,EAAKhB,EAAO,aAAa,gBAAgB,GAAK,WAAWtP,CAAC,GAC1D8K,EAAUrb,EAAK,cAA2B,qBAAqB,IAAI,OAAO6gB,CAAE,CAAC,IAAI,EACjF7F,EAAShb,EAAK,cAA2B,oBAAoB,IAAI,OAAO6gB,CAAE,CAAC,IAAI,EAC/EjL,EAAUsL,EAAoBrB,EAAO,QAAqB,mBAAmB,EAAI,KACjFrB,EAAWqB,EAAO,cAA2B,oBAAoB,EAEjE0B,EAAiBT,GAAajB,EAAQuB,CAAY,EAClDI,EAAaT,GAASlB,EAAQwB,CAAQ,EACtCI,EAAiBT,GAAanB,EAAQyB,CAAY,EAElDI,EAAkBZ,GAAazF,EAASkG,CAAc,EACtDI,EAAiBb,GAAa9F,EAAQuG,CAAc,EAEpDjX,EAAkB,CACtB,GAAAuW,EACA,MAAOtQ,EACP,OAAAsP,EACA,QAAAxE,EACA,OAAAL,EACA,QAAApF,EACA,SAAA4I,EACA,gBAAAkD,EACA,eAAAC,EACA,SAAUF,EACV,KAAMD,CAAA,EAERnX,EAAQ,KAAKC,CAAK,EAClB6W,EAAK,IAAIN,EAAIvW,CAAK,CACpB,CAAC,EAED,MAAMsX,EAAavX,EAAQ,KAAMa,GAAM,CAAC,CAACA,EAAE,OAAO,EAC5C2W,EAAgB,CAACD,GAAcvX,EAAQ,KAAMa,GAAM,CAAC,CAACA,EAAE,MAAM,EAE7D4W,EAAYxX,GAAiCA,EAAM,SAAWA,EAAM,OACpEyX,EAAYzX,GAA6BwX,EAASxX,CAAK,EAAE,aAAaqW,EAAW,IAAM,SAgC7F,MAAO,CACL,KAAA3gB,EACA,QAAAqK,EACA,KAAA8W,EACA,kBAAAD,EACA,WAAAU,EACA,cAAAC,EACA,SAAAC,EACA,SAAAC,EACA,UAxCgB,CAACzX,EAAiB0X,IAAwC,CAC1EF,EAASxX,CAAK,EAAE,aAAaqW,GAAaqB,CAAM,EAG3C1X,EAAM,SACLA,EAAM,SAASA,EAAM,QAAQ,aAAaqW,GAAaqB,CAAM,EAE/D1X,EAAM,QAAQA,EAAM,OAAO,aAAaqW,GAAaqB,CAAM,CACjE,EAiCE,YAhCkB,IAAuB3X,EAAQ,KAAK0X,CAAQ,GAAK,KAiCnE,aA/BmB,IAAuB,CAC1C,MAAM1d,EAAWrE,EAAK,cAA2B,mBAAmB,EACpE,GAAIqE,EAAU,CACZ,MAAM4d,EAAiB5d,EAAS,QAAQ,kBAAkB,EACtDA,EACAA,EAAS,cAA2B,kBAAkB,EAC1D,GAAI4d,EAAgB,CAClB,MAAMpB,EAAKoB,EAAe,aAAa,gBAAgB,EACvD,GAAIpB,EAAI,OAAOM,EAAK,IAAIN,CAAE,GAAK,IACjC,CAEA,MAAMqB,EAAgB7d,EAAS,cAA2B,kBAAkB,EAC5E,GAAI6d,EAAe,CACjB,MAAMrB,EAAKqB,EAAc,aAAa,gBAAgB,EACtD,GAAIrB,EAAI,OAAOM,EAAK,IAAIN,CAAE,GAAK,IACjC,CACF,CACA,OAAO,IACT,CAaE,CAEJ,CAEO,MAAMsB,GAAmBxB,GC5MhC,SAASjY,GAASF,EAAqBxI,EAAmBd,EAA0C,CAClG,MAAM6E,EAAS0c,GAAevhB,EAAO,SAAS,CAAC,EAC/C,GAAI6E,EAAO,OAAQ,OAEnB,MAAM/C,EAAOwH,EAAI,QACX4Z,GAAmB,IAAM,CAC7B,MAAM1R,EAAIxR,EAAO,aAAa,EACxBhD,EAAIwU,IAAM,OAAY,WAAWA,CAAC,EAAI,IAC5C,OAAO,OAAO,SAASxU,CAAC,EAAIA,EAAI8E,EAAK,QACvC,GAAA,EACMqhB,EAAcnjB,EAAO,SAAS,GAAK8B,EAAK,KAExCshB,EAAWhI,GACfpb,EAAO,aAAa,EACpB8B,EAAK,SACL,gBAAiB9B,CAAA,EAGb8M,EAAQiV,GAAejhB,EAAM,CACjC,SAAUoiB,EACV,SAAUE,EAAS,SACnB,KAAMD,CAAA,CACP,EACD,GAAIrW,EAAM,QAAQ,SAAW,EAAG,OAEhC,MAAMpQ,EAAO4M,EAAI,KAAK,KAChBrH,EAAgBqH,EAAI,KAAK,QAAQ,cAKvC,IAAI+L,EAAgBxQ,EAAO,KACvBue,EAAS,UACP/N,IAAS,UAAY/L,EAAI,OAC3B,QAAQ,KACN,2FACAxI,CAAA,EAGJuU,EAAO,YAKLA,IAAS,UAAYpT,GAAiBA,EAAc,UACtDoT,EAAO,UAGT,MAAMgO,EAAOlG,GAAqBrQ,CAAK,EACjCtB,EAAYwQ,GAA0B1S,EAAI,IAAI,EAEpD+Z,EAAK,aAAA,EACL7X,EAAU,mBAAmBsB,EAAM,OAAO,EAC1C,UAAW1B,KAAS0B,EAAM,QAASA,EAAM,UAAU1B,EAAO,UAAU,EAEpE,IAAIkY,EAA2C,KAC/C,MAAMC,EAAmB,IAAY,CAC9BthB,IACLqhB,GAAa,KAAA,EACbA,EAAc5mB,EAAK,YAAY,GAAK,IAAM,CACxCuF,EAAc,QAAA,EACdqhB,EAAc,IAChB,CAAC,EACH,EAEME,EAAapY,GAA0B,CAC3C,GAAI0B,EAAM,SAAS1B,CAAK,EAAG,OAE3B,IAAIqY,EAAc,EAClB,GAAIpO,IAAS,QAAS,CACpB,MAAMmI,EAAO1Q,EAAM,YAAA,EACf0Q,GAAQA,IAASpS,IAMfoS,EAAK,QAAU3B,GAAmB2B,EAAK,MAAM,IAC/CiG,EAAcjG,EAAK,eAAiBjZ,IAEtCmf,EAAWlG,CAAI,EAEnB,CACA1Q,EAAM,UAAU1B,EAAO,QAAQ,EAC/BiY,EAAK,UAAUjY,CAAK,EACpBI,EAAU,KAAKJ,EAAO,CAAE,YAAAqY,EAAa,WAAYF,EAAkB,CACrE,EAEMI,EAAiBvY,GAA0B,CAC/C,GAAI,CAAA0B,EAAM,SAAS1B,CAAK,EACxB,IAAIiK,IAAS,QAAS,CACpB,MAAMmI,EAAO1Q,EAAM,YAAA,EACf0Q,GAAQA,IAASpS,GAAOsY,EAAWlG,CAAI,CAC7C,CACA1Q,EAAM,UAAU1B,EAAO,QAAQ,EAC/BiY,EAAK,UAAUjY,CAAK,EACpBI,EAAU,iBAAiBJ,CAAK,EAClC,EAEMsY,EAActY,GAA0B,CACvC0B,EAAM,SAAS1B,CAAK,IACzB0B,EAAM,UAAU1B,EAAO,UAAU,EACjCiY,EAAK,YAAYjY,CAAK,EACtBI,EAAU,MAAMJ,EAAOmY,CAAgB,EACzC,EAEMnT,EAAe,CACnB,MAAAtD,EACA,KAAAuI,EACA,KAAMmO,EACN,SAAUG,EACV,MAAOD,CAAA,EAIT,IAAIE,EAAyC,KACzCC,EAAsC,KAM1C,MAAMC,GAAgB,IAAM,CAC1B,MAAM3e,EAAW2H,EAAM,aAAA,EACvB,OAAI3H,IACAkQ,IAAS,UAAYA,IAAS,YAAcA,IAAS,SAChDvI,EAAM,QAAQ,CAAC,GAAK,KAEtB,KACT,GAAA,EAIIgX,GACFpnB,EAAK,YAAY,EAAG,IAAM,CACnBoQ,EAAM,SAASgX,CAAY,KAAiBA,CAAY,CAC/D,CAAC,EAGH,MAAMC,EAAgBpD,GAA8B,CAClD,MAAMgB,EAAKhB,EAAO,aAAa,gBAAgB,EAC/C,GAAI,CAACgB,EAAI,OACT,MAAMvW,EAAQ0B,EAAM,KAAK,IAAI6U,CAAE,EAC/B,GAAI,CAACvW,EAAO,OAEZ,MAAM4Y,EAASlX,EAAM,SAAS1B,CAAK,EAEnC,GAAI,EAAA4Y,IADc3O,IAAS,UAAYA,IAAS,YAAcA,IAAS,WAMvE,IAAIwO,EAAY,CACdA,EAAW,YAAYzY,EAAM,KAAK,EAClC,MACF,CACA,GAAIwY,EAAa,CACfA,EAAY,KAAKxY,EAAM,KAAK,EAC5B,MACF,CAEI4Y,IAAmB5Y,CAAK,IACbA,CAAK,EACtB,EAEM6Y,EAAWjY,GAAmB,CAClC,MAAMnG,EAASmG,EAAE,OACjB,GAAI,CAACnG,EAAQ,OACb,MAAM8a,EAAS9a,EAAO,QAAqB,kBAAkB,EACzD,CAAC8a,GAAU,CAAC7f,EAAK,SAAS6f,CAAM,GACpCoD,EAAapD,CAAM,CACrB,EACA7f,EAAK,iBAAiB,QAASmjB,CAAO,EAEtC,MAAMhE,EAA8B,CAAA,EASpC,GARAA,EAAS,KAAK,IAAMnf,EAAK,oBAAoB,QAASmjB,CAAO,CAAC,EAE9DhE,EAAS,KACPM,GAAezf,EAAMgM,EAAM,QAAQ,IAAKd,GAAMA,EAAE,MAAM,EAAG,CACvD,SAAU+X,CAAA,CACX,CAAA,EAGC1O,IAAS,WACXuO,EAAc5E,GAAc1V,EAAI,KAAMxI,EAAMsP,EAAK,CAC/C,WAAYgT,EAAS,UAAA,CACtB,EACDnD,EAAS,KAAK,IAAM2D,GAAa,QAAA,CAAS,UACjCvO,IAAS,SAAU,CAG5B,MAAMlB,EAAY,WAAWnU,EAAO,cAAc,GAAK,EAAE,GAAK,EACxDsH,EAActH,EAAO,iBAAiB,GAAK,UAC3CkkB,EAAYlkB,EAAO,UAAU,EAC7B+B,EAAQmiB,IAAc,QAAmBA,IAAc,OAArB,GAAqC,WAAWA,CAAS,GAAK,GACtGL,EAAajD,GAAYtX,EAAI,KAAMxI,EAAMsP,EAAK,CAC5C,WAAY,GAAK+D,EACjB,YAAA7M,EACA,MAAAvF,CAAA,CACD,EACG8hB,GAAY5D,EAAS,KAAK,IAAM4D,GAAY,SAAS,CAC3D,CAEA,MAAO,IAAM,CACX,UAAWpe,KAAMwa,EAAUxa,EAAA,EAC3B6d,GAAa,KAAA,EACbA,EAAc,KACd9X,EAAU,QAAQsB,EAAM,OAAO,EAC/B,UAAW1B,KAAS0B,EAAM,QACxBA,EAAM,SAAS1B,CAAK,EAAE,gBAAgB6X,EAAgB,EAClD,CAAC7X,EAAM,SAAWA,EAAM,SAASA,EAAM,QAAQ,gBAAgB6X,EAAgB,EAC/E7X,EAAM,QAAQA,EAAM,OAAO,gBAAgB6X,EAAgB,EAEjEI,EAAK,QAAA,CACP,CACF,sEAEmC,CACjC,KAAM,OACN,KAAK/Z,EAAiC,CACpC,OAAAI,GAAgBJ,EAAK,UAAWE,EAAQ,EACjC,IAAM,CAAC,CAChB,CACF,yCChPA,SAAS2a,GAAkB9I,EAAuC,CAChE,MAAMjY,GAAUiY,GAAO,IACpB,OACA,MAAM,KAAK,EACX,OAAO,OAAO,EACjB,MAAO,CACL,QAASjY,EAAO,SAAS,OAAO,EAChC,UAAWA,EAAO,SAAS,QAAQ,EACnC,YAAaA,EAAO,SAAS,WAAW,EACxC,OAAQA,EAAO,SAAS,MAAM,CAAA,CAElC,CAKA,MAAMghB,GAAuB,CAC3B,aACA,WACA,cACA,aACA,aACA,WACA,kBACA,gBACA,SACF,EAGMC,GAAuB,CAC3B,UACA,YACA,SACA,aACA,YACA,mBACF,EAEA,SAASC,GAAelnB,EAAuB,CAC7C,UAAW2Z,KAAQsN,GAAsBjnB,EAAG,MAAM,eAAe2Z,CAAI,CACvE,CAOA,SAASwN,GAAcC,EAA0B,CAC/C,MAAMC,EAAWD,EAAM,QAAQ,cAAc,EACzC,CAACA,EAAO,GAAGA,EAAM,iBAA8B,cAAc,CAAC,EAC9D,CAAC,GAAGA,EAAM,iBAA8B,cAAc,CAAC,EAC3D,UAAWpnB,KAAMqnB,EAAU,CACzB,UAAW7mB,KAAQwmB,GAAsBhnB,EAAG,gBAAgBQ,CAAI,EAChE0mB,GAAelnB,CAAE,EACjB,UAAWsnB,KAAQtnB,EAAG,iBAA8B,GAAG,KAAkBsnB,CAAI,CAC/E,CACF,CAGA,MAAMC,GAAoB,IA6B1B,SAASC,GACPzT,EACA0T,EACAC,EACAC,EACAC,EACe,CACf,MAAMC,EAAwB,CAAA,EAKxBC,EAAmBJ,EAAYC,EAAgBC,EAAmB,EAAI,EAC5E,IAAIG,EAAS,EACb,KAAON,EAAM,YAAcK,GAAoBC,EAAS,IAAI,CAC1D,MAAMX,EAAQrT,EAAK,UAAU,EAAI,EACjCqT,EAAM,aAAa,mBAAoB,EAAE,EACzCA,EAAM,aAAa,cAAe,MAAM,EAGxCD,GAAcC,CAAK,EACnBK,EAAM,YAAYL,CAAK,EACvBS,EAAO,KAAKT,CAAK,EACjBW,GACF,CACA,OAAOF,CACT,CAEA,SAASzb,GACPF,EACAxI,EACAd,EAC0B,CAC1B,MAAMoD,EAAS+gB,GAAkBnkB,EAAO,YAAY,CAAC,EACrD,GAAIoD,EAAO,OAAQ,OAMnB,MAAMyhB,EAAQ/jB,EAAK,cAA2B,oBAAoB,EAC5DqQ,EAAOrQ,EAAK,cAA2B,mBAAmB,EAChE,GAAI,CAAC+jB,GAAS,CAAC1T,EAAM,CACf7H,EAAI,OACN,QAAQ,KACN,4FACAxI,CAAA,EAGJ,MACF,CAKA,MAAMsiB,EAAWhI,GACfpb,EAAO,aAAa,EACpBsJ,EAAI,QAAQ,SACZ,gBAAiBtJ,EACjB,EAAA,EAEIolB,EAAYhC,EAAS,QACrBxc,EAAWwc,EAAS,SASpBiC,EAAWvkB,EAAK,cAA2B,uBAAuB,EAClEwkB,EAAa9iB,GAAWxC,EAAO,UAAU,CAAC,EAC1CulB,EAAaD,IAAe,OAC9BC,GAAc,CAACF,GAAY/b,EAAI,OACjC,QAAQ,KACN,wGACAxI,CAAA,EAGJ,MAAM0kB,EAAUD,GAAc,CAAC,CAACF,EAC1BI,EAAiBnjB,EAAStC,EAAO,qBAAqB,EAAG,EAAE,EAE3DtD,EAAO4M,EAAI,KAAK,KAChBrH,EAAgBqH,EAAI,KAAK,QAAQ,cACjCoc,EAAYpc,EAAI,KAAK,QAAQ,UAC7Bqc,EAAgBrc,EAAI,KAAK,QAAQ,cAQjCsc,EAAe,IAAczU,EAAK,aAAeA,EAAK,wBAAwB,MAMpF,IAAI0U,EACAC,EAAa,EAEjB,MAAMC,EAActS,GAAoD,CACtE,MAAMqR,EAAYhkB,EAAK,sBAAA,EAAwB,MACzCikB,EAAgBa,EAAA,EACtB,GAAI,CAACd,GAAa,CAACC,EAAe,OAClCe,EAAaf,EAMb,MAAMiB,EAAcR,EAAWV,EAAYW,EAAkB,IAAM,EAE7DR,EAASL,GAAUzT,EAAM0T,EAAOC,EAAWC,EAAeiB,CAAW,EASrEC,EAA6BZ,GAAU,MAAM,YAAc,GAC7DG,GAAWH,IACbA,EAAS,MAAM,WAAa,GAAG,CAACW,CAAW,MAO7C,MAAME,EAASxpB,EAAK,MAAM,KACxB,CAACqoB,EACD,CAAA,EAEFroB,EAAK,IAAImoB,EAAO,CAAE,EAAG,EAAG,EAQxB,IAAIsB,EACJA,EAAOzpB,EAAK,GAAGmoB,EAAO,CACpB,EAAG,CAACE,EACJ,SAAAne,EACA,KAAM,OACN,OAAQ,GACR,OAAQ,GACR,kBAAmB,IAAMuf,EAAK,SAAS,CAAC,EACxC,UAAW,CACT,EAAIta,GAAcqa,EAAM,WAAWra,CAAC,CAAC,EAAI,IAAA,CAC3C,CACD,EACDga,EAAaM,EAIb,MAAMC,EAAgBhjB,EAAO,QAAU,GAAK,EACtCijB,EAAY,CAAE,MAAOD,CAAA,EAC3B,IAAIE,EAAsBF,EAGtBG,EAOJ,MAAMC,EAAc,CAAE,MAAO,CAAA,EAEvBC,EAAiB,IAAY,CACjC,MAAMC,EAAKL,EAAU,MAAQG,EAAY,MAYnCvF,EAAIkF,EAAK,SAAA,EACXO,EAAK,GAAKzF,GAAK,EAAGkF,EAAK,SAAS,CAAC,EAC5BO,EAAK,GAAKzF,GAAK,GAAGkF,EAAK,SAAS,CAAC,EAC1CA,EAAK,UAAUO,CAAE,EAIjB,MAAMjO,EAAM4N,EAAU,MAAQ,EAAI,QAAU,OACxC5N,IAAQ8N,IACVzlB,EAAK,aAAa,uBAAwB2X,CAAG,EAC7C8N,EAAoB9N,EAExB,EAMI,OAAOhF,GAAiB,UAAU0S,EAAK,SAAS1S,CAAY,EAChEgT,EAAA,EACIrB,KAAgB,KAAA,EAEpB,MAAMnF,EAA8B,CAAA,EAQpC,GAAIuF,GAAWH,GAAYpjB,EAAe,CACxC,MAAM0kB,EAAW7B,EAAYW,EAAkB,IAGzCmB,EAASR,EAAgB,EAAIO,EAAU,CAACA,EACxCE,EAAO,CAACD,EACRE,EAAapqB,EAAK,OACtB2oB,EACA,CAAE,EAAGuB,CAAA,EACL,CACE,EAAGC,EACH,KAAM,OACN,gBAAiB,GACjB,cAAe,CACb,QAAS/lB,EACT,MAAO,aACP,IAAK,aACL,MAAOwkB,EACP,oBAAqB,EAAA,CACvB,CACF,EAEFrF,EAAS,KAAK,IAAM,CAChB6G,EAAwD,eAAe,KAAA,EACzEA,EAAW,KAAA,CACb,CAAC,CACH,CAEA,IAAIC,EAAsC,KAQ1C,GAAI3jB,EAAO,YACT,GAAI,CAACsiB,GAAa,OAAOA,EAAU,QAAW,YAAc,CAACC,EACvDrc,EAAI,OACN,QAAQ,KACN,iJACAxI,CAAA,MAGC,CACL,MAAMwgB,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,aAAa,cAAe,MAAM,EACxCA,EAAM,MAAM,QAAU,0DACtBxgB,EAAK,YAAYwgB,CAAK,EAEtB,MAAM0F,EAAQtqB,EAAK,MAAM,KAAyD,EAAG,CAAC,EAChFuqB,EAAQ,EAAIlC,EAClB,IAAImC,EAAgB,EAIhBC,GAAiBf,EAKrB,MAAMgB,GAAkBrC,EAAgBne,EAGxC,IAAIygB,GAAa,EACbC,GAAa,EACbC,GAAY,GAEhB,MAAMC,GAAQ,IAAY,CACnBT,GACLZ,EAAK,SAASa,EAAKE,GAAiBH,EAAU,OAASA,EAAU,GAAKE,CAAK,CAAC,CAC9E,EAEMQ,GAAa,IAAY,CAGxBrC,IACLiB,EAAU,MAAQc,GAClBV,EAAA,EACAN,EAAK,OAAA,EACP,EAEAY,EAAYrB,EAAU,OAAOpE,EAAO,CAClC,QAASxgB,EACT,KAAM,IACN,QAAS,GACT,OAAQ,OACR,aAAc,WACd,aAAqC,CACnCpE,EAAK,aAAa2pB,CAAS,EAC3B3pB,EAAK,aAAaypB,CAAI,EACtBA,EAAK,MAAA,EACLe,EAAgBf,EAAK,SAAA,EAIrBzpB,EAAK,IAAI4kB,EAAO,CAAE,EAAG,CAAC4F,EAAgBD,EAAO,EAC7CK,GAAa,EACbC,GAAY,EACd,EACA,OAAQC,GACR,eAAuC,CAQrC,GAPAA,GAAA,EAOI,CAACpC,GAAamC,GAAW,OAC7B,MAAMG,GAAM,YAAY,IAAA,EAClB7b,GAAI,KAAK,EACf,GAAIyb,GAAY,CACd,MAAMK,IAAMD,GAAMJ,IAAc,IAChC,GAAIK,GAAK,GAAK,KAAK,IAAI9b,GAAIwb,EAAU,EAAIM,IAAMP,GAAiB,CAC9DG,GAAY,GACZ,KAAK,OAAO,KAAA,EACZE,GAAA,EACA,MACF,CACF,CACAJ,GAAaxb,GACbyb,GAAaI,EACf,EACA,WAAmC,CAMjC,MAAMjP,GAAM,KAAK,aAAa,UAAU,EACpCA,GAAI,WAAW,OAAO,EAAG0O,GAAiB,GACrC1O,GAAI,WAAW,MAAM,IAAG0O,GAAiB,GAG7C,KAAK,YAAYM,GAAA,CACxB,EACA,gBAAiBA,EAAA,CAClB,EAAE,CAAC,EAEJxH,EAAS,KAAK,IAAM,CAClB8G,GAAW,KAAA,EACXzF,EAAM,OAAA,CACR,CAAC,CACH,CAQF,GAAI8B,EAAS,YAAc,CAAChgB,EAAO,aAAegiB,EAAW,CAC3D,IAAIwC,EAAgB,GACpB3H,EAAS,KACPlB,GAAyB,CACvB,KAAAje,EACA,QAAS,IAAM,CACTqlB,EAAK,WACTA,EAAK,MAAA,EACLyB,EAAgB,GAClB,EACA,QAAS,IAAM,CACRA,IACLA,EAAgB,GAChBzB,EAAK,OAAA,EACP,CAAA,CACD,CAAA,CAEL,CAOA,GAAI/C,EAAS,WAAa,CAACA,EAAS,YAAc,CAAChgB,EAAO,aAAegiB,EAAW,CAClF,MAAMyC,EAAUhiB,GAAyB,CACvCnJ,EAAK,aAAa8pB,CAAW,EAC7B9pB,EAAK,GAAG8pB,EAAa,CACnB,MAAO3gB,EACP,SAAU,GACV,KAAM,aACN,SAAU4gB,EACV,WAAYA,CAAA,CACb,CACH,EACAxG,EAAS,KACPlB,GAAyB,CACvB,KAAAje,EACA,QAAS,IAAM+mB,EAAOlD,EAAiB,EACvC,QAAS,IAAMkD,EAAO,CAAC,CAAA,CACxB,CAAA,EAEH5H,EAAS,KAAK,IAAMvjB,EAAK,aAAa8pB,CAAW,CAAC,CACpD,CAKA,GAAIpjB,EAAO,WAAa,CAACA,EAAO,aAAegiB,EAAW,CACxD,MAAMxa,EAAQ,IAAY,CAGxB,MAAMkd,IAFkB,SAAS,KAAK,aAAa,qBAAqB,GAAK,UACtC,KACL,CAAC1B,EAAgBA,EAC/C0B,KAAiBxB,IACrBA,EAAsBwB,GACtBprB,EAAK,aAAa2pB,CAAS,EAC3B3pB,EAAK,GAAG2pB,EAAW,CACjB,MAAOyB,GACP,SAAU,GACV,KAAM,aACN,SAAUrB,EACV,WAAYA,CAAA,CACb,EACH,EACMsB,EAAK,IAAI,iBAAkBC,GAAc,CAC7C,UAAW5e,KAAK4e,EACd,GAAI5e,EAAE,gBAAkB,sBAAuB,CAC7CwB,EAAA,EACA,KACF,CAEJ,CAAC,EACDmd,EAAG,QAAQ,SAAS,KAAM,CACxB,WAAY,GACZ,gBAAiB,CAAC,qBAAqB,CAAA,CACxC,EACD9H,EAAS,KAAK,IAAM8H,EAAG,WAAA,CAAY,EACnCnd,EAAA,CACF,CAMA,MAAMwV,GAAcxB,GAAmBtV,EAAI,KAAM,CAC/C,QAASxI,EACT,SAAU,IAAM,CACVskB,KAAgB,OAAA,EACpBqB,EAAA,EACAM,GAAW,OAAA,CACb,EACA,OAAQ,IAAM,CACZZ,EAAK,MAAA,EACLY,GAAW,QAAA,CACb,CAAA,CACD,EACD,OAAI3G,IAAaH,EAAS,KAAKG,EAAW,EAEnC,IAAM,CACX,UAAW3a,KAAMwa,EAAUxa,EAAA,EAC3B/I,EAAK,aAAa2pB,CAAS,EAC3BF,EAAK,KAAA,EACDN,IAAeM,IAAMN,EAAa,QACtC,UAAWrU,KAAKyT,EAAQzT,EAAE,OAAA,EAC1B9U,EAAK,IAAImoB,EAAO,CAAE,WAAY,cAAe,EACzCW,GAAWH,IACb3oB,EAAK,IAAI2oB,EAAU,CAAE,WAAY,cAAe,EAIhDA,EAAS,MAAM,WAAaY,GAE9BnlB,EAAK,gBAAgB,sBAAsB,CAC7C,CACF,EAUA,IAAImnB,EAAgBlC,EAAA,EACpB,GAAI,CAACkC,GAAiB,OAAO,eAAmB,IAAa,OAa7D,IAAIC,EACAC,EAAe,GACnB,MAAMC,EAAmBC,GAAyB,CAC5CA,IAAOF,EAAe,IACtBD,gBAA2BA,CAAY,EAC3CA,EAAe,WAAW,IAAM,CAC9BA,EAAe,OACf,MAAMI,EAAUH,EAChBA,EAAe,GACf,MAAM1I,EAAOmG,EAAA,EAEb,GADI,CAACnG,GACD,KAAK,IAAIA,EAAOqG,CAAU,EAAI,GAAK,CAACwC,EAAS,OACjD,MAAM7U,EAAeoS,EAAaA,EAAW,SAAA,EAAa,OAC1DoC,IAAA,EACAA,EAAgBlC,EAAWtS,CAAY,CACzC,EAAG,GAAG,CACR,EAEM8U,EACJ,OAAO,eAAmB,IACtB,IAAI,eAAe,IAAMH,EAAgB,EAAK,CAAC,EAC/C,KACNG,GAAI,QAAQpX,CAAI,EAKhB,MAAMqX,EAAYhD,EAAUlc,EAAI,SAAS,IAAM8e,EAAgB,EAAI,EAAG,GAAG,EAAI,OAE7E,MAAO,IAAM,CACPF,gBAA2BA,CAAY,EAC3CK,GAAI,WAAA,EACJC,IAAA,EACAP,IAAA,CACF,CACF,CAOA,SAASQ,GAAmB3nB,EAAiD,CAC3E,MAAMlB,EAAQzC,EAAU2D,CAAI,EACtBukB,EAAWvkB,EAAK,cAA2B,uBAAuB,EACxE,GAAI,CAACukB,EAAU,OAAOzlB,EACtB,MAAM8oB,EAAgBvrB,EAAUkoB,CAAQ,EACxC,SAAW,CAACpkB,EAAK1D,CAAM,IAAKmrB,EAAc,QAAS,CACjD,MAAMC,EAASprB,EAAO,qBAAqB,EAC3C,GAAIorB,IAAW,OAAW,SAC1B,IAAI9iB,EAASjG,EAAM,QAAQ,IAAIqB,CAAgB,EAC1C4E,IACHA,EAAS,CAAA,EACTjG,EAAM,QAAQ,IAAIqB,EAAkB4E,CAAM,GAE5CA,EAAO,qBAAqB,EAAI8iB,CAClC,CACA,OAAO/oB,CACT,sEAEsC,CACpC,KAAM,UACN,KAAK0J,EAAiC,CACpC,OAAAI,GAAgBJ,EAAK,aAAcE,GAAUif,EAAkB,EACxD,IAAM,CAAC,CAChB,CACF,yCCvoBA,SAASG,GAAcrpB,EAA2C,CAChE,MAAMP,EAAyB,CAAE,KAAM,GAAO,OAAQ,GAAO,WAAY,IAAK,KAAM,EAAA,EACpF,GAAI,CAACO,EAAO,OAAOP,EACnB,MAAMoE,EAAS7D,EAAM,MAAM,KAAK,EAAE,OAAO,OAAO,EAChD,UAAWmF,KAAStB,EAClB,GAAIsB,IAAU,OAAQ1F,EAAO,KAAO,WAC3B0F,IAAU,OAAQ1F,EAAO,KAAO,WAChC0F,IAAU,SAAU1F,EAAO,OAAS,WACpC0F,EAAM,WAAW,SAAS,EAAG,CACpC1F,EAAO,OAAS,GAChB,MAAMhC,EAAI,SAAS0H,EAAM,MAAM,CAAC,EAAG,EAAE,EACjC,OAAO,SAAS1H,CAAC,MAAU,WAAaA,EAC9C,CAKF,OAAOgC,CACT,CAOA,SAAS6pB,GAAmBvf,EAAqBwf,EAAqC,CACpF,MAAMlpB,EAAQzC,EAAU2rB,CAAU,EAClC,OAAAxf,EAAI,WAAW,KAAKwf,EAAYlpB,EAAO,CAAC,CAAE,OAAAI,KAAa,CACrD,MAAM6E,EAAS+jB,GAAc5oB,EAAO,QAAQ,CAAC,EAC7C,GAAI6E,EAAO,KAAM,OAEjB,MAAMob,EAA8B,CAAA,EAEpC,GAAIpb,EAAO,KAAM,CAYf,MAAMnI,EAAO4M,EAAI,KAAK,KAChB6K,EAAY7R,EAAStC,EAAO,cAAc,EAAG,CAAC,EAC9C4G,EAAWtE,EAAStC,EAAO,aAAa,EAAGsJ,EAAI,QAAQ,QAAQ,EAC/DzC,EAAO7G,EAAO,SAAS,GAAK,OAC5B+oB,EAAU,KAAO5U,EAKjB5J,EAAO,SAAS,KAChBye,EAAa,IACjBze,EAAK,aAAa,qBAAqB,IAAM,QAC7CA,EAAK,aAAa,mBAAmB,IAAM,OAE7C,IAAI0e,EAASD,EAAA,EAKTC,GAAQvsB,EAAK,IAAIosB,EAAY,CAAE,SAAUC,EAAS,EAEtD,IAAIthB,EACJ,MAAMoY,EAAO,IAAY,CACvB,MAAMJ,EAAOuJ,EAAA,EACTvJ,IAASwJ,IACbA,EAASxJ,EACThY,EAAQ/K,EAAK,GAAGosB,EAAY,CAC1B,SAAUrJ,EAAOsJ,EAAU,EAC3B,SAAAniB,EACA,KAAAC,EACA,UAAW,MAAA,CACZ,EACH,EAEMqE,EAAW,IAAI,iBAAiB2U,CAAI,EAC1C3U,EAAS,QAAQX,EAAM,CACrB,WAAY,GACZ,gBAAiB,CAAC,sBAAuB,mBAAmB,CAAA,CAC7D,EAED0V,EAAS,KAAK,IAAM,CAClB/U,EAAS,WAAA,EACTzD,GAAO,KAAA,EACP/K,EAAK,IAAIosB,EAAY,CAAE,SAAU,EAAG,CACtC,CAAC,CACH,CAEA,GAAIjkB,EAAO,OAAQ,CACjB,MAAMqkB,EAAYrkB,EAAO,WACzB,IAAIskB,EAAW,GACf,MAAMC,EAAS,IAAY,CACzB,MAAMC,EAAO,OAAO,SAAWH,EAC3BG,GAAQ,CAACF,GACXL,EAAW,UAAU,IAAI,aAAa,EACtCK,EAAW,IACF,CAACE,GAAQF,IAClBL,EAAW,UAAU,OAAO,aAAa,EACzCK,EAAW,GAEf,EACAC,EAAA,EACA,OAAO,iBAAiB,SAAUA,EAAQ,CAAE,QAAS,GAAM,EAC3DnJ,EAAS,KAAK,IAAM,CAClB,OAAO,oBAAoB,SAAUmJ,CAAM,EAC3CN,EAAW,UAAU,OAAO,aAAa,CAC3C,CAAC,CACH,CAEA,MAAO,IAAM7I,EAAS,QAASzO,GAAMA,GAAG,CAC1C,CAAC,EAEM,IAAM,CAAC,CAChB,CAOA,SAAS8X,GACPhgB,EACAwf,EACY,CACZ,MAAM7mB,EAAgBqH,EAAI,KAAK,QAAQ,cACvC,GAAI,CAACrH,EAAe,MAAO,IAAM,CAAC,EAElC,MAAMsnB,EAAWT,EAAW,iBAA8B,oBAAoB,EAC9E,GAAIS,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMrnB,EAAoC,CAAA,EAC1C,OAAAqnB,EAAS,QAASC,GAAY,CAC5B,MAAMvd,EAAiBud,EAAQ,aAAa,kBAAkB,EAC9D,GAAI,CAACvd,EAAgB,OACrB,MAAMwd,EAAU,SAAS,cAAcxd,CAAc,EACrD,GAAI,CAACwd,EAAS,OAEd,MAAMC,EAAa,IAAY,CAC7BH,EAAS,QAASI,GAASA,EAAK,UAAU,OAAO,YAAY,CAAC,EAC9DH,EAAQ,UAAU,IAAI,YAAY,CACpC,EACMI,EAAe,IAAY,CAC/BJ,EAAQ,UAAU,OAAO,YAAY,CACvC,EAEAtnB,EAAS,KACPD,EAAc,OAAO,CACnB,QAASwnB,EACT,MAAO,SACP,IAAK,WACL,oBAAqB,GACrB,QAASC,EACT,YAAaA,EACb,QAASE,EACT,YAAaA,CAAA,CACd,CAAA,CAEL,CAAC,EAEM,IAAM,CACX,UAAWvnB,KAAKH,EACd,GAAI,CACFG,EAAE,KAAA,CACJ,MAAQ,CAER,CAEJ,CACF,CAMA,SAASwnB,GAAoBvgB,EAAqBwf,EAAqC,CACrF,MAAM7mB,EAAgBqH,EAAI,KAAK,QAAQ,cACvC,GAAI,CAACrH,EAAe,MAAO,IAAM,CAAC,EAElC,MAAM6nB,EAAW,SAAS,iBAA8B,kBAAkB,EAC1E,GAAIA,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMC,EAAuB,CAAA,EAC7BD,EAAS,QAASL,GAAY,CAC5B,MAAMO,EAAMP,EAAQ,aAAa,gBAAgB,EAC7CO,GAAKD,EAAW,KAAKC,CAAG,CAC9B,CAAC,EAED,MAAM9nB,EAAoC,CAAA,EAC1C,OAAA4nB,EAAS,QAASL,GAAY,CAC5B,MAAMQ,EAAeR,EAAQ,aAAa,gBAAgB,EAC1D,GAAI,CAACQ,EAAc,OAEnB,MAAMtK,EAAQ8J,EAAQ,aAAa,iBAAiB,GAAK,SACnDS,EAAMT,EAAQ,aAAa,eAAe,GAAK,YAE/CU,EAAY,IAAY,CAC5B,UAAWH,KAAOD,EAAYjB,EAAW,UAAU,OAAOkB,CAAG,EAC7DlB,EAAW,UAAU,IAAImB,CAAY,CACvC,EACMG,EAAc,IAAY,CAC9BtB,EAAW,UAAU,OAAOmB,CAAY,CAC1C,EAEA/nB,EAAS,KACPD,EAAc,OAAO,CACnB,QAASwnB,EACT,MAAA9J,EACA,IAAAuK,EACA,oBAAqB,GACrB,QAASC,EACT,YAAaA,EACb,QAASC,EACT,YAAaA,CAAA,CACd,CAAA,CAEL,CAAC,EAEM,IAAM,CACX,UAAW/nB,KAAKH,EACd,GAAI,CACFG,EAAE,KAAA,CACJ,MAAQ,CAER,CAEF,UAAW2nB,KAAOD,EAAYjB,EAAW,UAAU,OAAOkB,CAAG,CAC/D,CACF,CAQA,SAASK,GAAoBC,EAAyC,CACpE,MAAM1jB,EAAWtE,EAASgoB,EAAU,aAAa,aAAa,GAAK,OAAW,EAAG,EAC3EzjB,EAAOyjB,EAAU,aAAa,SAAS,GAAK,aAClD,MAAO,CACL,SAAA1jB,EACA,KAAAC,EACA,WAAY,CAAE,SAAAD,EAAU,KAAAC,EAAM,SAAU,GAAM,OAAQ,GAAM,UAAW,MAAA,CAAO,CAElF,CAEA,SAAS0jB,GAAezB,EAAyB0B,EAA6C,CAE5F,OADiB1B,EAAW,cAA2B,+BAA+B,GACnE0B,EAAM,CAAC,CAC5B,CAMA,SAASC,GAAsBnhB,EAAqBwf,EAAqC,CACvF,MAAM4B,EAAOphB,EAAI,KAAK,QAAQ,KAC9B,GAAI,CAACohB,EAAM,MAAO,IAAM,CAAC,EAEzB,MAAMJ,EAAYxB,EAAW,cAA2B,4BAA4B,EACpF,GAAI,CAACwB,EAAW,MAAO,IAAM,CAAC,EAE9B,MAAMf,EAAWT,EAAW,iBAA8B,oBAAoB,EAC9E,GAAIS,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMoB,EAAMN,GAAoBC,CAAS,EACzC,IAAIM,EAAsC,KAE1C,sBAAsB,IAAM,CAC1B,MAAMjB,EAAOY,GAAezB,EAAYS,CAAQ,EAC3CI,IACLiB,EAAkBjB,EAClBe,EAAK,IAAIJ,EAAWX,EAAM,CAAE,SAAU,EAAG,SAAU,GAAM,OAAQ,EAAA,CAAM,EACvE,WAAW,IAAM,CACfW,EAAU,MAAM,QAAU,GAC5B,EAAGK,EAAI,SAAW,GAAI,EACxB,CAAC,EAED,MAAMzf,EAAW,IAAI,iBAAkB8c,GAAc,CACnD,UAAW6C,KAAY7C,EAAW,CAChC,GAAI6C,EAAS,OAAS,aAAc,SACpC,MAAMhlB,EAASglB,EAAS,OACxB,GAAIhlB,EAAO,UAAU,SAAS,YAAY,EAAG,CAC3C+kB,EAAkB/kB,EAClB6kB,EAAK,IAAIJ,EAAWzkB,EAAQ8kB,EAAI,UAAU,EAC1C,KACF,CACF,CACF,CAAC,EACDpB,EAAS,QAASI,GAAS,CACzBze,EAAS,QAAQye,EAAM,CAAE,WAAY,GAAM,gBAAiB,CAAC,OAAO,EAAG,CACzE,CAAC,EAED,MAAMnB,EAAYlf,EAAI,SAAS,IAAM,CAC/BshB,GACFF,EAAK,IAAIJ,EAAWM,EAAiB,CAAE,SAAU,EAAG,SAAU,GAAM,OAAQ,EAAA,CAAM,CAEtF,EAAG,EAAE,EAEL,MAAO,IAAM,CACX1f,EAAS,WAAA,EACTsd,EAAA,CACF,CACF,CAMA,SAASsC,GAAoBxhB,EAAqBwf,EAAqC,CACrF,MAAM4B,EAAOphB,EAAI,KAAK,QAAQ,KAC9B,GAAI,CAACohB,EAAM,MAAO,IAAM,CAAC,EAKzB,GAFE,OAAO,OAAW,MACjB,iBAAkB,SAAW,WAAW,gBAAkB,GAAK,SAC9C,IAAM,CAAC,EAE3B,MAAMJ,EAAYxB,EAAW,cAA2B,0BAA0B,EAClF,GAAI,CAACwB,EAAW,MAAO,IAAM,CAAC,EAE9B,MAAMf,EAAWT,EAAW,iBAA8B,oBAAoB,EAC9E,GAAIS,EAAS,SAAW,EAAG,MAAO,IAAM,CAAC,EAEzC,MAAMoB,EAAMN,GAAoBC,CAAS,EACzC,IAAIM,EAAsC,KACtCzL,EAAa,GAEjB,MAAM4L,EAAY,CAACllB,EAAqBmlB,IAAoC,CACtEA,IAAqB,EACvBN,EAAK,IAAIJ,EAAWzkB,EAAQ,CAAE,SAAU,EAAG,SAAU,GAAM,OAAQ,EAAA,CAAM,EAEzE6kB,EAAK,IAAIJ,EAAWzkB,EAAQ8kB,EAAI,UAAU,CAE9C,EAEA,sBAAsB,IAAM,CAC1B,MAAMhB,EAAOY,GAAezB,EAAYS,CAAQ,EAC3CI,IACLiB,EAAkBjB,EAClBoB,EAAUpB,EAAM,CAAC,EACjB,WAAW,IAAM,CACfW,EAAU,MAAM,QAAU,GAC5B,EAAGK,EAAI,SAAW,GAAI,EACxB,CAAC,EAED,MAAMzf,EAAW,IAAI,iBAAkB8c,GAAc,CACnD,UAAW6C,KAAY7C,EAAW,CAChC,GAAI6C,EAAS,OAAS,aAAc,SACpC,MAAMhlB,EAASglB,EAAS,OACxB,GAAIhlB,EAAO,UAAU,SAAS,YAAY,EAAG,CAC3C+kB,EAAkB/kB,EACbsZ,GAAY4L,EAAUllB,CAAM,EACjC,KACF,CACF,CACF,CAAC,EACD0jB,EAAS,QAASI,GAAS,CACzBze,EAAS,QAAQye,EAAM,CAAE,WAAY,GAAM,gBAAiB,CAAC,OAAO,EAAG,CACzE,CAAC,EAED,MAAMsB,MAAoB,IAC1B1B,EAAS,QAASI,GAAS,CACzB,MAAMlkB,EAAK,IAAY,CACrB0Z,EAAa,GACb4L,EAAUpB,CAAI,CAChB,EACAA,EAAK,iBAAiB,aAAclkB,CAAE,EACtCwlB,EAAc,IAAItB,EAAMlkB,CAAE,CAC5B,CAAC,EAED,MAAMylB,EAAa,IAAY,CAC7B/L,EAAa,GACTyL,KAA2BA,CAAe,CAChD,EACA9B,EAAW,iBAAiB,aAAcoC,CAAU,EAEpD,MAAM1C,EAAYlf,EAAI,SAAS,IAAM,CAC/BshB,GAAiBG,EAAUH,EAAiB,CAAC,CACnD,EAAG,EAAE,EAEL,MAAO,IAAM,CACX1f,EAAS,WAAA,EACT,SAAW,CAACye,EAAMlkB,CAAE,IAAKwlB,EAAetB,EAAK,oBAAoB,aAAclkB,CAAE,EACjFqjB,EAAW,oBAAoB,aAAcoC,CAAU,EACvD1C,EAAA,CACF,CACF,sEAEkC,CAChC,KAAM,MACN,KAAKlf,EAAiC,CACpC,MAAM6hB,EAAc7hB,EAAI,SAAS,OAC9BlM,GAA0BA,aAAc,aAAeA,EAAG,aAAa,QAAQ,CAAA,EAElF,GAAI+tB,EAAY,SAAW,EAAG,MAAO,IAAM,CAAC,EAE5C,MAAMC,EAA+B,CAAA,EACrC,UAAWtC,KAAcqC,EACvBC,EAAU,KACRvC,GAAmBvf,EAAKwf,CAAU,EAClCQ,GAAyBhgB,EAAKwf,CAAU,EACxCe,GAAoBvgB,EAAKwf,CAAU,EACnC2B,GAAsBnhB,EAAKwf,CAAU,EACrCgC,GAAoBxhB,EAAKwf,CAAU,CAAA,EAIvC,MAAO,IAAM,CACX,UAAWuC,KAAKD,EACd,GAAI,CACFC,EAAA,CACF,OAASpiB,EAAK,CACRK,EAAI,OAAO,QAAQ,MAAM,qCAAsCL,CAAG,CACxE,CAEJ,CACF,CACF,yCC/aO,SAASqiB,GACd3rB,EACA4rB,EACA,CAAE,SAAArhB,EAAW,GAAA,EAA+B,GAChC,CACZ,GAAI,OAAO,eAAmB,IAAa,MAAO,IAAM,CAAC,EACzD,IAAIshB,EAAY7rB,EAAQ,sBAAA,EAAwB,MAC5C8rB,EACJ,MAAMlD,EAAK,IAAI,eAAe,IAAM,CAClC,MAAMlpB,EAAQM,EAAQ,sBAAA,EAAwB,MAC1CN,IAAUmsB,IACdA,EAAYnsB,EACRA,IAAU,IACVosB,gBAAoBA,CAAK,EAC7BA,EAAQ,WAAWF,EAAUrhB,CAAQ,GACvC,CAAC,EACD,OAAAqe,EAAG,QAAQ5oB,CAAO,EACX,IAAM,CACP8rB,gBAAoBA,CAAK,EAC7BlD,EAAG,WAAA,CACL,CACF,CCCO,SAASvJ,GACdvf,EACAqB,EACA4qB,EACAnlB,EACoB,CACpB,MAAM7J,EAAO+C,EAAW,KAClB,CAAE,SAAAic,EAAU,SAAA9U,EAAU,KAAAC,EAAM,WAAA8U,GAAepV,EAC3ColB,EAAUplB,EAAQ,UAAY,IAAA,CAAiBmlB,EAAO,KAAK,CAAE,SAAA9kB,EAAU,KAAAC,CAAA,CAAM,IAEnF,IAAIoY,EAEO,KACPC,EAAkB,GAClB0M,EAAiB,GAErB,MAAMC,EAAmC,CAAA,EACzC,UAAWzuB,KAAM0D,EAAK,iBAA0B,sBAAsB,EAAG,CACvE,MAAMsK,EAAQwS,GAAoBxgB,EAAI,qBAAsByJ,EAAMnK,EAAK,GAAG,EACtE0O,GAAOygB,EAAgB,KAAKzgB,CAAK,CACvC,CACA,MAAMkU,EAAWd,GAAoB9hB,EAAMmvB,CAAe,EAEpDC,EAAgBpN,GAA8BY,EAAS,KAAKZ,EAAa,IAAMhD,CAAQ,EAEvFiE,EAAQ,IAAY,CACxB,GAAIV,EAAc,OAClB,MAAMO,EAAO,IAAY,CACvBmM,EAAA,EACAjvB,EAAK,YAAYkK,EAAW,EAAG,IAAM,CACnCklB,EAAaJ,EAAO,SAAS,CAC/B,CAAC,EACDzM,EAAeviB,EAAK,YAAYkK,EAAW8U,EAAU8D,CAAI,CAC3D,EACAsM,EAAaJ,EAAO,SAAS,EAC7BzM,EAAeviB,EAAK,YAAYgf,EAAU8D,CAAI,CAChD,EAEMI,EAAO,IAAY,CACnBX,IACFA,EAAa,KAAA,EACbA,EAAe,MAEjBK,EAAS,MAAA,EACTJ,EAAkB,EACpB,EAEM6M,EAAQ,IAAY,CACxBnM,EAAA,CACF,EAEMG,EAAe,IAAY,CAC3Bd,IACFA,EAAa,MAAA,EACbK,EAAS,MAAA,EACTJ,EAAkB,GAEtB,EAEMc,EAAkB,IAAY,CAC9Bf,GAAgBC,IAClBD,EAAa,OAAA,EACbK,EAAS,OAAA,EACTJ,EAAkB,GAEtB,EAEMe,EAA8B,CAAA,EAGhCtE,GACFsE,EAAS,KACPlB,GAAyB,CACvB,KAAAje,EACA,QAAS,IAAM,CACTme,GAAgB,CAACA,EAAa,OAAA,GAAUc,EAAA,CAC9C,EACA,QAAS,IAAM,CACTb,EAAiBc,EAAA,EACZ,CAACf,GAAgB,CAAC2M,GAAgBjM,EAAA,CAC7C,CAAA,CACD,CAAA,EAKL,MAAMS,EAAcxB,GAAmBnf,EAAY,CACjD,QAASqB,EACT,SAAU6e,EACV,OAAQC,CAAA,CACT,EACD,OAAIQ,EAAaH,EAAS,KAAKG,CAAW,EACrCT,EAAA,EAWE,CAAE,MAAAA,EAAO,KAAAC,EAAM,aAAAkM,EAAc,MAAAC,EAAO,kBAJhB/H,GAA0B,CACnD4H,EAAiB5H,CACnB,EAE8D,QAT9C,IAAY,CAC1BpE,EAAA,EACA,UAAWna,KAAMwa,EAAUxa,EAAA,CAC7B,CAM8D,CAChE,CCjIO,SAASumB,GACdtkB,EACAqf,EACAkF,EACY,CACZ,IAAIC,EAAc,EACdC,EAAc,EACdC,EAAoB,GACpBC,EAAoB,GAExB,MAAMC,EAAoBtgB,GAAwB,CAChDkgB,EAAclgB,EAAE,QAAQ,CAAC,EAAE,QAC3BmgB,EAAcngB,EAAE,QAAQ,CAAC,EAAE,OAC7B,EACMugB,EAAmBvgB,GAAwB,CAC/C,GAAIogB,EAAmB,OACvB,MAAMI,EAAS,KAAK,IAAIxgB,EAAE,QAAQ,CAAC,EAAE,QAAUkgB,CAAW,EAC3C,KAAK,IAAIlgB,EAAE,QAAQ,CAAC,EAAE,QAAUmgB,CAAW,EAC7CK,GACXzF,EAAU,QAAA,EACVsF,EAAoB,IAEpBD,EAAoB,EAExB,EACMK,EAAiB,IAAY,CAC5BL,GAAmBrF,EAAU,OAAA,EAC9BsF,IACFA,EAAoB,GACpBJ,EAAA,GAEFG,EAAoB,EACtB,EAEA,OAAA1kB,EAAQ,iBAAiB,aAAc4kB,EAAkB,CAAE,QAAS,GAAM,EAC1E5kB,EAAQ,iBAAiB,YAAa6kB,EAAiB,CAAE,QAAS,GAAM,EACxE7kB,EAAQ,iBAAiB,WAAY+kB,CAAc,EAE5C,IAAM,CACX/kB,EAAQ,oBAAoB,aAAc4kB,CAAgB,EAC1D5kB,EAAQ,oBAAoB,YAAa6kB,CAAe,EACxD7kB,EAAQ,oBAAoB,WAAY+kB,CAAc,CACxD,CACF,CCtCO,SAASC,GACdjtB,EACAktB,EACA3sB,EAA+B,CAAA,EACnB,CACZ,MAAMtD,EAAO+C,EAAW,KAClBimB,EAAYjmB,EAAW,QAAQ,UAE/B+qB,EAAwB9tB,EAAK,MAAM,QAA0CiwB,CAAQ,EACrFC,EAASpC,EAAM,OACfe,EAAWvrB,EAAO,SAClB6sB,EAAS7sB,EAAO,OAKhB8sB,EAAmB9sB,EAAO,OAASA,EAAO,MAAQ,EAAIA,EAAO,MAAQ,GAIrEgF,EAAYwlB,EAAM,CAAC,EAAE,WAErB/Y,EAAoB,CAAA,EAC1B,IAAIsb,EAAO,EACPC,EAAO,EACPC,EAAW,EACXC,EAAY,EACZC,EAAW,EACXC,EAAe,GAIfC,EAAiB,GAErB,MAAMC,EAAQ,CAACC,EAAaC,EAAaxvB,IACvCA,EAAIuvB,EAAMA,EAAMvvB,EAAIwvB,EAAMA,EAAMxvB,EAE5ByvB,EAAYrwB,GAChB,WAAW,OAAOV,EAAK,YAAYU,EAAI,IAAK,IAAI,CAAC,CAAC,GAAK,EAEnDswB,EAAmBnuB,GAA0B,CACjD,IAAIouB,EAAU,KACV7kB,EAAQ,EACZ,QAASuI,EAAI,EAAGA,EAAIub,EAAQvb,IAAK,CAC/B,MAAMga,EAAI,KAAK,IAAI5Z,EAAQJ,CAAC,EAAI9R,CAAK,EACjC8rB,EAAIsC,IACNA,EAAUtC,EACVviB,EAAQuI,EAEZ,CACA,OAAOvI,CACT,EAKM8kB,EAAavc,GACjBic,EAAMP,EAAMC,EAAMvb,EAAQ6b,EAAM,EAAGV,EAAS,EAAGvb,CAAC,CAAC,CAAC,EAE9Cwc,EAAW,IAAY,CAC3B,MAAMC,EAAiB9oB,EAAU,YACjCqoB,EAAiBS,IAAmB,EACpC,MAAMC,EAAYvD,EAAM,CAAC,EAAE,WAC3B,IAAIwD,EAAe,EACnBxD,EAAM,QAAQ,CAACptB,EAAIiU,IAAM,CACvB,MAAM4c,EAAY7wB,EAAG,WAAa2wB,EAC5B1uB,EAAQjC,EAAG,YACjBqU,EAAQJ,CAAC,EAAIwb,EAASiB,EAAiB,GAAKG,EAAY5uB,EAAQ,GAAK,CAAC4uB,EAGtED,EAAeC,EAAY5uB,CAC7B,CAAC,EACGwtB,GACFG,EAAOvb,EAAQ,CAAC,EAChBsb,EAAOtb,EAAQmb,EAAS,CAAC,IAEzBI,EAAO,EACPD,EAAO,KAAK,IAAI,EAAGe,EAAiBE,CAAY,EAEpD,EAEME,EAAUriB,GAAoB,CAClCnP,EAAK,IAAI8tB,EAAO,CAAE,EAAA3e,CAAA,CAAG,EACrBshB,EAAWthB,CACb,EAEMsiB,EAAcrlB,GAAwB,CACtCA,IAAUokB,IACdA,EAAYpkB,EACRyiB,GAAUA,EAASf,EAAM1hB,CAAK,EAAGA,CAAK,EAC5C,EAEM+P,EAAKnc,EAAK,SAAS,CAAE,OAAQ,GAAM,EAEnC0xB,EAAgB1E,GAAiC,CACrD,MAAM5gB,EAAQ4kB,EAAgBP,CAAQ,EACtC,OAAIzD,IACFuD,EAAWnkB,EACXskB,EAAe,IAEVtkB,CACT,EAEMulB,EAAU,IAAejB,EAAegB,EAAa,EAAI,EAAInB,EAEnE,IAAIqB,EAAyC,KAE7C,SAASC,EAAQzlB,EAAe+I,EAAyC,CACvE,MAAMhM,EAASynB,EAAM,EAAGV,EAAS,EAAG,KAAK,MAAM9jB,CAAK,CAAC,EAC/C0lB,EAAUZ,EAAU/nB,CAAM,EAChConB,EAAWpnB,EACXsoB,EAAWtoB,CAAM,EACjB,MAAMe,EAAWiL,GAAO,SACxB,GAAIjL,IAAa,EAAG,CAClB0nB,GAAW,KAAA,EACXJ,EAAOM,CAAO,EACd,MACF,CACA,OAAAF,EAAY5xB,EAAK,GAAG8tB,EAAO,CACzB,EAAGgE,EACH,SAAU5nB,GAAYkmB,EACtB,KAAOjb,GAAO,MAAkC,aAChD,UAAW,GACX,SAAU,IAAM,CACdsb,EAAWM,EAASjD,EAAM,CAAC,CAAC,CAC9B,EACA,WAAY,IAAM,CAChB2C,EAAWqB,CACb,CAAA,CACD,EACMF,CACT,CAEA,IAAIhN,EAEJ5kB,EAAK,IAAI8tB,EAAO,CAAE,EAAG,EAAG,EACxBqD,EAAA,EAEAhV,EAAG,QAAU0V,EACb1V,EAAG,aAAeuV,EAClBvV,EAAG,QAAUwV,EACbxV,EAAG,KAAQhH,GAAmC0c,EAAQF,EAAA,EAAY,EAAGxc,CAAI,EACzEgH,EAAG,SAAYhH,GAAmC0c,EAAQF,EAAA,EAAY,EAAGxc,CAAI,EAC7EgH,EAAG,MAAQpH,EAEX,MAAMvB,EAAU,IAAY,CAC1B,MAAMue,EAAYpB,EAClBQ,EAAA,EACA,MAAMa,EAAO7V,EAAG,UAIhB,GAHI6V,GACAA,EAA0D,YAAY,CAAE,KAAA3B,EAAM,KAAAC,EAAM,EAEpFyB,GAAa,CAACpB,EAGhBJ,EAAW,EACXC,EAAY,GACZE,EAAe,GACfc,EAAON,EAAU,CAAC,CAAC,EACnBO,EAAW,CAAC,MACP,CAML,MAAMQ,EAAYvB,EAAegB,EAAa,EAAI,EAAInB,EACtDiB,EAAON,EAAUe,CAAS,CAAC,CAC7B,CACF,EAGA,GAFA9V,EAAG,QAAU3I,EAETlQ,EAAO,WAAa0lB,GAAa,OAAOA,EAAU,QAAW,WAAY,CAC3EpE,EAAQ,SAAS,cAAc,KAAK,EACpC,IAAIyF,EAEJA,EAAYrB,EAAU,OAAOpE,EAAO,CAClC,QAASkJ,EAAM,CAAC,EAAE,WAClB,KAAM,IACN,OAAQ,CAAE,KAAAuC,EAAM,KAAAC,CAAA,EAChB,eAAgB,IAChB,QAAS,GACT,YAAa,IACb,YAAa,GACb,aAAqC,CAEnCsB,GAAW,KAAA,EAIXT,EAAA,EACE9G,EAA+D,YAAY,CAC3E,KAAAgG,EACA,KAAAC,CAAA,CACD,EACDtwB,EAAK,IAAI4kB,EAAO,CAAE,EAAG6L,EAAU,EAC/BntB,EAAO,cAAA,CACT,EACA,QAAgC,CAC9BkuB,EAAO,KAAK,CAAC,EACbC,EAAWT,EAAgB,KAAK,CAAC,CAAC,CACpC,EACA,eAAuC,CACrCQ,EAAO,KAAK,CAAC,EACbC,EAAWT,EAAgB,KAAK,CAAC,CAAC,CACpC,EACA,KAAKnuB,EAAuB,CAC1B,OAAO+tB,EAAMP,EAAMC,EAAMvb,EAAQic,EAAgBnuB,CAAK,CAAC,CAAC,CAC1D,EACA,WAAmC,CACjC,MAAMqvB,EAAc,CAAC,CAAC,KAAK,WAC3BR,EAAa,EAAI,EACbQ,IAAaxB,EAAe,IAChCptB,EAAO,YAAY4uB,CAAW,CAChC,EACA,iBAAkB,CAChBR,EAAa,EAAI,EACjBD,EAAWlB,CAAQ,EACnBjtB,EAAO,kBAAkBitB,CAAQ,CACnC,CAAA,CACD,EAAE,CAAC,EAEJpU,EAAG,aAAemT,GAChBxB,EAAM,CAAC,EAAE,WACTzD,EACA,IAAM/mB,EAAO,YAAY,EAAK,CAAA,EAGhC6Y,EAAG,UAAYkO,CACjB,CAIA,MAAM8H,EAAahW,EAAG,KAAK,KAAKA,CAAE,EAClC,OAAAA,EAAG,KAAO,KACRyV,GAAW,KAAA,EACX5xB,EAAK,aAAa8tB,CAAK,EACnBlJ,GAAO5kB,EAAK,aAAa4kB,CAAK,EAC3BuN,EAAA,GAGTX,EAAON,EAAU,CAAC,CAAC,EACnBX,EAAW,EACXC,EAAY,EACR3B,GAAUA,EAASf,EAAM,CAAC,EAAG,CAAC,EAE3B3R,CACT,CCzMO,SAASiW,GACdrvB,EACAktB,EACA3sB,EAA+B,CAAA,EACnB,CACZ,MAAMtD,EAAO+C,EAAW,KAClBimB,EAAYjmB,EAAW,QAAQ,UAE/B+qB,EAAwB9tB,EAAK,MAAM,QAA0CiwB,CAAQ,EACrFpB,EAAWvrB,EAAO,SACxB,IAAIktB,EAAY,EAChB,MAAMrU,EAAKnc,EAAK,SAAS,CACvB,OAAQsD,EAAO,OACf,SACEurB,GACA,UAAgD,CAC9C,MAAMla,EAAKwH,EAAiD,aAAA,EACxDqU,IAAc7b,IAChB6b,EAAY7b,EACZka,EAASf,EAAMnZ,CAAC,EAAGA,CAAC,EAExB,EACF,OAAQrR,EAAO,OACf,SAAU,CAAE,KAAM,MAAA,EAClB,kBAAmB,IAAM6Y,EAAG,UAAUA,EAAG,UAAYA,EAAG,SAAA,EAAa,GAAG,CAAA,CACzE,EAEK+T,EAASpC,EAAM,OACrB,IAAI5D,EAAS4D,EAAM,CAAC,EAAE,WACtB,MAAMuE,EAAkB,CAAA,EAClBC,EAAmB,CAAA,EACnBC,EAAwB,CAAA,EACxBC,EAAsB,CAAA,EAC5B,IAAIjC,EAAW,EACXG,EAAe,GACnB,MAAMP,EAAS7sB,EAAO,OAChBmvB,GAAmBnvB,EAAO,OAAS,GAAK,IACxCovB,EACJpvB,EAAO,OAAS,GACXhC,GAAcA,EACdtB,EAAK,MAAM,KACTsD,EAAO,MAA+B,CAAA,EAE/C,IAAIqvB,EAAa,EACjB,MAAMrqB,EACJ6nB,IAAW,GACNrC,EAAM,CAAC,EAAE,WACR9tB,EAAK,MAAM,QAA0CmwB,CAAM,EAAE,CAAC,GAC/DrC,EAAM,CAAC,EAAE,WAChB,IAAI8E,EAAa,EAIbjC,EAAiB,GAErB,MAAMkC,EAAgB,IACpB/E,EAAMoC,EAAS,CAAC,EAAE,WACjBsC,EAAUtC,EAAS,CAAC,EAAI,IAAOoC,EAAOpC,EAAS,CAAC,EACjDhG,EACA4D,EAAMoC,EAAS,CAAC,EAAE,YAAclwB,EAAK,YAAY8tB,EAAMoC,EAAS,CAAC,EAAG,QAAQ,GAC3E,WAAW,OAAO5sB,EAAO,cAAgB,CAAC,CAAC,GAAK,GAE7CwvB,EAAiB,IAAY,CACjC,IAAIC,EAAKzqB,EAAU,sBAAA,EACnBqoB,EAAiBoC,EAAG,QAAU,EAC9B,IAAIC,EACJlF,EAAM,QAAQ,CAACptB,EAAIiU,IAAM,CACvB2d,EAAO3d,CAAC,EAAI,WAAW3U,EAAK,YAAYU,EAAI,QAAS,IAAI,CAAC,EAC1D8xB,EAAU7d,CAAC,EAAI+d,EACZ,WAAW1yB,EAAK,YAAYU,EAAI,IAAK,IAAI,CAAC,EAAI4xB,EAAO3d,CAAC,EAAK,IACzD3U,EAAK,YAAYU,EAAI,UAAU,CAAA,EAEpCsyB,EAAKtyB,EAAG,sBAAA,EACR6xB,EAAY5d,CAAC,EAAIqe,EAAG,MAAQre,EAAIoe,EAAG,MAAQA,EAAG,MAC9CA,EAAKC,CACP,CAAC,EACDhzB,EAAK,IAAI8tB,EAAO,CACd,SAAWnZ,GAAc6d,EAAU7d,CAAC,CAAA,CACrC,EACDie,EAAaC,EAAA,CACf,EAEA,IAAII,EAAmC3yB,GAAMA,EAE7C,MAAM4yB,EAAkB,IAAY,CAClCP,EAAaxC,EAAUhU,EAAG,SAAA,GAAc7T,EAAU,YAAc,GAAMsqB,EAAa,EAC/EzC,GACFkC,EAAM,QAAQ,CAACc,EAAIxe,IAAM,CACvB0d,EAAM1d,CAAC,EAAIse,EACT9W,EAAG,OAAO,QAAUxH,CAAC,EAAKwH,EAAG,SAAA,EAAamW,EAAO3d,CAAC,EAAK,EAAIie,EAAaD,CAAA,CAE5E,CAAC,CAEL,EAEMS,EAAa,CAACC,EAAkBxwB,EAAeynB,IAAyB,CAC5E,IAAI3V,EAAI0e,EAAO,OACXpC,EAAU,KACV7kB,EAAQ,EACRuiB,EACJ,KAAOha,KACLga,EAAI,KAAK,IAAI0E,EAAO1e,CAAC,EAAI9R,CAAK,EAC1B8rB,EAAIrE,EAAO,IAAGqE,EAAIrE,EAAOqE,GACzBA,EAAIsC,IACNA,EAAUtC,EACVviB,EAAQuI,GAGZ,OAAOvI,CACT,EAEMknB,EAAmB,IAAY,CACnC,IAAIrG,EACAsG,EACAC,EACAC,EACJtX,EAAG,MAAA,EACH,QAASxH,EAAI,EAAGA,EAAIub,EAAQvb,IAC1BsY,EAAOa,EAAMnZ,CAAC,EACd4e,EAAQf,EAAU7d,CAAC,EAAI,IAAO2d,EAAO3d,CAAC,EACtC6e,EAAkBvG,EAAK,WAAasG,EAAOrJ,EAASqI,EAAY,CAAC,EACjEkB,EAAiBD,EAAkBlB,EAAO3d,CAAC,EAAI3U,EAAK,YAAYitB,EAAM,QAAQ,EAE9E9Q,EAAG,GACD8Q,EACA,CACE,SAAUyF,GAAOa,EAAOE,GAAkBnB,EAAO3d,CAAC,EAAK,GAAG,EAC1D,SAAU8e,EAAiBhB,CAAA,EAE7B,CAAA,EAEC,OACCxF,EACA,CAAE,SAAUyF,GAAOa,EAAOE,EAAiBb,GAAcN,EAAO3d,CAAC,EAAK,GAAG,CAAA,EACzE,CACE,SAAU6d,EAAU7d,CAAC,EACrB,UAAW4e,EAAOE,EAAiBb,EAAaW,GAAQd,EACxD,gBAAiB,EAAA,EAEnBgB,EAAiBhB,CAAA,EAElB,IAAI,QAAU9d,EAAG6e,EAAkBf,CAAe,EAErDJ,EAAM1d,CAAC,EAAI6e,EAAkBf,EAE/BQ,EAAYjzB,EAAK,MAAM,KACrB,EACAmc,EAAG,SAAA,CAAS,CAEhB,EAEM3I,EAAWkgB,GAAyB,CACxC,MAAM9Q,EAAWzG,EAAG,SAAA,EAOd6F,EAAsB0O,EAAevU,EAAG,aAAA,EAAiBoU,EAIzDwB,EAAYpB,EAClBxU,EAAG,SAAS,EAAG,EAAI,EACnB+N,EAAS4D,EAAM,CAAC,EAAE,WAClBgF,EAAA,EACIY,GAAMJ,EAAA,EACVJ,EAAA,EACIQ,GAAQ3B,GAAa,CAACpB,GAKxBJ,EAAW,EACXpU,EAAG,KAAKkW,EAAM,CAAC,EAAG,EAAI,EACtB7B,EAAY,EACR3B,GAAUA,EAASf,EAAM,CAAC,EAAG,CAAC,GACzB4F,GAAQvX,EAAG,WAGpBoU,EAAWvO,EACX0O,EAAe,GACfvU,EAAG,KAAKkW,EAAMrQ,CAAW,EAAG,EAAI,GAIhC7F,EAAG,SAASyG,EAAU,EAAI,CAE9B,EAEA,IAAIgC,EAEJ5kB,EAAK,IAAI8tB,EAAO,CAAE,EAAG,EAAG,EACxBgF,EAAA,EACAQ,EAAA,EACAJ,EAAA,EAEA,SAASrB,EAAQzlB,EAAe+I,EAAyC,CACvE,MAAM7T,EAA6B6T,EAAO,CAAE,GAAGA,CAAA,EAAS,CAAA,EACpD,KAAK,IAAI/I,EAAQmkB,CAAQ,EAAIL,EAAS,IACxC9jB,GAASA,EAAQmkB,EAAW,CAACL,EAASA,GAExC,MAAMyD,EAAY3zB,EAAK,MAAM,KAC3B,EACAkwB,EACA9jB,CAAA,EAEF,IAAI6E,EAAOohB,EAAMsB,CAAQ,EACzB,OAAI1iB,EAAOkL,EAAG,KAAA,GAAW/P,EAAQmkB,GAAYnkB,IAAUmkB,IACrDtf,GAAQkL,EAAG,SAAA,GAAc/P,EAAQmkB,EAAW,EAAI,MAE9Ctf,EAAO,GAAKA,EAAOkL,EAAG,cACxB7a,EAAE,UAAY,CAAE,KAAM2xB,CAAA,GAExB1C,EAAWoD,EACXryB,EAAE,UAAY,GACVsjB,GAAO5kB,EAAK,aAAa4kB,CAAK,EAC3BtjB,EAAE,WAAa,EAAI6a,EAAG,KAAK8W,EAAShiB,CAAI,CAAC,EAAIkL,EAAG,QAAQlL,EAAM3P,CAAC,CACxE,CAsBA,GApBA6a,EAAG,QAAU0V,EACb1V,EAAG,aAAgB6Q,GAAyB,CAC1C,MAAM5gB,EAAQgnB,EAAWf,EAAOlW,EAAG,OAAQA,EAAG,UAAU,EACxD,OAAI6Q,IACFuD,EAAWnkB,EACXskB,EAAe,IAEVtkB,CACT,EACA+P,EAAG,QAAU,IAAOuU,EAAevU,EAAG,aAAa,EAAI,EAAIoU,EAC3DpU,EAAG,KAAQhH,GAAmC0c,EAAQ1V,EAAG,QAAA,EAAY,EAAGhH,CAAI,EAC5EgH,EAAG,SAAYhH,GAAmC0c,EAAQ1V,EAAG,QAAA,EAAY,EAAGhH,CAAI,EAChFgH,EAAG,MAAQkW,EACXlW,EAAG,SAAS,EAAG,EAAI,EAAE,SAAS,EAAG,EAAI,EAEjC7Y,EAAO,WACT6Y,EAAG,KAAK,kBAAA,EACRA,EAAG,QAAA,GAGD7Y,EAAO,WAAa0lB,GAAa,OAAOA,EAAU,QAAW,WAAY,CAC3EpE,EAAQ,SAAS,cAAc,KAAK,EACpC,MAAM0F,EAAQtqB,EAAK,MAAM,KAAyD,EAAG,CAAC,EACtF,IAAIuqB,EAAQ,EACRC,EAAgB,EAChBoJ,EAAW,EACXC,EAAc,EACdC,EAAa,GACbzJ,EAEJ,MAAMS,EAAQ,IAAY,CACxB3O,EAAG,SAASmO,EAAKE,GAAiBH,EAAU,OAASA,EAAU,GAAKE,CAAK,CAAC,CAC5E,EACMwJ,EAAY,IAAc5X,EAAG,aAAa,EAAI,EAEpDkO,EAAYrB,EAAU,OAAOpE,EAAO,CAClC,QAASkJ,EAAM,CAAC,EAAE,WAClB,KAAM,IACN,aAAqC,CACnC,MAAM3e,EAAI,KAAK,EACfnP,EAAK,aAAamc,CAAE,EACpB2X,EAAa,CAAC3X,EAAG,OAAA,EACjBA,EAAG,MAAA,EACHqO,EAAgBrO,EAAG,SAAA,EACnB3I,EAAA,EACA+W,EAAQ,EAAIqI,EACZiB,EAAcrJ,EAAgB,CAACD,EAAQpb,EACvCnP,EAAK,IAAI4kB,EAAO,CAAE,EAAG4F,EAAgB,CAACD,EAAO,EAC7CjnB,EAAO,cAAA,CACT,EACA,OAAQwnB,EACR,cAAeA,EACf,mBAAoB,EACpB,QAAS,GACT,YAAa,IACb,YAAa,GACb,KAA8BjoB,EAAuB,CACnD,GAAI,KAAK,IAAI2nB,EAAgB,CAACD,EAAQ,KAAK,CAAC,EAAI,GAC9C,OAAOqJ,EAAWC,EAEpB,IAAI5iB,EAAO,EAAEpO,EAAQ0nB,GAASpO,EAAG,SAAA,EACjC,MAAM6X,GAAcf,EAAShiB,CAAI,EAEjC,IAAIgjB,EADa5B,EAAMe,EAAWf,EAAO2B,GAAa7X,EAAG,SAAA,CAAU,CAAC,EAC/C6X,GACrB,OAAI,KAAK,IAAIC,CAAG,EAAI9X,EAAG,WAAa,IAAG8X,GAAOA,EAAM,EAAI9X,EAAG,SAAA,EAAa,CAACA,EAAG,SAAA,GAC5EyX,GAAY3iB,EAAOgjB,GAAO9X,EAAG,SAAA,EAAa,CAACoO,EACpCqJ,CACT,EACA,WAAmC,CACjCG,EAAA,EACI,KAAK,aAAYrD,EAAe,IACpCptB,EAAO,YAAY,CAAC,CAAC,KAAK,UAAU,CACtC,EACA,gBAAiB,IAAM,CACrBywB,EAAA,EACID,KAAe,KAAA,EACnBxwB,EAAO,kBAAkBitB,CAAQ,CACnC,CAAA,CACD,EAAE,CAAC,EAEJpU,EAAG,aAAemT,GAChBxB,EAAM,CAAC,EAAE,WACTzD,EACA,IAAM/mB,EAAO,YAAY,EAAK,CAAA,EAGhC6Y,EAAG,UAAYkO,CACjB,CAEA,OAAAlO,EAAG,aAAa,EAAI,EAIhB7Y,EAAO,SACTuuB,EAAQ,EAAG,CAAE,SAAU,CAAA,CAAG,EAC1Bre,EAAQ,EAAI,GAGdgd,EAAYD,EACR1B,GAAUA,EAASf,EAAMyC,CAAQ,EAAGA,CAAQ,EAIhDpU,EAAG,QAAU3I,EAEN2I,CACT,CCnYA,MAAM+X,OAAmB,IAAI,CAAC,YAAa,aAAc,OAAQ,KAAK,CAAC,EAEhE,SAASrQ,GACdzf,EACA+vB,EACApQ,EACY,CAGZ,MAAMqQ,EAAchwB,EAAK,aAAa,UAAU,EAC3CgwB,GAAahwB,EAAK,aAAa,WAAY,GAAG,EAEnD,MAAM4f,EAAS1U,GAA2B,CACxC,GAAI,CAAC4kB,GAAa,IAAI5kB,EAAE,GAAG,EAAG,OAG9B,MAAMnG,EAASmG,EAAE,OACjB,GAAI,EAAAnG,IAAWA,EAAO,UAAY,SAAWA,EAAO,UAAY,aAGhE,OADAmG,EAAE,eAAA,EACMA,EAAE,IAAA,CACR,IAAK,aACHyU,EAAS,KAAA,EACT,MACF,IAAK,YACHA,EAAS,SAAA,EACT,MACF,IAAK,OACHA,EAAS,QAAQ,CAAC,EAClB,MACF,IAAK,MACCoQ,EAAQ,GAAGpQ,EAAS,QAAQoQ,EAAQ,CAAC,EACzC,KAAA,CAEN,EAEA,OAAA/vB,EAAK,iBAAiB,UAAW4f,CAAK,EAE/B,IAAM,CACX5f,EAAK,oBAAoB,UAAW4f,CAAK,EACpCoQ,GAAahwB,EAAK,gBAAgB,UAAU,CACnD,CACF,CC9CA,IAAIiwB,GAAwB,EAyBrB,SAASC,GAASlwB,EAAmBgB,EAAmB,GAAoB,CACjF,MAAM0oB,EAAQ,MAAM,KAAK1pB,EAAK,iBAA8B,kBAAkB,CAAC,EAC/E,GAAI0pB,EAAM,SAAW,EACnB,MAAO,CACL,SAAU,IAAM,CAAC,EACjB,MAAO,CAAA,EACP,MAAO,EACP,qBAAsB,IAAM,IAAM,CAAC,CAAA,EAIvC,MAAMqG,EAAQrG,EAAM,OACdyG,EAAiBnwB,EAAK,IAAM,aAAaiwB,IAAuB,GAEhEG,EAAapwB,EAAK,cAA2B,kBAAkB,EAC/DqwB,EAAarwB,EAAK,cAA2B,kBAAkB,EAC/DswB,EAAYtwB,EAAK,cAA2B,qBAAqB,EACjEuwB,EAAUvwB,EAAK,cAA2B,mBAAmB,EAI7DwwB,EAAiB,MAAM,KAAKxwB,EAAK,iBAA8B,oBAAoB,CAAC,EACpFywB,EAAiBzwB,EAAK,GACxB,MAAM,KACJ,SAAS,iBACP,wCAAwCA,EAAK,EAAE,IAAA,CACjD,EAEF,CAAA,EACE0wB,EAAS,CAAC,GAAGF,EAAgB,GAAGC,CAAc,EAI/CzwB,EAAK,aAAa,MAAM,GAAGA,EAAK,aAAa,OAAQ,QAAQ,EAClEA,EAAK,aAAa,uBAAwB,UAAU,EAIhD,CAACA,EAAK,aAAa,YAAY,GAAK,CAACA,EAAK,aAAa,iBAAiB,GAC1EA,EAAK,aAAa,aAAc,UAAU,EAI5C0pB,EAAM,QAAQ,CAACiH,EAAOpgB,IAAM,CAEtB,CADcogB,EAAM,UAAU,SAAS,YAAY,GACrC,CAACA,EAAM,aAAa,MAAM,GAAGA,EAAM,aAAa,OAAQ,OAAO,EACjFA,EAAM,aAAa,uBAAwB,OAAO,EAClDA,EAAM,aAAa,aAAc,SAASpgB,EAAI,CAAC,OAAOwf,CAAK,EAAE,EACxDY,EAAM,KAAIA,EAAM,GAAK,GAAGR,CAAc,UAAU5f,CAAC,GACxD,CAAC,EAEG6f,IACGA,EAAW,aAAa,YAAY,GAAGA,EAAW,aAAa,aAAc,YAAY,EACzFA,EAAW,aAAa,MAAM,GAAGA,EAAW,aAAa,OAAQ,QAAQ,GAE5EC,IACGA,EAAW,aAAa,YAAY,GACvCA,EAAW,aAAa,aAAc,gBAAgB,EACnDA,EAAW,aAAa,MAAM,GAAGA,EAAW,aAAa,OAAQ,QAAQ,GAG5EK,EAAO,OAAS,GAClBA,EAAO,QAAQ,CAACE,EAAKrgB,IAAM,CACpBqgB,EAAI,aAAa,YAAY,GAAGA,EAAI,aAAa,aAAc,eAAergB,EAAI,CAAC,EAAE,EAMtFqgB,EAAI,UAAY,UAAY,CAACA,EAAI,aAAa,MAAM,GAAGA,EAAI,aAAa,OAAQ,QAAQ,EAC5FA,EAAI,aAAa,gBAAiB,GAAGT,CAAc,UAAU5f,CAAC,EAAE,CAClE,CAAC,EAGCggB,IACFA,EAAQ,YAAcR,EAAQ,GAAK,IAAIA,CAAK,GAAK,OAAOA,CAAK,GAG/D,MAAMc,EAAe30B,GAAuBA,EAAI,GAAK,IAAIA,CAAC,GAAK,OAAOA,CAAC,EAqEvE,MAAO,CAAE,SAnEQ,CAAC40B,EAAgBC,IAA2B,CAC3D,MAAM/oB,GAAU+oB,EAAWhB,EAASA,GAASA,EA+B7C,GA7BArG,EAAM,QAAQ,CAACiH,EAAOpgB,IAAM,CAC1B,MAAMygB,EAAYL,EAAM,UAAU,SAAS,WAAW,EAChD5O,EAAWxR,IAAMvI,EACvB2oB,EAAM,UAAU,OAAO,YAAa5O,CAAQ,EAMxCA,GAAY,CAACiP,EAAWlsB,EAAY6rB,EAAO,cAAc,EACpD,CAAC5O,GAAYiP,GAAWlsB,EAAY6rB,EAAO,gBAAgB,CACtE,CAAC,EAEGD,EAAO,OAAS,GAClBA,EAAO,QAAQ,CAACE,EAAKrgB,IAAM,CACzB,MAAMwR,EAAWxR,IAAMvI,EACvB4oB,EAAI,UAAU,OAAO,YAAa7O,CAAQ,EACtCA,EAAU6O,EAAI,aAAa,eAAgB,MAAM,EAChDA,EAAI,gBAAgB,cAAc,CACzC,CAAC,EAGCN,IACFA,EAAU,YAAcO,EAAY7oB,EAAQ,CAAC,GAM3ChH,EAAK,OAAQ,CACf,GAAIqvB,EAAY,CACd,MAAMY,EAAWjpB,IAAU,EAC3BqoB,EAAW,UAAU,OAAO,cAAeY,CAAQ,EACnDZ,EAAW,aAAa,gBAAiB,OAAOY,CAAQ,CAAC,CAC3D,CACA,GAAIb,EAAY,CACd,MAAMa,EAAWjpB,IAAU+nB,EAAQ,EACnCK,EAAW,UAAU,OAAO,cAAea,CAAQ,EACnDb,EAAW,aAAa,gBAAiB,OAAOa,CAAQ,CAAC,CAC3D,CACF,CACF,EAuBmB,MAAAvH,EAAO,MAAAqG,EAAO,qBArBHpQ,GAA6C,CACzE,MAAMR,EAA8B,CAAA,EAC9B+R,EAAM,CAAC50B,EAAiB60B,EAAaxsB,IAA4B,CACrErI,EAAG,iBAAiB60B,EAAKxsB,CAAE,EAC3Bwa,EAAS,KAAK,IAAM7iB,EAAG,oBAAoB60B,EAAKxsB,CAAE,CAAC,CACrD,EAEA,OAAIyrB,GAAYc,EAAId,EAAY,QAAS,IAAMzQ,EAAS,MAAM,EAC1D0Q,GAAYa,EAAIb,EAAY,QAAS,IAAM1Q,EAAS,UAAU,EAClE+Q,EAAO,QAAQ,CAACE,EAAKrgB,IAAM,CACzB2gB,EAAIN,EAAK,QAAS,IAAM,CAClBrgB,IAAMoP,EAAS,WACnBA,EAAS,QAAQpP,CAAC,CACpB,CAAC,CACH,CAAC,EAEM,IAAM,CACX,UAAW5L,KAAMwa,EAAUxa,EAAA,CAC7B,CACF,CAEiC,CACnC,CC7JA,SAASysB,GAAiB7W,EAAuC,CAC/D,MAAMjY,GAAUiY,GAAO,IACpB,OACA,MAAM,KAAK,EACX,OAAO,OAAO,EACjB,MAAO,CACL,YAAajY,EAAO,SAAS,WAAW,EACxC,SAAUA,EAAO,SAAS,QAAQ,EAClC,SAAUA,EAAO,SAAS,QAAQ,EAClC,OAAQA,EAAO,SAAS,MAAM,CAAA,CAElC,CAEA,SAASoG,GAASF,EAAqBxI,EAAmBd,EAA0C,CAClG,MAAMoD,EAAS8uB,GAAiBlyB,EAAO,WAAW,CAAC,EACnD,GAAIoD,EAAO,OAAQ,OAEnB,MAAMonB,EAAQ1pB,EAAK,iBAA8B,kBAAkB,EACnE,GAAI0pB,EAAM,SAAW,EAAG,OAExB,MAAM1oB,EAAOwH,EAAI,QACX1C,EAAWtE,EAAStC,EAAO,aAAa,EAAG8B,EAAK,QAAQ,EACxD+E,EAAO7G,EAAO,SAAS,GAAK8B,EAAK,KACjCshB,EAAWhI,GACfpb,EAAO,aAAa,EACpB8B,EAAK,SACL,gBAAiB9B,CAAA,EAIbmyB,EAAkB3H,EAAM,CAAC,EAAE,cAC3B4H,EAAMD,GACR,WAAW,OAAO,iBAAiBA,CAAe,EAAE,WAAa,GAAG,GAAK,EAGvEE,EAAMrB,GAASlwB,EAAM,CAAE,OAAQsC,EAAO,SAAU,EAEhD1G,EAAO4M,EAAI,KAAK,KAUtB,IAAIgpB,EAAkB,GACtB,MAAMC,EAAe,CAAC5I,EAAe7gB,IAAwB,CAC3D,GAAIwpB,EAAiB,CACnBA,EAAkB,GAClB51B,EAAK,YAAY,EAAG,IAAM21B,EAAI,SAAS1I,EAAM7gB,CAAK,CAAC,EACnD,MACF,CACAupB,EAAI,SAAS1I,EAAM7gB,CAAK,CAC1B,EAIA,IAAI8a,EAAyC,KAW7C,MAAM4O,EAAgC,IAAY,CAC3C5O,IACDR,EAAS,YACKtiB,EAAK,QAAQ,QAAQ,GAAK,CAAC,OAAO,WAAW,eAAe,EAAE,SAChE8iB,EAAY,MAAA,EAI9B,EAGM8H,GADctoB,EAAO,SAAWspB,GAAcoC,IACbxlB,EAAI,KAAMkhB,EAAO,CACtD,MAAO5jB,EACP,OAAQ,GACR,OAAQ,GACR,aAAcwrB,EACd,OAAQhvB,EAAO,SACf,UAAWA,EAAO,YAClB,SAAUmvB,EACV,YAAa,IAAM,CACjB3O,GAAa,kBAAkB,EAAI,EACnCA,GAAa,KAAA,CACf,EACA,UAAY6O,GAAe,CAKpBA,IACH7O,GAAa,kBAAkB,EAAK,EACpC4O,EAAA,EAEJ,EACA,gBAAiB,IAAM,CAGrB5O,GAAa,kBAAkB,EAAK,EACpC4O,EAAA,CACF,CAAA,CACD,EAEKvS,EAA8B,CAAA,EAGpC,GAAImD,EAAS,QAAS,CAGpB,MAAMuI,EAAUvoB,EAAO,SACnB,IAAY,CACNsoB,EAAO,WAAa2G,EAAI,MAAQ,EAAG3G,EAAO,QAAQ,EAAG,CAAE,SAAA9kB,EAAU,KAAAC,CAAA,CAAM,EACtE6kB,EAAO,KAAK,CAAE,SAAA9kB,EAAU,KAAAC,EAAM,CACrC,EACA,OACJ+c,EAAc5E,GAAc1V,EAAI,KAAMxI,EAAM4qB,EAAQ,CAClD,SAAUtI,EAAS,SACnB,SAAAxc,EACA,KAAAC,EACA,WAAYuc,EAAS,WACrB,GAAIuI,EAAU,CAAE,QAAAA,GAAY,CAAA,CAAC,CAC9B,EACD1L,EAAS,KAAK,IAAM2D,GAAa,QAAA,CAAS,CAC5C,CAEA,MAAM8O,EAAiB,IAAY,CAC7B9O,GAAalnB,EAAK,YAAY,GAAK81B,CAA6B,CACtE,EAEMG,EAAc,CAClB,KAAM,IAAM,CACV/O,GAAa,KAAA,EACb8H,EAAO,KAAK,CAAE,SAAA9kB,EAAU,KAAAC,CAAA,CAAM,EAC9B6rB,EAAA,CACF,EACA,SAAU,IAAM,CACd9O,GAAa,KAAA,EACb8H,EAAO,SAAS,CAAE,SAAA9kB,EAAU,KAAAC,CAAA,CAAM,EAClC6rB,EAAA,CACF,EACA,QAAU7sB,GAAmB,CAC3B+d,GAAa,KAAA,EACb8H,EAAO,QAAQ7lB,EAAQ,CAAE,SAAAe,EAAU,KAAAC,EAAM,EACzC6rB,EAAA,CACF,EACA,QAAS,IAAMhH,EAAO,QAAA,CAAQ,EAGhCzL,EAAS,KAAKoS,EAAI,qBAAqBM,CAAW,CAAC,EAEnD1S,EAAS,KACPM,GAAezf,EAAMuxB,EAAI,MAAO,CAC9B,KAAMM,EAAY,KAClB,SAAUA,EAAY,SACtB,QAASA,EAAY,OAAA,CACtB,CAAA,EAmBH,MAAMC,EAAY,IAAYlH,EAAO,QAAQ,EAAI,EACjD,OAAAzL,EAAS,KAAK3W,EAAI,SAASspB,EAAW,GAAG,CAAC,EAC1C3S,EAAS,KAAKqL,GAAYxqB,EAAM8xB,CAAS,CAAC,EAOnC,IAAM,CACX,UAAWntB,KAAMwa,EAAUxa,EAAA,EAC3BimB,EAAO,eAAA,EACPA,EAAO,WAAW,KAAA,EAClBA,EAAO,KAAA,CACT,CACF,sEAEqC,CACnC,KAAM,SACN,KAAKpiB,EAAiC,CACpC,OAAAI,GAAgBJ,EAAK,YAAaE,EAAQ,EACnC,IAAM,CAAC,CAChB,CACF,yCC1NMqpB,GAAoB,GAsB1B,SAASC,GAAeC,EAA4B,CAClD,OAAOlwB,GAAoBkwB,CAAI,CACjC,CAEO,SAAS/W,GAA0Bvc,EAA6C,CACrF,MAAM/C,EAAO+C,EAAW,KA6FxB,MAAO,CAAE,mBA3FkB,CAAC0L,EAAuB6nB,IAAuC,CACxF,UAAWhnB,KAAKb,EAQda,EAAE,KAAK,MAAM,WAAa,SAC1BA,EAAE,KAAK,MAAM,cAAgB,OACxB8mB,GAAe9mB,EAAE,IAAI,GACxBtP,EAAK,IAAIsP,EAAE,KAAM,CAAE,UAAW,EAAG,EAGjCgnB,GAAUt2B,EAAK,IAAIs2B,EAAU,CAAE,UAAW,EAAG,CACnD,EA2E6B,KAzEhB,CAAC5nB,EAAmB4nB,EAA8BC,IAA+B,CAG5F7nB,EAAM,KAAK,MAAM,WAAa,UAC9BA,EAAM,KAAK,MAAM,cAAgB,GAC5B0nB,GAAe1nB,EAAM,IAAI,GAC5B1O,EAAK,OACH0O,EAAM,KACN,CAAE,UAAW,CAAA,EACb,CAAE,UAAW,EAAG,SAAU6nB,EAAc,KAAM,YAAA,CAAa,EAG3DD,IACFt2B,EAAK,aAAas2B,CAAQ,EAC1Bt2B,EAAK,OACHs2B,EACA,CAAE,UAAW,CAAA,EACb,CAAE,UAAW,EAAG,SAAUH,GAAmB,KAAM,YAAA,CAAa,GAGpEjtB,EAAYwF,EAAM,KAAM,cAAc,CACxC,EAoDmC,MAlDrB,CACZA,EACA4nB,EACAC,EACA7W,IACS,CACTxW,EAAYwF,EAAM,KAAM,gBAAgB,EAKxC,MAAM8nB,EAAWD,EAAe1uB,GAE3BuuB,GAAe1nB,EAAM,IAAI,IAC5B1O,EAAK,aAAa0O,EAAM,IAAI,EAC5B1O,EAAK,GAAG0O,EAAM,KAAM,CAAE,UAAW,EAAG,SAAU8nB,EAAU,KAAM,WAAA,CAAa,GAI7E,MAAMC,EAAgB,KAAK,IAAI,EAAGD,EAAWL,EAAiB,EAC1DG,IACFt2B,EAAK,aAAas2B,CAAQ,EAC1Bt2B,EAAK,GAAGs2B,EAAU,CAChB,UAAW,EACX,SAAUH,GACV,KAAM,YACN,MAAOM,CAAA,CACR,GAGH,MAAMC,EAAY,KAAK,IAAIF,EAAUC,EAAgBN,EAAiB,EACtEn2B,EAAK,YAAY02B,EAAW,IAAM,CAChChoB,EAAM,KAAK,MAAM,WAAa,SAC9BA,EAAM,KAAK,MAAM,cAAgB,OACjCgR,IAAA,CACF,CAAC,CACH,EAc0C,QAZ1B,CAACjR,EAAuB6nB,IAAuC,CAC7E,UAAWhnB,KAAKb,EACdzO,EAAK,aAAasP,EAAE,IAAI,EACxBtP,EAAK,IAAIsP,EAAE,KAAM,CAAE,WAAY,qBAAsB,EACrDA,EAAE,KAAK,MAAM,cAAgB,GAE3BgnB,IACFt2B,EAAK,aAAas2B,CAAQ,EAC1Bt2B,EAAK,IAAIs2B,EAAU,CAAE,WAAY,qBAAsB,EAE3D,CAE0C,CAC5C,CC9HA,MAAMK,GAAqB,CACzB,UACA,yBACA,6CACA,yBACA,2BACA,iCACF,EAAE,KAAK,GAAG,EAEJC,GAAiB,CACrB,2GACA,yBACA,0BACF,EAAE,KAAK,GAAG,EAEV,SAASC,GAAaR,EAAkC,CACtD,OAAO,MAAM,KAAKA,EAAK,iBAA8BM,EAAkB,CAAC,EAAE,OACvEj2B,GAAO,CAACA,EAAG,aAAa,UAAU,GAAKA,EAAG,eAAiB,IAAA,CAEhE,CAEA,SAASo2B,GAAcT,EAAuC,CAC5D,OACE,MAAM,KAAKA,EAAK,iBAA8BO,EAAc,CAAC,EAAE,KAC5Dl2B,GAAO,CAACA,EAAG,aAAa,UAAU,GAAKA,EAAG,eAAiB,IAAA,GACzD,IAET,CAOO,SAASq2B,GAAUV,EAA+B,CACvD,MAAMW,EAAa1nB,GAA2B,CAC5C,GAAIA,EAAE,MAAQ,MAAO,OACrB,MAAM2nB,EAAYJ,GAAaR,CAAI,EACnC,GAAIY,EAAU,SAAW,EAAG,CAC1B3nB,EAAE,eAAA,EACF+mB,EAAK,MAAM,CAAE,cAAe,EAAA,CAAM,EAClC,MACF,CACA,MAAMa,EAAQD,EAAU,CAAC,EACnB50B,EAAO40B,EAAUA,EAAU,OAAS,CAAC,EACrC3P,EAAS,SAAS,cACpBhY,EAAE,UACAgY,IAAW4P,GAAS,CAACb,EAAK,SAAS/O,CAAM,KAC3ChY,EAAE,eAAA,EACFjN,EAAK,MAAA,GAGHilB,IAAWjlB,IACbiN,EAAE,eAAA,EACF4nB,EAAM,MAAA,EAGZ,EACA,OAAAb,EAAK,iBAAiB,UAAWW,CAAS,EACnC,IAAMX,EAAK,oBAAoB,UAAWW,CAAS,CAC5D,CAcO,SAASG,GAAWd,EAAyB,CAClD,MAAMe,EAAaN,GAAcT,CAAI,EACrC,GAAIe,EAAY,CACdA,EAAW,MAAA,EACX,MACF,CACKf,EAAK,aAAa,UAAU,GAAGA,EAAK,aAAa,WAAY,IAAI,EACtEA,EAAK,MAAM,CAAE,cAAe,EAAA,CAAM,CACpC,CAEA,MAAMgB,GAAsB,GAa5B,SAASC,GAAqBjB,EAAkC,CAC9D,GAAI,OAAO,SAAa,IAAa,OAAO,KAU5C,MAAMa,EATS,SAAS,iBAAiBb,EAAM,WAAW,UAAW,CACnE,WAAWkB,EAAc,CACvB,GAAI,CAACA,EAAK,aAAe,CAACA,EAAK,YAAY,KAAA,EAAQ,OAAO,WAAW,cACrE,QAAS72B,EAAK62B,EAAK,cAAe72B,GAAMA,IAAO21B,EAAM31B,EAAKA,EAAG,cAC3D,GAAIA,EAAG,aAAa,aAAa,IAAM,cAAe,WAAW,cAEnE,OAAO,WAAW,aACpB,CAAA,CACD,EACoB,SAAA,EACrB,GAAI,CAACw2B,EAAO,OAAO,KAEnB,MAAM1d,IADQ0d,EAAM,eAAiBb,GACjB,aAAe,IAAI,QAAQ,OAAQ,GAAG,EAAE,KAAA,EAC5D,GAAI,CAAC7c,EAAM,OAAO,KAClB,GAAIA,EAAK,QAAU6d,GAAqB,OAAO7d,EAC/C,MAAM2E,EAAQ3E,EAAK,MAAM,EAAG6d,EAAmB,EACzCG,EAAMrZ,EAAM,YAAY,GAAG,EACjC,OAAQqZ,EAAMH,GAAsB,EAAIlZ,EAAM,MAAM,EAAGqZ,CAAG,EAAIrZ,GAAO,KAAA,CACvE,CASO,SAASsZ,GAAqBpB,EAAmBv2B,EAAsB,CAI5E,GAHKu2B,EAAK,aAAa,MAAM,GAAGA,EAAK,aAAa,OAAQ,QAAQ,EAC7DA,EAAK,aAAa,YAAY,GAAGA,EAAK,aAAa,aAAc,MAAM,EAExE,CAACA,EAAK,aAAa,YAAY,GAAK,CAACA,EAAK,aAAa,iBAAiB,EAAG,CAC7E,MAAMl2B,EAAOm3B,GAAqBjB,CAAI,EAClCl2B,EACFk2B,EAAK,aAAa,aAAcl2B,CAAI,EAC3BL,GACT,QAAQ,KACN,qKAAA,CAGN,CACF,CAOO,SAAS43B,GAAmBjrB,EAA0B,CAC3D,GAAI,SAAO,SAAa,KACxB,UAAWzB,KAAW,SAAS,iBAA8B,mBAAmB,EAAG,CACjF,MAAM7K,EAAO6K,EAAQ,aAAa,iBAAiB,EAC/C7K,GAAQsM,EAAM,IAAItM,CAAI,GAAK,CAAC6K,EAAQ,aAAa,eAAe,GAClEA,EAAQ,aAAa,gBAAiB,QAAQ,CAElD,CACF,CAKO,SAAS2sB,GAAUC,EAA+B,CACvD,MAAMZ,EAAa1nB,GAA2B,CACxCA,EAAE,MAAQ,UAAUsoB,EAAA,CAC1B,EACA,gBAAS,iBAAiB,UAAWZ,CAAS,EACvC,IAAM,SAAS,oBAAoB,UAAWA,CAAS,CAChE,CC9JA,MAAMa,GAAa,kBACnB,IAAIC,GAAY,EAET,SAASC,IAAuB,CAErC,GADAD,IAAa,EACT,EAAAA,GAAY,GAChB,IAAI,OAAO,OAAW,KAAe,OAAO,MAC1C,GAAI,CACF,OAAO,MAAM,KAAA,CACf,MAAQ,CAER,CAEE,OAAO,SAAa,KACtB,SAAS,KAAK,UAAU,IAAID,EAAU,EAE1C,CAEO,SAASG,IAAyB,CACvC,GAAIF,KAAc,IAClBA,IAAa,EACT,EAAAA,GAAY,IAChB,IAAI,OAAO,OAAW,KAAe,OAAO,MAC1C,GAAI,CACF,OAAO,MAAM,MAAA,CACf,MAAQ,CAER,CAEE,OAAO,SAAa,KACtB,SAAS,KAAK,UAAU,OAAOD,EAAU,EAE7C,CAEO,SAASI,IAAwB,CACtC,GAAIH,KAAc,EAElB,IADAA,GAAY,EACR,OAAO,OAAW,KAAe,OAAO,MAC1C,GAAI,CACF,OAAO,MAAM,MAAA,CACf,MAAQ,CAER,CAEE,OAAO,SAAa,KACtB,SAAS,KAAK,UAAU,OAAOD,EAAU,EAE7C,CCpDO,MAAMK,GAA0B,wBAkBhC,SAASC,GAAiBjb,EAAgC,CAC/D,MAAMkb,EAAQ,MAAM,KAAKlb,EAAM,iBAA8B,iBAAiB,CAAC,EACzEzO,EAAwB,CAAA,EACxB4pB,MAAa,IACnB,UAAWhC,KAAQ+B,EAAO,CACxB,MAAMj4B,EAAOk2B,EAAK,aAAa,eAAe,EAC9C,GAAI,CAACl2B,EAAM,SACX,MAAMuO,EAAoB,CAAE,KAAAvO,EAAM,KAAAk2B,CAAA,EAClC5nB,EAAQ,KAAKC,CAAK,EAClB2pB,EAAO,IAAIl4B,EAAMuO,CAAK,CACxB,CAGA,MAAM4nB,EAAWpZ,EAAM,cAA2B,qBAAqB,EAEjEiJ,EAAYzX,GAChBA,EAAM,KAAK,aAAa9G,EAAiB,IAAM,SAiBjD,MAAO,CAAE,MAAAsV,EAAO,QAAAzO,EAAS,OAAA4pB,EAAQ,SAAA/B,EAAU,SAAAnQ,EAAU,UAfnC,CAACzX,EAAmB0X,IAA0C,CAC9E1X,EAAM,KAAK,aAAa9G,GAAmBwe,CAAM,CACnD,EAagE,eAXxCA,GAA0C,CAChElJ,EAAM,aAAagb,GAAyB9R,CAAM,EAKlDlJ,EAAM,MAAM,WAAakJ,IAAW,SAAW,UAAY,QAC7D,EAIgF,YAF5D,IAAyB3X,EAAQ,KAAK0X,CAAQ,GAAK,IAES,CAClF,CCpCA,SAASmS,GAAch1B,EAAgBuC,EAA0B,CAC/D,MAAMiP,EAAIxR,EAAO,aAAa,EAC9B,GAAIwR,IAAM,OAAW,OAAOjP,EAC5B,MAAMvF,EAAI,WAAWwU,CAAC,EACtB,OAAO,OAAO,SAASxU,CAAC,EAAIA,EAAIuF,CAClC,CAEA,SAASiH,GACPF,EACAsQ,EACA5Z,EAC0B,CAC1B,MAAM8M,EAAQ+nB,GAAiBjb,CAAK,EACpC,GAAI9M,EAAM,QAAQ,SAAW,EAAG,OAQ5B,OAAO,SAAa,KAAe8M,EAAM,gBAAkB,SAAS,MACtE,SAAS,KAAK,YAAYA,CAAK,EAGjC,MAAM9X,EAAOwH,EAAI,QACX2rB,EAAgBD,GAAch1B,EAAQ8B,EAAK,QAAQ,EACnD0J,EAAYwQ,GAA0B1S,EAAI,IAAI,EAC9C5M,EAAO4M,EAAI,KAAK,KAChB2W,EAA8B,CAAA,EAG9BtB,EAAevT,GAA8B,CACjD,MAAMpN,EAAIoN,EAAM,KAAK,aAAa,aAAa,EAC/C,GAAIpN,EAAG,CACL,MAAMhB,EAAI,WAAWgB,CAAC,EACtB,GAAI,OAAO,SAAShB,CAAC,EAAG,OAAOA,CACjC,CACA,OAAOi4B,CACT,EAEAnoB,EAAM,eAAe,YAAY,EACjC,UAAW1B,KAAS0B,EAAM,QAASA,EAAM,UAAU1B,EAAO,YAAY,EACtEI,EAAU,mBAAmBsB,EAAM,QAASA,EAAM,QAAQ,EAK1D,MAAMtQ,EAAQ8M,EAAI,QAAQ,OAAS,GACnC,UAAW8B,KAAS0B,EAAM,QAASqnB,GAAqB/oB,EAAM,KAAM5O,CAAK,EACzE43B,GAAmB,IAAI,IAAItnB,EAAM,QAAQ,IAAKd,GAAMA,EAAE,IAAI,CAAC,CAAC,EAE5D,IAAIkpB,EAAkC,KAClCC,EAAiC,KACjCC,EAAgD,KAEpD,MAAM1R,EAActY,GAA4B,CAC9C,GAAI,CAAC0B,EAAM,SAAS1B,CAAK,EAAG,OAC5B8pB,IAAA,EACAA,EAAa,KACbC,IAAA,EACAA,EAAY,KACZC,GAAkB,KAAA,EAClBA,EAAmB,KAEnB,MAAMnC,EAAetU,EAAYvT,CAAK,EACtCI,EAAU,MAAMJ,EAAO0B,EAAM,SAAUmmB,EAAc,IAAM,CACzDnmB,EAAM,UAAU1B,EAAO,YAAY,EAC9B0B,EAAM,YAAA,GAAeA,EAAM,eAAe,YAAY,EAC3D4nB,GAAA,CACF,CAAC,CACH,EAEMlR,EAAapY,GAA4B,CAC7C,GAAI0B,EAAM,SAAS1B,CAAK,EAAG,OAK3B,MAAMoS,EAAO1Q,EAAM,YAAA,EACf0Q,GAAQA,IAASpS,GAAOsY,EAAWlG,CAAI,EAE3C1Q,EAAM,eAAe,QAAQ,EAC7BA,EAAM,UAAU1B,EAAO,QAAQ,EAC/BqpB,GAAA,EACA,MAAMxB,EAAetU,EAAYvT,CAAK,EACtCI,EAAU,KAAKJ,EAAO0B,EAAM,SAAUmmB,CAAY,EAElDiC,EAAazB,GAAUroB,EAAM,IAAI,EACjC+pB,EAAYd,GAAU,IAAM3Q,EAAWtY,CAAK,CAAC,EAE7CgqB,GAAkB,KAAA,EAClBA,EAAmB14B,EAAK,YAAYu2B,EAAc,IAAM,CACtDY,GAAWzoB,EAAM,IAAI,EACrBgqB,EAAmB,IACrB,CAAC,CACH,EAIMC,EAAcrpB,GAAmB,CACrC,MAAMnG,EAASmG,EAAE,OACjB,GAAI,CAACnG,EAAQ,OACb,MAAM6B,EAAU7B,EAAO,QAAqB,mBAAmB,EAC/D,GAAI,CAAC6B,EAAS,OACd,MAAM7K,EAAO6K,EAAQ,aAAa,iBAAiB,EACnD,GAAI,CAAC7K,EAAM,OACX,MAAMuO,EAAQ0B,EAAM,OAAO,IAAIjQ,CAAI,EAC9BuO,IACLY,EAAE,eAAA,EACFwX,EAAUpY,CAAK,EACjB,EACA,SAAS,iBAAiB,QAASiqB,CAAU,EAC7CpV,EAAS,KAAK,IAAM,SAAS,oBAAoB,QAASoV,CAAU,CAAC,EAKrE,MAAMC,EAAgBtpB,GAAmB,CACvC,MAAMnG,EAASmG,EAAE,OACjB,GAAI,CAACnG,EAAQ,OACb,MAAM0vB,EAAS1vB,EAAO,QAAqB,kBAAkB,EAC7D,GAAI,CAAC0vB,GAAU,CAAC3b,EAAM,SAAS2b,CAAM,EAAG,OACxC,MAAMvR,EAASlX,EAAM,YAAA,EAChBkX,IACLhY,EAAE,eAAA,EACF0X,EAAWM,CAAM,EACnB,EACA,OAAApK,EAAM,iBAAiB,QAAS0b,CAAY,EAC5CrV,EAAS,KAAK,IAAMrG,EAAM,oBAAoB,QAAS0b,CAAY,CAAC,EAE7D,IAAM,CACX,UAAW7vB,KAAMwa,EAAUxa,EAAA,EAC3ByvB,IAAA,EACAC,IAAA,EACAC,GAAkB,KAAA,EACdtoB,EAAM,eAER4nB,GAAA,EAEFlpB,EAAU,QAAQsB,EAAM,QAASA,EAAM,QAAQ,EAC/CA,EAAM,MAAM,gBAAgB8nB,EAAuB,EACnD9nB,EAAM,MAAM,MAAM,eAAe,YAAY,EAC7C,UAAW1B,KAAS0B,EAAM,QAAS1B,EAAM,KAAK,gBAAgB9G,EAAiB,CACjF,CACF,sEAEoC,CAClC,KAAM,QACN,KAAKgF,EAAiC,CACpC,OAAAI,GAAgBJ,EAAK,iBAAkBE,EAAQ,EACxC,IAAM,CAGXmrB,GAAA,CACF,CACF,CACF,yCCxKMa,OAAuC,IAAI,CAC/C,MACA,WACA,aACA,MACA,SACA,OACA,OACF,CAAC,EAEM,SAASC,GAAmBryB,EAAyC,CAC1E,UAAW,KAAKA,EACd,GAAIoyB,GAAY,IAAI,CAAC,EAAG,OAAO,EAEjC,MAAO,KACT,CAEO,SAASE,GAAYrgB,EAA2B,CACrD,OAAIA,IAAS,OAASA,IAAS,WAAmB,SAC9CA,IAAS,aAAqB,OAC3BA,CACT,CAEO,SAASsgB,GAAWC,EAAmBx4B,EAAaiY,EAA2B,CACpF,GAAIA,IAAS,OAASA,IAAS,UAAYA,IAAS,QAAUA,IAAS,QAAS,OAAOA,EAEvF,MAAMlT,EAAO/E,EAAG,sBAAA,EACVyO,EAAI+pB,EAAM,QAAUzzB,EAAK,KACzB0zB,EAAID,EAAM,QAAUzzB,EAAK,IACzB1F,EAAI0F,EAAK,MACT2zB,EAAI3zB,EAAK,OAEf,GAAIkT,IAAS,WAAY,OAAOwgB,EAAIC,EAAI,EAAI,MAAQ,SACpD,GAAIzgB,IAAS,aAAc,OAAOxJ,EAAIpP,EAAI,EAAI,OAAS,QAGvD,IAAIs5B,EAAa,MACbxI,EAAMsI,EACV,OAAIC,EAAID,EAAItI,IACVwI,EAAO,SACPxI,EAAMuI,EAAID,GAERhqB,EAAI0hB,IACNwI,EAAO,OACPxI,EAAM1hB,GAEJpP,EAAIoP,EAAI0hB,IACVwI,EAAO,SAEFA,CACT,CC3CO,SAASC,GAAYC,EAAgC,CAC1D,MAAMC,EAAuB,CAAA,EACvBC,EAAW,iBAAiBF,CAAI,EAEtC,OAAIE,EAAS,WAAa,WACxBD,EAAQ,SAAWD,EAAK,MAAM,SAC9BA,EAAK,MAAM,SAAW,YAEpBE,EAAS,WAAa,UAAYA,EAAS,WAAa,SAC1DD,EAAQ,SAAWD,EAAK,MAAM,SAC9BA,EAAK,MAAM,SAAW,UAEpBE,EAAS,YAAc,SACzBD,EAAQ,UAAYD,EAAK,MAAM,UAC/BA,EAAK,MAAM,UAAY,WAElBC,CACT,CAEO,SAASE,GAAYH,EAAmBC,EAA4B,CACrEA,EAAQ,WAAa,SAAWD,EAAK,MAAM,SAAWC,EAAQ,UAC9DA,EAAQ,WAAa,SAAWD,EAAK,MAAM,SAAWC,EAAQ,UAC9DA,EAAQ,YAAc,SAAWD,EAAK,MAAM,UAAYC,EAAQ,UACtE,CAWO,SAASG,GAAiBJ,EAAgC,CAC/D,MAAMC,EAAuB,CAAA,EACvBC,EAAW,iBAAiBF,CAAI,EACtC,OAAIE,EAAS,WAAa,WACxBD,EAAQ,SAAWD,EAAK,MAAM,SAC9BA,EAAK,MAAM,SAAW,YAEpBE,EAAS,YAAc,SACzBD,EAAQ,UAAYD,EAAK,MAAM,UAC/BA,EAAK,MAAM,UAAY,WAElBC,CACT,CCnDA,MAAMI,GAA0D,CAC9D,IAAK,CAAE,EAAG,EAAG,EAAG,IAAA,EAChB,OAAQ,CAAE,EAAG,EAAG,EAAG,GAAA,EACnB,KAAM,CAAE,EAAG,KAAM,EAAG,CAAA,EACpB,MAAO,CAAE,EAAG,IAAK,EAAG,CAAA,CACtB,EAUO,SAASC,GACdN,EACAvuB,EACAhL,EACA85B,EACY,CACZ,MAAMN,EAAUF,GAAYC,CAAI,EAE1BQ,EAAK,SAAS,cAAc,MAAM,EACxCA,EAAG,aAAa,cAAe,OAAO,EACtCA,EAAG,aAAa,cAAe,MAAM,EAGrCA,EAAG,MAAM,WAAaD,EAAS,MAM/BP,EAAK,YAAYQ,CAAE,EAEnB,MAAM9W,EAAQ2W,GAAgBZ,GAAYc,EAAS,IAAI,CAAC,EACxD95B,EAAK,KAAK,IAAI+5B,EAAI,CAAE,SAAU9W,EAAM,EAAG,SAAUA,EAAM,CAAA,CAAG,EAE1D,IAAIqE,EAA2B,KAQ/B,MAAM0S,EAAWd,GAA4B,CAC3C,MAAMvzB,EAAIi0B,GAAgBX,GAAWC,EAAOluB,EAAS8uB,EAAS,IAAI,CAAC,EACnExS,GAAQ,KAAA,EACRA,EAAStnB,EAAK,KAAK,OACjB+5B,EACA,CAAE,SAAUp0B,EAAE,EAAG,SAAUA,EAAE,CAAA,EAC7B,CACE,SAAU,EACV,SAAU,EACV,SAAUm0B,EAAS,SACnB,KAAMA,EAAS,KACf,MAAOA,EAAS,MAChB,UAAW,EAAA,CACb,CAEJ,EAEMG,EAAWf,GAA4B,CAC3C,MAAMvzB,EAAIi0B,GAAgBX,GAAWC,EAAOluB,EAAS8uB,EAAS,IAAI,CAAC,EACnExS,GAAQ,KAAA,EACRA,EAAStnB,EAAK,KAAK,GAAG+5B,EAAI,CACxB,SAAUp0B,EAAE,EACZ,SAAUA,EAAE,EACZ,SAAUm0B,EAAS,SACnB,KAAMA,EAAS,KACf,UAAW,EAAA,CACZ,CACH,EAEA,OAAA9uB,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC9ChvB,EAAQ,iBAAiB,aAAcivB,CAAO,EAEvC,IAAM,CACXjvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EACjDhvB,EAAQ,oBAAoB,aAAcivB,CAAO,EACjD3S,GAAQ,KAAA,EACRyS,EAAG,OAAA,EACHL,GAAYH,EAAMC,CAAO,CAC3B,CACF,CAMA,MAAMU,GAAS,6BAWTC,GAAiE,CACrE,IAAK,CACH,MAAO,6CACP,IAAK,kDAAA,EAEP,OAAQ,CACN,MAAO,qDACP,IAAK,gDAAA,EAEP,KAAM,CACJ,MAAO,2CACP,IAAK,gDAAA,EAEP,MAAO,CACL,MAAO,uDACP,IAAK,kDAAA,CAET,EAkBA,SAASC,GAAiBf,EAAYzW,EAA0B,CAC9D,MAAM2B,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG3B,CAAQ,CAAC,EACrCyX,EAAQ,GAAK,KAAK,IAAI,KAAK,GAAK9V,CAAC,EAEvC,GAAI8U,IAAS,MAAO,CAClB,MAAMiB,EAAQ,KAAO,EAAI/V,GACnBgW,EAAQD,EAAQD,EACtB,MAAO,eAAeC,CAAK,SAASC,CAAK,QAAQD,CAAK,kBACxD,CACA,GAAIjB,IAAS,SAAU,CACrB,MAAMiB,EAAQ,IAAM/V,EACdgW,EAAQD,EAAQD,EACtB,MAAO,eAAeC,CAAK,SAASC,CAAK,QAAQD,CAAK,sBACxD,CACA,GAAIjB,IAAS,OAAQ,CACnB,MAAMmB,EAAQ,KAAO,EAAIjW,GACnBkW,EAAQD,EAAQH,EACtB,MAAO,WAAWG,CAAK,QAAQC,CAAK,OAAOD,CAAK,sBAClD,CAEA,MAAMA,EAAQ,IAAMjW,EACdkW,EAAQD,EAAQH,EACtB,MAAO,aAAaG,CAAK,QAAQC,CAAK,OAAOD,CAAK,0BACpD,CAUO,SAASE,GACdnB,EACAvuB,EACAhL,EACA85B,EACY,CACZ,MAAMN,EAAUF,GAAYC,CAAI,EAE1BoB,EAAM,SAAS,gBAAgBT,GAAQ,KAAK,EAClDS,EAAI,aAAa,cAAe,OAAO,EACvCA,EAAI,aAAa,cAAe,MAAM,EACtCA,EAAI,aAAa,UAAW,aAAa,EACzCA,EAAI,aAAa,sBAAuB,MAAM,EAI9CA,EAAI,MAAM,KAAOb,EAAS,MAE1B,MAAMloB,EAAO,SAAS,gBAAgBsoB,GAAQ,MAAM,EACpDtoB,EAAK,aAAa,IAAKuoB,GAAiBnB,GAAYc,EAAS,IAAI,CAAC,EAAE,KAAK,EACzEa,EAAI,YAAY/oB,CAAI,EAGpB2nB,EAAK,YAAYoB,CAAG,EAEpB,IAAIrT,EAA2B,KAI/B,MAAM0S,EAAWd,GAA4B,CAC3C,MAAMG,EAAOJ,GAAWC,EAAOluB,EAAS8uB,EAAS,IAAI,EAC/CvV,EAAI4V,GAAiBd,CAAI,EAC/B/R,GAAQ,KAAA,EACRA,EAAStnB,EAAK,KAAK,OACjB4R,EACA,CAAE,KAAM,CAAE,EAAG2S,EAAE,MAAM,EACrB,CACE,KAAM,CAAE,EAAGA,EAAE,GAAA,EACb,SAAUuV,EAAS,SACnB,KAAMA,EAAS,KACf,MAAOA,EAAS,MAChB,UAAW,EAAA,CACb,CAEJ,EAEMG,EAAWf,GAA4B,CAC3C,MAAMG,EAAOJ,GAAWC,EAAOluB,EAAS8uB,EAAS,IAAI,EACrDxS,GAAQ,KAAA,EACR,MAAMlX,EAAQ,CAAE,EAAG,CAAA,EACnBkX,EAAStnB,EAAK,KAAK,GAAGoQ,EAAO,CAC3B,EAAG,EACH,SAAU0pB,EAAS,SACnB,KAAMA,EAAS,KACf,SAAU,IAAM,CACdloB,EAAK,aAAa,IAAKwoB,GAAiBf,EAAMjpB,EAAM,CAAC,CAAC,CACxD,EACA,UAAW,EAAA,CACZ,CACH,EAEA,OAAApF,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC9ChvB,EAAQ,iBAAiB,aAAcivB,CAAO,EAEvC,IAAM,CACXjvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EACjDhvB,EAAQ,oBAAoB,aAAcivB,CAAO,EACjD3S,GAAQ,KAAA,EACRqT,EAAI,OAAA,EACJjB,GAAYH,EAAMC,CAAO,CAC3B,CACF,CAgBO,MAAMoB,OAA2C,IAAmB,CACzE,KACA,OACA,OACA,QACA,WACA,UACA,aACA,WACF,CAAC,EAOKC,GAA4C,CAChD,MAAO,CAAE,YAAa,CAAE,KAAM,QAAS,IAAK,GAAA,EAAO,OAAQ,CAAE,SAAU,IAAI,EAC3E,KAAM,CAAE,YAAa,CAAE,KAAM,OAAQ,IAAK,GAAA,EAAO,OAAQ,CAAE,SAAU,KAAK,EAC1E,GAAI,CAAE,YAAa,CAAE,KAAM,IAAK,IAAK,MAAA,EAAU,OAAQ,CAAE,SAAU,KAAK,EACxE,KAAM,CAAE,YAAa,CAAE,KAAM,IAAK,IAAK,OAAA,EAAW,OAAQ,CAAE,SAAU,IAAI,EAC1E,WAAY,CACV,YAAa,CAAE,KAAM,QAAS,IAAK,MAAA,EACnC,OAAQ,CAAE,SAAU,IAAK,SAAU,IAAA,CAAK,EAE1C,aAAc,CACZ,YAAa,CAAE,KAAM,QAAS,IAAK,OAAA,EACnC,OAAQ,CAAE,SAAU,IAAK,SAAU,GAAA,CAAI,EAEzC,UAAW,CACT,YAAa,CAAE,KAAM,OAAQ,IAAK,MAAA,EAClC,OAAQ,CAAE,SAAU,KAAM,SAAU,IAAA,CAAK,EAE3C,YAAa,CACX,YAAa,CAAE,KAAM,OAAQ,IAAK,OAAA,EAClC,OAAQ,CAAE,SAAU,KAAM,SAAU,GAAA,CAAI,CAE5C,EA+BA,SAASC,GAAYj4B,EAAek4B,EAA4B,CAC9D,GAAIl4B,IAAU,KAAOA,IAAU,KAAM,OAAOA,EAC5C,MAAM8F,EAAQ9F,EAAM,MAAM,kBAAkB,EAC5C,OAAK8F,EACE,GAAG,WAAWA,EAAM,CAAC,CAAC,EAAIoyB,CAAU,GAAGpyB,EAAM,CAAC,CAAC,GADnC9F,CAErB,CAEA,SAASm4B,GACPC,EACAF,EACoB,CACpB,MAAMr3B,EAA0B,CAAA,EAChC,OAAIu3B,EAAO,WAAa,SAAWv3B,EAAI,SAAWu3B,EAAO,SAAWF,GAChEE,EAAO,WAAa,SAAWv3B,EAAI,SAAWu3B,EAAO,SAAWF,GAC7Dr3B,CACT,CAEO,SAASw3B,GACd3B,EACAvuB,EACAhL,EACA85B,EACY,CACZ,MAAMqB,EAAO5B,EAAK,cAAc,KAAK,EACrC,GAAI,CAAC4B,EAAM,MAAO,IAAM,CAAC,EAEzB,MAAMC,EAAMP,GAASf,EAAS,SAAS,EACjC7Y,EAASka,EAAK,WACpB,GAAI,CAACla,EAAQ,MAAO,IAAM,CAAC,EAK3B,MAAMqJ,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,aAAa,qBAAsB,EAAE,EAC1C,OAAO,OAAOA,EAAK,MAAO,CACxB,QAAS,cACT,SAAU,WACV,SAAU,SACV,cAAe,QAAA,CAChB,EACDrJ,EAAO,aAAaqJ,EAAM6Q,CAAI,EAC9B7Q,EAAK,YAAY6Q,CAAI,EAKrB,MAAME,EAAavB,EAAS,OAAS,EAAI,EACnCmB,EAASD,GAAYI,EAAI,OAAQC,CAAU,EAE3C9S,EAAuB,CAAA,EAC7B,QAAS5T,EAAI,EAAGA,GAAK0mB,EAAY1mB,IAAK,CACpC,MAAMmT,EAAQqT,EAAK,UAAU,EAAI,EACjCrT,EAAM,aAAa,cAAe,MAAM,EACxC,OAAO,OAAOA,EAAM,MAAO,CACzB,SAAU,WACV,KAAMgT,GAAYM,EAAI,YAAY,KAAMzmB,CAAC,EACzC,IAAKmmB,GAAYM,EAAI,YAAY,IAAKzmB,CAAC,CAAA,CACxC,EACGmlB,EAAS,QAAU,iBAAgBhS,EAAM,MAAM,MAAQgS,EAAS,OACpExP,EAAK,YAAYxC,CAAK,EACtBS,EAAO,KAAKT,CAAK,CACnB,CAEA,MAAM3L,EAAmBnc,EAAK,KAAK,SAAS,CAC1C,OAAQ,GACR,SAAU,CAAE,SAAU85B,EAAS,SAAU,KAAMA,EAAS,KAAM,MAAOA,EAAS,KAAA,CAAM,CACrF,EACD3d,EAAG,GAAGgf,EAAMF,EAAQ,CAAC,EACrB,QAAStmB,EAAI,EAAGA,EAAI4T,EAAO,OAAQ5T,IACjCwH,EAAG,GAAGoM,EAAO5T,CAAC,EAAGsmB,EAAQnB,EAAS,UAAYnlB,EAAI,EAAE,EAGtD,MAAMqlB,EAAU,IAAY,CAC1B7d,EAAG,UAAU,CAAC,EAAE,KAAK,CAAC,CACxB,EACM8d,EAAU,IAAY,CAO1B9d,EAAG,UAAU,GAAG,EAAE,QAAA,CACpB,EAEA,OAAAnR,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC1CF,EAAS,SAAS9uB,EAAQ,iBAAiB,aAAcivB,CAAO,EAE7D,IAAM,CACXjvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EAC7CF,EAAS,SAAS9uB,EAAQ,oBAAoB,aAAcivB,CAAO,EACvE9d,EAAG,KAAA,EACH,UAAW2L,KAASS,EAAQT,EAAM,OAAA,EAElC7G,EAAO,aAAaka,EAAM7Q,CAAI,EAC9BA,EAAK,OAAA,EACLtqB,EAAK,KAAK,IAAIm7B,EAAM,CAAE,WAAY,YAAa,CACjD,CACF,CAiBA,SAASG,GAAmB9f,EAAgC,CAC1D,MAAMG,EAAM,SAAS,cAAc,MAAM,EACzC,OAAAA,EAAI,aAAa,qBAAsB,EAAE,EACzCA,EAAI,aAAa,cAAe,MAAM,EAIlCH,IAAU,iBAAgBG,EAAI,MAAM,gBAAkBH,GACnDG,CACT,CAUA,SAAS4f,GACPhC,EACAvuB,EACAhL,EACA85B,EACY,CACZ,MAAMN,EAAUG,GAAiBJ,CAAI,EAC/B5d,EAAM2f,GAAmBxB,EAAS,KAAK,EAC7CP,EAAK,YAAY5d,CAAG,EACpB3b,EAAK,KAAK,IAAI2b,EAAK,CAAE,OAAQ,EAAG,gBAAiB,cAAe,EAEhE,IAAI2L,EAA8B,KAClC,MAAMkU,EAAO1B,EAAS,SAAW,EAE3BE,EAAU,IAAY,CACtB1S,IACJA,EAAStnB,EAAK,KACX,SAAS,CAAE,MAAO85B,EAAS,MAAO,WAAY,IAAOxS,EAAS,IAAA,CAAO,EACrE,IAAI3L,EAAK,CAAE,gBAAiB,eAAgB,EAC5C,GAAGA,EAAK,CAAE,OAAQ,EAAG,SAAU6f,EAAM,KAAM1B,EAAS,IAAA,CAAM,EAC1D,IAAIne,EAAK,CAAE,gBAAiB,aAAA,CAAe,EAC3C,GAAGA,EAAK,CAAE,OAAQ,EAAG,SAAU6f,EAAM,KAAM1B,EAAS,KAAM,EAC/D,EAEA,OAAA9uB,EAAQ,iBAAiB,aAAcgvB,CAAO,EAEvC,IAAM,CACXhvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EACjD1S,GAAQ,KAAA,EACR3L,EAAI,OAAA,EACJ+d,GAAYH,EAAMC,CAAO,CAC3B,CACF,CASA,SAASiC,GACPlC,EACAvuB,EACAhL,EACA85B,EACY,CAGZ,MAAMN,EAAUG,GAAiBJ,CAAI,EAC/B5d,EAAM2f,GAAmBxB,EAAS,KAAK,EAC7CP,EAAK,YAAY5d,CAAG,EACpB3b,EAAK,KAAK,IAAI2b,EAAK,CAAE,OAAQ,EAAG,gBAAiB,cAAe,EAEhE,IAAI+f,EAA6B,KAC7BC,EAA8B,KAC9BC,EAAe,GACfC,EAAe,GAEnB,MAAMC,EAAQ,IAAY,CACxBJ,EAAW17B,EAAK,KAAK,OACnB2b,EACA,CAAE,OAAQ,EAAG,gBAAiB,aAAA,EAC9B,CACE,OAAQ,EACR,SAAUme,EAAS,SACnB,KAAMA,EAAS,KACf,MAAOA,EAAS,MAChB,WAAY,IAAM,CAChB4B,EAAW,KACPE,IACFA,EAAe,GACfG,EAAA,EAEJ,CAAA,CACF,CAEJ,EAEMA,EAAS,IAAY,CACzBJ,EAAY37B,EAAK,KAAK,OACpB2b,EACA,CAAE,gBAAiB,cAAA,EACnB,CACE,OAAQ,EACR,SAAUme,EAAS,SACnB,KAAMA,EAAS,KACf,WAAY,IAAM,CAChB6B,EAAY,KACRE,IACFA,EAAe,GACfC,EAAA,EAEJ,CAAA,CACF,CAEJ,EAEM9B,EAAU,IAAY,CAC1B,GAAI0B,EAAU,CAGZE,EAAe,GACf,MACF,CACA,GAAID,EAAW,CAIbE,EAAe,GACfD,EAAe,GACf,MAAMI,EAAgBlC,EAAS,UAAY,EAAI6B,EAAU,YACzDA,EAAU,UAAU,KAAK,IAAI,EAAGK,EAAgB,EAAc,CAAC,EAC/D,MACF,CACAJ,EAAe,GACfE,EAAA,CACF,EAEM7B,EAAU,IAAY,CAC1B,GAAIyB,EAAU,CACZE,EAAe,GACf,MACF,CACA,GAAID,EAAW,CAGbE,EAAe,GACfF,EAAU,UAAU,CAAC,EACrB,MACF,CACAI,EAAA,CACF,EAEA,OAAA/wB,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC9ChvB,EAAQ,iBAAiB,aAAcivB,CAAO,EAEvC,IAAM,CACXjvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EACjDhvB,EAAQ,oBAAoB,aAAcivB,CAAO,EACjDyB,GAAU,KAAA,EACVC,GAAW,KAAA,EACXhgB,EAAI,OAAA,EACJ+d,GAAYH,EAAMC,CAAO,CAC3B,CACF,CAEO,SAASyC,GACd1C,EACAvuB,EACAhL,EACA85B,EACY,CACZ,OAAOA,EAAS,UAAY,YACxByB,GAAoBhC,EAAMvuB,EAAShL,EAAM85B,CAAQ,EACjD2B,GAAiBlC,EAAMvuB,EAAShL,EAAM85B,CAAQ,CACpD,CAyCA,SAASoC,GAAgB3C,EAAoC,CAC3D,MAAMC,EAA2B,CAC/B,WAAYD,EAAK,MAAM,WACvB,WAAYA,EAAK,MAAM,WACvB,cAAeA,EAAK,MAAM,cAC1B,SAAUA,EAAK,MAAM,SACrB,QAASA,EAAK,MAAM,OAAA,EAEtB,OAAAA,EAAK,MAAM,WAAa,IACxBA,EAAK,MAAM,WAAa,IACxBA,EAAK,MAAM,cAAgB,IACvB,iBAAiBA,CAAI,EAAE,UAAY,WAAUA,EAAK,MAAM,QAAU,gBAC/DC,CACT,CAEA,SAAS2C,GAAgB5C,EAAmBC,EAAgC,CAC1ED,EAAK,MAAM,WAAaC,EAAQ,WAChCD,EAAK,MAAM,WAAaC,EAAQ,WAChCD,EAAK,MAAM,cAAgBC,EAAQ,cACnCD,EAAK,MAAM,SAAWC,EAAQ,SAC9BD,EAAK,MAAM,QAAUC,EAAQ,OAC/B,CAEO,SAAS4C,GACd7C,EACAvuB,EACAhL,EACA85B,EACY,CACZ,MAAMuC,EAAeH,GAAgB3C,CAAI,EASnC+C,EAAe,iBAAiB/C,CAAI,EAAE,iBAAiB,sBAAsB,EAAE,KAAA,EACrFA,EAAK,MAAM,SAAW+C,GAAgB,oBAOtC,MAAMC,EACJ,iBAAiBhD,CAAI,EAAE,iBAAiB,uBAAuB,EAAE,QAAU,QAE7E,IAAIiD,EAAuB,CAAA,EACvBrgB,EAA0B,KAE9B,MAAMsgB,EAAgBC,GAA6B,CACjD,UAAWzf,KAAKyf,EAAKzf,EAAE,MAAM,WAAa,KAAKsf,CAAK,IAAIzC,EAAS,KAAK,EACxE,EACM6C,EAAgBD,GAA6B,CACjD,UAAWzf,KAAKyf,EAAKzf,EAAE,MAAM,WAAa,EAC5C,EAEM2f,EAAa7hB,GAKb+e,EAAS,YAAc,QAAgB/e,EAAM,MAM7C+e,EAAS,YAAc,QAAgB/e,EAAM,MAC1CA,EAAM,MAeT8hB,EAAgB,IAAY,CAChC1gB,GAAI,KAAA,EACJA,EAAKnc,EAAK,KAAK,SAAS,CAAE,OAAQ,GAAM,EACxCmc,EAAG,OACDqgB,EACA,CAAE,EAAG,CAAA,EACL,CACE,EAAG,IAAID,CAAK,GACZ,SAAUzC,EAAS,SACnB,KAAMA,EAAS,KACf,MAAOA,EAAS,MAChB,QAASA,EAAS,OAAA,CACpB,EAEGA,EAAS,SACZ3d,EAAG,cAAc,aAAc,IAAM,CACnCnc,EAAK,KAAK,IAAIw8B,EAAO,CAAE,EAAG,EAAG,CAC/B,CAAC,CAEL,EAEMzhB,EAAQjC,GAAWygB,EAAMO,EAAS,UAAW95B,EAAM,CACvD,UAAYyc,GAAa,CACvB+f,EAAQI,EAAUngB,CAAQ,EAC1BggB,EAAaD,CAAK,EAClBK,EAAA,CACF,CAAA,CACD,EAED,GADAL,EAAQI,EAAU7hB,CAAK,EACnByhB,EAAM,SAAW,EACnB,OAAAzhB,EAAM,OAAA,EACNohB,GAAgB5C,EAAM8C,CAAY,EAC3B,IAAM,CAAC,EAEhBI,EAAaD,CAAK,EAClBK,EAAA,EAEA,MAAM7C,EAAU,IAAY,CAC1B,GAAIF,EAAS,QAIX3d,EAAI,UAAU,CAAC,EAAE,KAAA,MACZ,CAGL,GAAIA,EAAI,WAAY,OACpBA,EAAI,QAAA,CACN,CACF,EAEM8d,EAAU,IAAY,CAM1B9d,EAAI,UAAU,GAAG,EAAE,QAAA,CACrB,EAEA,OAAAnR,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC1CF,EAAS,SAAS9uB,EAAQ,iBAAiB,aAAcivB,CAAO,EAE7D,IAAM,CACXjvB,EAAQ,oBAAoB,aAAcgvB,CAAO,EAC7CF,EAAS,SAAS9uB,EAAQ,oBAAoB,aAAcivB,CAAO,EACvE9d,GAAI,KAAA,EACJwgB,EAAaH,CAAK,EAClBL,GAAgB5C,EAAM8C,CAAY,EAClCthB,EAAM,OAAA,CACR,CACF,CCnyBA,SAAS+hB,GAAgBj6B,EAA4B,CACnD,MAAM6D,EAAS7D,EAAM,KAAA,EAAO,MAAM,KAAK,EAAE,OAAO,OAAO,EACvD,GAAI6D,EAAO,SAAW,EAAG,MAAO,CAAE,KAAM,KAAM,MAAO,EAAC,EACtD,MAAMD,EAAOC,EAAO,CAAC,EACfuN,EAAQvN,EAAO,MAAM,CAAC,EAE5B,GAAID,IAAS,QAAS,MAAO,CAAE,KAAM,QAAS,MAAAwN,CAAA,EAC9C,GAAIxN,IAAS,QAAS,MAAO,CAAE,KAAM,QAAS,MAAAwN,CAAA,EAC9C,GAAIxN,IAAS,YAAa,MAAO,CAAE,KAAM,YAAa,MAAAwN,CAAA,EACtD,GAAIxN,IAAS,eAAgB,MAAO,CAAE,KAAM,eAAgB,MAAAwN,CAAA,EAC5D,GAAIxN,IAAS,OAAQ,MAAO,CAAE,KAAM,OAAQ,MAAAwN,CAAA,EAC5C,GAAIxN,EAAK,WAAW,OAAO,EAAG,CAC5B,MAAMsV,EAAMtV,EAAK,MAAM,CAAc,EACrC,GAAIm0B,GAAgB,IAAI7e,CAAG,EACzB,MAAO,CAAE,KAAM,OAAQ,UAAWA,EAAsB,MAAA9H,CAAA,CAE5D,CACA,MAAO,CAAE,KAAM,KAAM,MAAAA,CAAA,CACvB,CAEA,SAASiE,GAAexX,EAAsB,CAC5C,MAAMmC,EAAQnC,EAAG,aAAa,UAAU,EACxC,GAAI,CAACmC,EAAO,MAAO,GACnB,UAAWoC,KAAQpC,EAAM,MAAM,GAAG,EAChC,GAAIi6B,GAAgB73B,EAAK,KAAA,CAAM,EAAE,KAAM,MAAO,GAEhD,UAAW5D,IAAM,CAAC,KAAM,KAAM,KAAM,IAAI,EAAG,CACzC,MAAMC,EAAIZ,EAAG,aAAa,YAAYW,CAAE,EAAE,EAC1C,GAAIC,GAAKw7B,GAAgBx7B,EAAE,MAAM,EAAE,KAAM,MAAO,EAClD,CACA,MAAO,EACT,CAEA,MAAMy7B,GAAiB,CACrB,MAAO,EAOP,aAAc,GAChB,EAQA,SAASC,IAAiD,CACxD,MAAM5B,MAAU,QAChB,GAAI,OAAO,SAAa,IAAa,OAAOA,EAC5C,MAAM51B,EAAW,SAAS,iBAA8B,oBAAoB,EAC5E,UAAWwF,KAAWxF,EAAU,CAC1BwF,EAAQ,aAAa,UAAU,GAAGowB,EAAI,IAAIpwB,EAASA,CAAO,EAC9D,UAAWgd,KAAQhd,EAAQ,iBAA8B,YAAY,EACnEowB,EAAI,IAAIpT,EAAMhd,CAAO,CAEzB,CACA,OAAOowB,CACT,CAEA,SAAStuB,GACPF,EACAqwB,EACAh6B,EACAK,EAC0B,CAC1B,MAAMT,EAAQS,EAAO,UAAU,EAC/B,GAAI,CAACT,EAAO,OACZ,MAAMsF,EAAS20B,GAAgBj6B,CAAK,EACpC,GAAI,CAACsF,EAAO,KAAM,OAElB,MAAMoxB,EAAOt2B,EAGP+H,EAAUiyB,EAAW,IAAI1D,CAAI,GAAKA,EAClCrvB,EAAWtE,EAAStC,EAAO,aAAa,EAAGsJ,EAAI,QAAQ,QAAQ,EAC/DlC,EAAQ9E,EAAStC,EAAO,UAAU,EAAGy5B,GAAe,KAAK,EACzD5yB,EAAO7G,EAAO,SAAS,GAAKsJ,EAAI,QAAQ,KACxC4O,EAAQlY,EAAO,UAAU,GAAK,eAEpC,GAAI6E,EAAO,OAAS,QAClB,OAAO0xB,GAAgBN,EAAMvuB,EAAS4B,EAAI,KAAM,CAC9C,SAAA1C,EACA,MAAAQ,EACA,KAAAP,EACA,MAAAqR,EACA,KAAMud,GAAmB5wB,EAAO,KAAK,CAAA,CACtC,EAEH,GAAIA,EAAO,OAAS,QAClB,OAAOuyB,GAAgBnB,EAAMvuB,EAAS4B,EAAI,KAAM,CAC9C,SAAA1C,EACA,MAAAQ,EACA,KAAAP,EACA,MAAAqR,EACA,KAAMud,GAAmB5wB,EAAO,KAAK,CAAA,CACtC,EAEH,GAAIA,EAAO,OAAS,QAAUA,EAAO,UAAW,CAC9C,MAAMsP,EAAY7R,EAAStC,EAAO,cAAc,EAAG,CAAC,EACpD,OAAO43B,GAAe3B,EAAMvuB,EAAS4B,EAAI,KAAM,CAC7C,UAAWzE,EAAO,UAClB,QAASA,EAAO,MAAM,SAAS,SAAS,EACxC,OAAQA,EAAO,MAAM,SAAS,QAAQ,EACtC,SAAA+B,EACA,MAAAQ,EACA,KAAAP,EACA,SAAU4yB,GAAe,aAAetlB,EACxC,MAAA+D,CAAA,CACD,CACH,CACA,GAAIrT,EAAO,OAAS,aAAeA,EAAO,OAAS,eACjD,OAAO8zB,GAAoB1C,EAAMvuB,EAAS4B,EAAI,KAAM,CAClD,SAAA1C,EACA,MAAAQ,EACA,KAAAP,EACA,MAAAqR,EACA,QAASrT,EAAO,IAAA,CACjB,EAEH,GAAIA,EAAO,OAAS,OAAQ,CAC1B,MAAMyL,EAAuB6E,GAAWnV,EAAO,UAAU,CAAC,GAAG,MAAQ,QAC/D0R,EAAcjB,GAClBzQ,EAAO,YAAY,EACnBqQ,GAAkBC,IAAc,QAAU,OAAYA,EAAWhH,EAAI,OAAO,CAAA,EAE9E,OAAOwvB,GAAe7C,EAAMvuB,EAAS4B,EAAI,KAAM,CAC7C,SAAA1C,EACA,MAAAQ,EACA,KAAAP,EACA,MAAAqR,EACA,UAAA5H,EACA,QAASS,GAAaW,EAAY,KAAMA,EAAY,KAAK,EACzD,QAAS7M,EAAO,MAAM,SAAS,SAAS,CAAA,CACzC,CACH,CAEF,sEAEoC,CAClC,KAAM,QACN,KAAKyE,EAAiC,CAEpC,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,WAAW,gBAAgB,EAAE,QACxE,MAAO,IAAM,CAAC,EAEhB,MAAMqwB,EAAaD,GAAA,EACbjwB,EAAWH,EAAI,SAAS,OAAOsL,EAAc,EACnD,UAAWjV,KAAW8J,EAAU,CAC9B,MAAM7J,EAAQzC,EAAUwC,CAAO,EAC/B2J,EAAI,WAAW,KAAK3J,EAASC,EAAO,CAAC,CAAE,OAAAI,CAAA,IACrCwJ,GAASF,EAAKqwB,EAAYh6B,EAASK,CAAM,CAAA,CAE7C,CACA,MAAO,IAAM,CAAC,CAChB,CACF,yCC9KM45B,GAAmB,EACnBC,GAAmB,KACnBC,GAAgB,KAChBC,GAAgB,KAChBC,GAAc,GAEdC,GAAyB,IAAI,IAAI,CAAC,QAAQ,CAAC,EAE3CC,GAAgB,GAChBC,GAAgB,GAChBC,GAAc,SACdC,GAAY,aACZC,GAAY,YACZC,GAAc,SACdC,GAAkB,GAYxB,SAASC,GAASr9B,EAAgC,CAChD,MAAO,CACL,SAAUA,EAAG,MAAM,SACnB,KAAMA,EAAG,MAAM,KACf,IAAKA,EAAG,MAAM,IACd,QAASA,EAAG,MAAM,QAClB,WAAYA,EAAG,MAAM,WACrB,cAAeA,EAAG,MAAM,cACxB,UAAWA,EAAG,MAAM,SAAA,CAExB,CAEA,SAAS84B,GAAQ94B,EAAiBgyB,EAA2B,CAC3DhyB,EAAG,MAAM,SAAWgyB,EAAK,SACzBhyB,EAAG,MAAM,KAAOgyB,EAAK,KACrBhyB,EAAG,MAAM,IAAMgyB,EAAK,IACpBhyB,EAAG,MAAM,QAAUgyB,EAAK,QACxBhyB,EAAG,MAAM,WAAagyB,EAAK,WAC3BhyB,EAAG,MAAM,cAAgBgyB,EAAK,cAC9BhyB,EAAG,MAAM,UAAYgyB,EAAK,SAC5B,CAEA,SAASsL,GAAoBhzB,EAA0C,CACrE,MAAM1I,EAAiC,CAAA,EACvC,UAAWpB,KAAQ,MAAM,KAAK8J,EAAQ,UAAU,EAAG,CACjD,GAAI,CAAC9J,EAAK,KAAK,WAAW,YAAY,GAAKA,EAAK,OAAS,oBAAqB,SAC9E,MAAM+D,EAAO/D,EAAK,KAAK,MAAM,EAAmB,EAC5C,CAAC+D,GAAQs4B,GAAuB,IAAIt4B,CAAI,IAC5C3C,EAAO2C,CAAI,EAAI/D,EAAK,MACtB,CACA,OAAOoB,CACT,CAEA,SAAS27B,GACPp7B,EACAq7B,EACAp+B,EACkB,CAClB,GAAI,CAAC+C,EAAO,MAAO,CAACq6B,GAAkBC,EAAgB,EACtD,MAAM/7B,EAAQyB,EAAM,KAAA,EAAO,MAAM,KAAK,EAChCs7B,EAAQC,IACRt+B,GACF,QAAQ,KACN,iDAAiDo+B,EAAa,KAAKA,CAAU,IAAM,EAAE,KAAKE,CAAM,UAAUv7B,CAAK,8BAAA,EAG5G,CAACq6B,GAAkBC,EAAgB,GAE5C,GAAI/7B,EAAM,SAAW,EAAG,OAAO+8B,EAAK,yDAAyD,EAC7F,MAAMhvB,EAAI,OAAO/N,EAAM,CAAC,CAAC,EACnB+3B,EAAI,OAAO/3B,EAAM,CAAC,CAAC,EACzB,MAAI,CAAC,OAAO,SAAS+N,CAAC,GAAK,CAAC,OAAO,SAASgqB,CAAC,EAAUgF,EAAK,+BAA+B,EACpF,CAAChvB,EAAGgqB,CAAC,CACd,CAsBA,SAASkF,GACPC,EACAC,EACAv+B,EACAw+B,EACAC,EACgB,CAChB,MAAMC,EAAaX,GAASO,CAAQ,EAC9BK,EAAYZ,GAASQ,CAAW,EAChCK,MAAgB,IAEhBzlB,EAAuB,CAC3B,GAAImlB,EACJ,MAAOC,EACP,WAAAG,EACA,UAAAC,EACA,UAAAC,EACA,eAAgB,CAAA,EAChB,cAAe,KACf,SAAU,GACV,mBAAoB,KACpB,IAAK,IAAM,CAAC,EACZ,IAAK,IAAM,CAAC,EACZ,iBAAkB,IAAM,CAAC,EACzB,cAAe,IAAM,CAAC,EACtB,aAAc,IAAM,CAAC,EACrB,WAAY,IAAM,CAAC,EACnB,WAAY,IAAM,CAAC,EACnB,QAAS,IAAM,CAAC,CAAA,EAGZC,EAAW55B,GAAiC,CAChD,MAAM65B,EAASF,EAAU,IAAI35B,CAAI,EACjC,GAAI65B,EAAQ,OAAOA,EACnB,MAAMC,EAAQT,EAAS,cAAc,cAAcr5B,CAAI,GAAG,EAC1D,OAAI85B,GAAOH,EAAU,IAAI35B,EAAM85B,CAAK,EAC7BA,CACT,EAEA,OAAA5lB,EAAK,cAAiBnO,GAA2B,CAC/C,MAAM+X,EAAOib,GAAoBhzB,CAAO,EAClCg0B,EAAW,OAAO,KAAKjc,CAAI,EAKjC,GAHE,EAAA5J,EAAK,gBAAkBnO,GACvBg0B,EAAS,SAAW,OAAO,KAAK7lB,EAAK,cAAc,EAAE,QACrD6lB,EAAS,MAAOl+B,GAAMqY,EAAK,eAAerY,CAAC,IAAMiiB,EAAKjiB,CAAC,CAAC,GAG1D,WAAWmE,KAAQ+5B,EAAU,CAC3B,MAAMC,EAAOJ,EAAQ55B,CAAI,EACzB,GAAI,CAACg6B,EAAM,SACX,MAAMp8B,EAAQkgB,EAAK9d,CAAI,EACvB,GAAIA,IAAS,SAAWg6B,EAAK,UAAY,MAAO,CAC9C,MAAMC,EAAMD,EACZC,EAAI,IAAMr8B,EACVq8B,EAAI,IAAM,EACZ,MACED,EAAK,YAAcp8B,CAEvB,CAEAsW,EAAK,eAAiB4J,EACtB5J,EAAK,cAAgBnO,EACvB,EAEAmO,EAAK,aAAe,IAAY,CAC9B,UAAWlU,KAAQ,OAAO,KAAKkU,EAAK,cAAc,EAAG,CACnD,MAAM8lB,EAAOJ,EAAQ55B,CAAI,EACpBg6B,IACDh6B,IAAS,SAAWg6B,EAAK,UAAY,OACvCA,EAAK,gBAAgB,KAAK,EAC1BA,EAAK,gBAAgB,KAAK,GAE1BA,EAAK,YAAc,GAEvB,CACA9lB,EAAK,eAAiB,CAAA,EACtBA,EAAK,cAAgB,IACvB,EAEAnZ,EAAK,IAAIs+B,EAAU,CACjB,SAAU,QACV,KAAM,EACN,IAAK,EACL,SAAUE,EACV,SAAUC,EACV,QAAS,EACT,cAAe,MAAA,CAChB,EACDz+B,EAAK,IAAIu+B,EAAa,CAAE,QAAS,EAAG,EAEpCplB,EAAK,IAAMnZ,EAAK,QAAQs+B,EAAU,IAAK,CAAE,KAAMZ,GAAa,EAC5DvkB,EAAK,IAAMnZ,EAAK,QAAQs+B,EAAU,IAAK,CAAE,KAAMZ,GAAa,EAE5DvkB,EAAK,iBAAmB,CAAChK,EAAWgqB,IAAoB,CACtD,GAAIhgB,EAAK,SAAU,OACnB,MAAMgmB,EAAsBb,EAAS,YAAchB,GAC7C8B,EAAWjwB,EAAI,OAAO,WAAagwB,EAAsB/B,GAAgBoB,EACzEa,EAAWlG,EAAI,OAAO,YAAc,GAAMkE,GAAgBoB,EAChEz+B,EAAK,GAAGs+B,EAAU,CAChB,SAAAc,EACA,SAAAC,EACA,SAAUvB,GACV,KAAMD,EAAA,CACP,CACH,EAEA1kB,EAAK,WAAa,IAAY,CAC5BnZ,EAAK,GAAGs+B,EAAU,CAAE,QAAS,EAAG,SAAUd,GAAe,KAAMG,GAAW,EAC1E39B,EAAK,OACHu+B,EACA,CAAE,EAAG,EAAG,SAAU,EAAG,QAAS,CAAA,EAC9B,CAAE,EAAG,EAAG,SAAU,EAAG,QAAS,EAAG,SAAUf,GAAe,KAAMG,EAAA,CAAU,CAE9E,EAEAxkB,EAAK,WAAa,IAAY,CAC5BA,EAAK,SAAW,GAChBnZ,EAAK,aAAau+B,CAAW,EAC7B,MAAMe,EAAef,EAAY,aAAe,IAC1CgB,EAAiB,KAAK,OAAA,EAAW,GAAK,GAC5Cv/B,EAAK,GAAGs+B,EAAU,CAAE,QAAS,EAAG,SAAUb,GAAe,KAAMG,GAAW,EAC1E59B,EAAK,GAAGu+B,EAAa,CACnB,EAAGe,EACH,SAAUC,EACV,QAAS,EACT,SAAU9B,GACV,KAAMG,GACN,WAAY,IAAM,CAChB59B,EAAK,IAAIu+B,EAAa,CAAE,EAAG,EAAG,SAAU,EAAG,EAC3CplB,EAAK,aAAA,EACLA,EAAK,SAAW,GAChB,MAAMqmB,EAASrmB,EAAK,mBACpB,GAAIqmB,EAAQ,CACVrmB,EAAK,mBAAqB,KAC1B,MAAMsmB,EAAe,SAAS,iBAAiBC,GAAiBC,EAAe,EAE3EF,IAAiBD,IAAWC,GAAgBD,EAAO,SAASC,CAAY,KAE1EtmB,EAAK,cAAgBqmB,EACrBrmB,EAAK,cAAcqmB,CAAM,EACzBrmB,EAAK,WAAA,EAET,CACF,CAAA,CACD,CACH,EAEAA,EAAK,QAAU,IAAY,CACzBnZ,EAAK,aAAas+B,CAAQ,EAC1Bt+B,EAAK,aAAau+B,CAAW,EAC7BplB,EAAK,aAAA,EACLqgB,GAAQ8E,EAAUI,CAAU,EAC5BlF,GAAQ+E,EAAaI,CAAS,CAChC,EAEOxlB,CACT,CAEA,IAAIumB,GAAkB,EAClBC,GAAkB,uEAEe,CACnC,KAAM,SACN,KAAK/yB,EAAiC,CACpC,GAAI,OAAO,OAAW,IAAa,MAAO,IAAM,CAAC,EAEjD,MAAMgzB,EAAY,MAAM,KAAK,SAAS,iBAA8B,aAAa,CAAC,EAClF,GAAIA,EAAU,SAAW,EAAG,MAAO,IAAM,CAAC,EAE1C,GAAI,CAAC,OAAO,WAAW,gBAAgB,EAAE,QAAS,CAChD,UAAWl/B,KAAMk/B,EACfl/B,EAAG,MAAM,QAAU,IACnBA,EAAG,MAAM,WAAa,SACtBA,EAAG,MAAM,cAAgB,OAE3B,MAAO,IAAM,CACX,UAAWA,KAAMk/B,EACfl/B,EAAG,MAAM,QAAU,GACnBA,EAAG,MAAM,WAAa,GACtBA,EAAG,MAAM,cAAgB,EAE7B,CACF,CAEA,MAAMV,EAAO4M,EAAI,KAAK,KAChBizB,MAAc,IAEpB,UAAWn/B,KAAMk/B,EAAW,CAC1B,MAAMz/B,EAAOO,EAAG,aAAa,WAAW,GAAK,GAC7C,GAAIm/B,EAAQ,IAAI1/B,CAAI,EAAG,CACjByM,EAAI,OACN,QAAQ,KACN,sCAAsCzM,EAAO,KAAKA,CAAI,IAAM,EAAE,oCAAA,EAGlE,QACF,CACA,MAAM6c,EAAQtc,EAAG,cAA2B,cAAc,EAC1D,GAAI,CAACsc,EAAO,CACNpQ,EAAI,OACN,QAAQ,KACN,4CAA4CzM,EAAO,KAAKA,CAAI,IAAM,EAAE,0CAAA,EAGxE,QACF,CACA,KAAM,CAACq+B,EAASC,CAAO,EAAIR,GACzBv9B,EAAG,aAAa,kBAAkB,EAClCP,EACAyM,EAAI,KAAA,EAENizB,EAAQ,IAAI1/B,EAAMk+B,GAAqB39B,EAAIsc,EAAOhd,EAAMw+B,EAASC,CAAO,CAAC,CAC3E,CAEA,GAAIoB,EAAQ,OAAS,EAAG,MAAO,IAAM,CAAC,EAEtC,IAAIC,EAAuB,KAC3B,MAAMC,EAAe7G,GAA4B,CAC/CwG,GAAkBxG,EAAM,QACxByG,GAAkBzG,EAAM,QACpB4G,IAAU,OACdA,EAAQ,sBAAsB,IAAM,CAClCA,EAAQ,KACR,UAAW3mB,KAAQ0mB,EAAQ,SACzB1mB,EAAK,iBAAiBumB,GAAiBC,EAAe,EACtDxmB,EAAK,IAAIumB,EAAe,EACxBvmB,EAAK,IAAIwmB,EAAe,CAE5B,CAAC,EACH,EACA,OAAO,iBAAiB,YAAaI,EAAa,CAAE,QAAS,GAAM,EAEnE,MAAMv6B,EAAW,MAAM,KAAK,SAAS,iBAA8B,qBAAqB,CAAC,EACnFw6B,MAAsB,QAK5B,UAAWh1B,KAAWxF,EAAU,CAC9B,MAAMrF,EAAO6K,EAAQ,aAAa,mBAAmB,GAAK,GACpDmO,EAAO0mB,EAAQ,IAAI1/B,CAAI,EAC7B,GAAI,CAACgZ,EAAM,SAEX,MAAM6gB,EAAU,IAAY,CAC1B,GAAI7gB,EAAK,SAAU,CACjBA,EAAK,mBAAqBnO,EAC1B,MACF,CACAmO,EAAK,cAAgBnO,EACrBmO,EAAK,cAAcnO,CAAO,EAC1BmO,EAAK,WAAA,CACP,EACM8gB,EAAU,IAAY,CAC1B9gB,EAAK,WAAA,CACP,EACAnO,EAAQ,iBAAiB,aAAcgvB,CAAO,EAC9ChvB,EAAQ,iBAAiB,aAAcivB,CAAO,EAC9C+F,EAAgB,IAAIh1B,EAAS,CAAE,MAAOgvB,EAAS,MAAOC,EAAS,CACjE,CAEA,MAAO,IAAM,CACX,OAAO,oBAAoB,YAAa8F,CAAW,EAC/CD,IAAU,OACZ,qBAAqBA,CAAK,EAC1BA,EAAQ,MAEV,UAAW90B,KAAWxF,EAAU,CAC9B,MAAMue,EAAWic,EAAgB,IAAIh1B,CAAO,EACvC+Y,IACL/Y,EAAQ,oBAAoB,aAAc+Y,EAAS,KAAK,EACxD/Y,EAAQ,oBAAoB,aAAc+Y,EAAS,KAAK,EAC1D,CACA,UAAW5K,KAAQ0mB,EAAQ,SACzB1mB,EAAK,mBAAqB,KAC1BA,EAAK,QAAA,EAEP0mB,EAAQ,MAAA,CACV,CACF,CACF,yCC9XMI,OAAe,IAAI,CACvB,OACA,QACA,SACA,YACA,aACA,OACA,UACA,UACF,CAAC,EACKC,GAAa,IAAI,IAAI,CAAC,SAAU,OAAO,CAAC,EACxCC,GAAY,IAAI,IAAI,CAAC,OAAQ,QAAS,cAAe,OAAQ,OAAQ,OAAO,CAAC,EAInF,SAASC,GAAWv9B,EAA2Bw9B,EAAiC,CAC9E,GAAI,CAACx9B,EAAO,OAAO,IAAI,IACvB,MAAMa,MAAU,IAChB,UAAWiC,KAAK9C,EAAM,KAAA,EAAO,MAAM,KAAK,EAClC8C,GAAKA,IAAM,QAAU06B,EAAM,IAAI16B,CAAC,GAAGjC,EAAI,IAAIiC,CAAC,EAElD,OAAOjC,CACT,CAeA,SAAS48B,GAAiBl0B,EAAeqL,EAAmBkB,EAA4B,CACtF,OAAIA,IAAS,KAAavM,EAAQqL,EAC9BkB,IAAS,MAAc,CAACvM,EAAQqL,EAChCrL,IAAU,EAAU,GAChBA,EAAQ,IAAM,EAAI,GAAK,GAAK,EAAIqL,CAC1C,CAKA,SAAS8oB,GAAQtsB,EAAoBusB,EAAgD,CACnF,OAAIvsB,EAAM,IAAI,GAAGusB,CAAM,KAAK,EAAU,KAClCvsB,EAAM,IAAI,GAAGusB,CAAM,MAAM,EAAU,MACnCvsB,EAAM,IAAIusB,CAAM,EAAU,UACvB,IACT,CASA,SAASC,GACPC,EACAC,EACAv0B,EACAqL,EACgC,CAChC,OAAIkpB,IAAa,KACR,CAAE,KAAM,EAAG,GAAIL,GAAiBl0B,EAAOqL,EAAWkpB,CAAQ,CAAA,EAE/DD,IAAe,KACV,CAAE,KAAMJ,GAAiBl0B,EAAOqL,EAAWipB,CAAU,EAAG,GAAI,CAAA,EAE9D,CAAA,CACT,CAKA,SAASE,GAAY3sB,EAAoBwD,EAAmBopB,EAAoC,CAC9F,MAAMv/B,EAAU,CAAA,EAChB,OAAI2S,EAAM,IAAI,OAAO,IAAG3S,EAAE,MAAQ,KAAK,IAAI,EAAG,EAAI,GAAMmW,CAAS,GAC7DopB,IAAa,SAAWv/B,EAAE,SAAWu/B,GAClCv/B,CACT,CAEA,SAASw/B,GAAU7sB,EAAoB4sB,EAAoC,CACzE,MAAMv/B,EAAU,CAAA,EAChB,OAAI2S,EAAM,IAAI,OAAO,MAAK,MAAQ,GAC9B4sB,IAAa,SAAWv/B,EAAE,SAAWu/B,GAClCv/B,CACT,CAEA,SAASy/B,GAAW9sB,EAAoBwD,EAAyB,CAC/D,MAAMnW,EAAU,CAAA,EAIhB,OAAI2S,EAAM,IAAI,MAAM,MAAK,QAAU,GAC/BA,EAAM,IAAI,OAAO,IAAG3S,EAAE,MAAQ,KAAK,IAAI,EAAG,EAAI,IAAOmW,CAAS,GAC9DxD,EAAM,IAAI,aAAa,IACzB3S,EAAE,UAAY,GAAKmW,EACnBnW,EAAE,MAAQ,IAOVA,EAAE,EAAI,GAAG,GAAKmW,CAAS,KAErBxD,EAAM,IAAI,MAAM,IAClB3S,EAAE,OAAS,QAAQ,EAAImW,CAAS,MAChCnW,EAAE,EAAI,GAAG,KAAOmW,CAAS,KAEvBxD,EAAM,IAAI,MAAM,IAClB3S,EAAE,EAAI,GAAG,GAAKmW,CAAS,MACvBnW,EAAE,QAAU,GAEV2S,EAAM,IAAI,OAAO,IACnB3S,EAAE,EAAI,GAAG,EAAImW,CAAS,MACtBnW,EAAE,QAAU,GAEPA,CACT,CAEA,SAAS0/B,GAAShhC,EAAoBq2B,EAAmBpiB,EAA0B,CAC7EA,EAAM,IAAI,QAAQ,EACpBjU,EACG,SAAS,CAAE,UAAW,MAAA,CAAQ,EAC9B,GAAGq2B,EAAM,CAAE,OAAQ,KAAM,OAAQ,IAAM,SAAU,GAAK,KAAM,YAAA,CAAc,EAC1E,GAAGA,EAAM,CAAE,OAAQ,EAAG,OAAQ,EAAG,SAAU,GAAK,KAAM,sBAAuB,EACvEpiB,EAAM,IAAI,OAAO,GAC1BjU,EACG,SAAS,CAAE,UAAW,MAAA,CAAQ,EAC9B,GAAGq2B,EAAM,CAAE,MAAO,KAAM,SAAU,IAAM,KAAM,YAAA,CAAc,EAC5D,GAAGA,EAAM,CAAE,MAAO,EAAG,SAAU,GAAK,KAAM,aAAA,CAAe,CAEhE,CAuBA,SAAS4K,GAAgB7I,EAAqC,CAG5D,MAAM8I,EAAY,WAAW,iBAAiB9I,EAAM,CAAC,CAAC,EAAE,GAAG,GAAK,EAC1D+I,EAAkB,CAAA,EACxB,QAASxsB,EAAI,EAAGA,EAAIyjB,EAAM,OAAQzjB,IAChCwsB,EAAM,KAAK/I,EAAMzjB,CAAC,EAAE,MAAM,QAAQ,EAClCyjB,EAAMzjB,CAAC,EAAE,MAAM,SAAW,SAGvByjB,EAAM,CAAC,EAAE,aACd,MAAMgJ,EAAOhJ,EAAM,IAAKtjB,GAAM,CAC5B,IAAIpF,EAAM,EACN2xB,EAA0BvsB,EAC9B,KAAOusB,GACL3xB,GAAO2xB,EAAI,UACXA,EAAMA,EAAI,aAEZ,OAAO3xB,CACT,CAAC,EACD,QAASiF,EAAI,EAAGA,EAAIyjB,EAAM,OAAQzjB,IAChCyjB,EAAMzjB,CAAC,EAAE,MAAM,SAAWwsB,EAAMxsB,CAAC,EAEnC,MAAO,CAAE,KAAAysB,EAAM,UAAAF,CAAA,CACjB,CAiBA,SAASI,GAAsBz+B,EAAmC,CAChE,GAAI,CAACA,EAAO,MAAO,KACnB,MAAMzB,EAAQyB,EAAM,KAAA,EAAO,MAAM,KAAK,EAChC0+B,EAASngC,EAAM,OAAS,EAAIA,EAAM,CAAC,EAAIA,EAAM,CAAC,EACpD,GAAI,CAACmgC,EAAQ,MAAO,KACpB,GAAIA,IAAW,SAAU,MAAO,GAChC,GAAIA,IAAW,SAAU,MAAO,IAChC,GAAIA,IAAW,MAAO,MAAO,GAC7B,MAAM70B,EAAI60B,EAAO,MAAM,cAAc,EACrC,GAAI,CAAC70B,EAAG,MAAO,KACf,MAAMpM,EAAI,WAAWoM,EAAE,CAAC,CAAC,EACzB,OAAO,OAAO,SAASpM,CAAC,EAAKA,EAAI,EAAIA,EAAI,IAAMA,EAAK,GACtD,CAEA,SAASwM,GACPF,EACAxI,EACAd,EAC0B,CAC1B,IAAKA,EAAO,UAAU,GAAK,IAAI,KAAA,IAAW,OAAQ,OAElD,MAAM80B,EAAQ,MAAM,KAAKh0B,EAAK,iBAA8B,iBAAiB,CAAC,EAC9E,GAAIg0B,EAAM,SAAW,EAAG,OAExB,MAAM7yB,EAAgBqH,EAAI,KAAK,QAAQ,cACvC,GAAI,CAACrH,EAAe,OAEpB,MAAMvF,EAAO4M,EAAI,KAAK,KAEhB40B,EAAUpB,GAAW98B,EAAO,aAAa,EAAG28B,EAAQ,EACpDwB,EAAYrB,GAAW98B,EAAO,eAAe,EAAG48B,EAAU,EAC1DwB,EAAWtB,GAAW98B,EAAO,cAAc,EAAG68B,EAAS,EAEvD1oB,EAAY7R,EAAStC,EAAO,cAAc,EAAGsJ,EAAI,QAAQ,SAAS,EAOlEvH,EAAc,GAKdq7B,EAAaH,GAAQiB,EAAS,QAAQ,EACtCb,EAAWJ,GAAQiB,EAAS,MAAM,EASlCG,EAAgBL,GACpBh+B,EAAO,iBAAiB,GAAKsJ,EAAI,QAAQ,WAAA,EAS3C,IAAIg1B,EAAWX,GAAgB7I,CAAK,EAEpC,MAAMyJ,EAAej1B,EAAI,gBAAkB,KAqBrCk1B,EAAY,IACZC,EAAW3J,EAAMA,EAAM,OAAS,CAAC,EACjC4J,EACJ,CAACH,GAAgBzJ,EAAM,OAAS,GAAKsJ,EAAS,IAAI,aAAa,GAAKK,IAAa,OAC7EE,EAAc,IAAeF,EAAS,aAAeD,EAAYrqB,EAAa,IAC9EyqB,EAAcH,IAAa,OAAYA,EAAS,MAAM,aAAe,GACrEI,EAAmB,IAAY,CAC/BH,IAAcD,EAAS,MAAM,aAAe,GAAGE,GAAa,KAClE,EACAE,EAAA,EAEA,MAAMC,EAAgB,IAAY,CAChCR,EAAWX,GAAgB7I,CAAK,EAChC+J,EAAA,CACF,EACA58B,EAAc,iBAAiB,cAAe68B,CAAa,EAE3D,MAAM7e,EAA8B,CAAA,EACpCA,EAAS,KAAK,IAAMhe,EAAc,oBAAoB,cAAe68B,CAAa,CAAC,EAC/EJ,GAAcze,EAAS,KAAK,IAAOwe,EAAS,MAAM,aAAeG,CAAY,EACjF,MAAM/pB,EAAQvL,EAAI,QAAQ,QAAU,GAEpC,OAAAwrB,EAAM,QAAQ,CAAC/B,EAAMjqB,IAAU,CAK7BpM,EAAK,IAAIq2B,EAAM,CAAE,OAAQjqB,EAAQ,EAAG,EAKpC,MAAMi2B,EAAa,IAAcT,EAAS,KAAKx1B,CAAK,EAAI,OAAO,YACzDk2B,EAAY,IAAcV,EAAS,KAAKx1B,CAAK,EAAIw1B,EAAS,UAC1DW,EAAgB,IACpBX,EAAS,KAAKx1B,CAAK,EAAIu1B,EAAgB,OAAO,YAC1Ca,EAAe,IACnBZ,EAAS,KAAKx1B,CAAK,EAAI,OAAO,YAShC,IAAI+Z,EAAW,GACf,MAAMsH,EAAY,CAAC1K,EAAe5iB,IAAgD,CAC5EgmB,IAAapD,IACjBoD,EAAWpD,EACX7Z,EAAYmtB,EAAMl2B,CAAI,EACxB,EAKMsiC,EAAgBl9B,EAAc,OAAO,CACzC,QAAS8wB,EACT,MAAOkM,EACP,QAAS,IAAM9U,EAAU,GAAM,aAAa,CAAA,CAC7C,EAKD,GAJAlK,EAAS,KAAK,IAAMkf,EAAc,KAAA,CAAM,EAIpCtqB,EAAO,CACT,MAAMuqB,EAAkBn9B,EAAc,OAAO,CAC3C,QAAS8wB,EACT,MAAOmM,EACP,YAAa,IAAM/U,EAAU,GAAO,eAAe,CAAA,CACpD,EACDlK,EAAS,KAAK,IAAMmf,EAAgB,KAAA,CAAM,CAC5C,CAUA,GAAI,OAAO,SAAWH,IAAiB,CACrCpc,EAAW,GACX,MAAMwc,EAAY3iC,EAAK,YAAY,EAAG,IAAMkJ,EAAYmtB,EAAM,aAAa,CAAC,EAC5E9S,EAAS,KAAK,IAAMof,EAAU,KAAA,CAAM,CACtC,CAKA,GAAId,EAAc,OAOlB,GAAIL,EAAQ,IAAI,MAAM,EAAG,CACvB,MAAMoB,EAAU,KAAeP,EAAA,EAAeC,KAAe,EACvDO,EAAY7iC,EAAK,OACrBq2B,EACA,CAAE,QAAS,CAAA,EACX,CACE,QAAS,EACT,KAAM,YACN,gBAAiB,GACjB,cAAe,CAAE,QAASA,EAAM,MAAOgM,EAAY,IAAKO,EAAS,MAAAv9B,CAAA,CAAM,CACzE,EAEFke,EAAS,KAAK,IAAMsf,EAAU,KAAA,CAAM,CACtC,CAEA,MAAMC,EAAMrC,GAAaC,EAAYC,EAAUv0B,EAAOqL,CAAS,EACzDsrB,EAASnC,GAAYY,EAAS/pB,EAAWqrB,EAAI,IAAI,EACvD,GAAI,OAAO,KAAKC,CAAM,EAAE,OAAS,EAAG,CAClC,MAAMh4B,EAAQ/K,EAAK,OAAOq2B,EAAM0M,EAAQ,CACtC,GAAGjC,GAAUU,EAASsB,EAAI,EAAE,EAC5B,KAAM,YAUN,gBAAiB,GACjB,cAAe,CACb,QAASzM,EACT,MAAOgM,EACP,IAAKC,EACL,MAAAj9B,CAAA,CACF,CACD,EACDke,EAAS,KAAK,IAAMxY,EAAM,KAAA,CAAM,CAClC,CAEA,GAAI02B,EAAU,KAAO,EAAG,CACtB,MAAMz2B,EAAUzF,EAAc,OAAO,CACnC,QAAS8wB,EACT,MAAOiM,EACP,QAAS,IAAMtB,GAAShhC,EAAMq2B,EAAMoL,CAAS,CAAA,CAC9C,EACDle,EAAS,KAAK,IAAMvY,EAAQ,KAAA,CAAM,CACpC,CAYA,GAAI02B,EAAS,KAAO,GAAKt1B,EAAQgsB,EAAM,OAAS,EAAG,CACjD,MAAM4K,EAAW5K,EAAMhsB,EAAQ,CAAC,EAC1B62B,EAAW,IACf,KAAK,IACHrB,EAAS,KAAKx1B,EAAQ,CAAC,EAAI,OAAO,YAClCw1B,EAAS,KAAKx1B,CAAK,EAAIw1B,EAAS,SAAA,EAE9BsB,EAAS,IAActB,EAAS,KAAKx1B,EAAQ,CAAC,EAAIw1B,EAAS,UAC3D72B,EAAQ/K,EAAK,GAAGq2B,EAAM,CAC1B,GAAG0K,GAAWW,EAAUjqB,CAAS,EACjC,KAAM,YACN,cAAe,CACb,QAASurB,EACT,MAAOC,EACP,IAAKC,EACL,MAAA79B,EAGA,oBAAqB,EAAA,CACvB,CACD,EACDke,EAAS,KAAK,IAAMxY,EAAM,KAAA,CAAM,CAClC,CAQA,GAAIi3B,GAAgB51B,IAAUgsB,EAAM,OAAS,EAAG,CAC9C,MAAM+K,EAAa,IAAcvB,EAAS,KAAKx1B,CAAK,EAAIw1B,EAAS,UAC3DwB,EAAW,IAAcxB,EAAS,KAAKx1B,CAAK,EAAIw1B,EAAS,UAAYK,EAAA,EACrEl3B,EAAQ/K,EAAK,GAAGq2B,EAAM,CAC1B,EAAG,GAAG,CAACyL,EAAYrqB,CAAS,IAC5B,KAAM,OACN,cAAe,CACb,QAAS4e,EACT,MAAO8M,EACP,IAAKC,EACL,MAAA/9B,EAGA,oBAAqB,EAAA,CACvB,CACD,EACDke,EAAS,KAAK,IAAMxY,EAAM,KAAA,CAAM,CAClC,CACF,CAAC,EAEM,IAAM,CACX,GAAI,CACF,UAAWhC,KAAMwa,EAAUxa,EAAA,CAC7B,MAAQ,CAGR,CACF,CACF,sEAEoC,CAClC,KAAM,QACN,KAAK6D,EAAiC,CACpC,OAAAI,GAAgBJ,EAAK,WAAYE,EAAQ,EAClC,IAAM,CAAC,CAChB,CACF,yCCpgBA,SAASu2B,GAAW3iC,EAAsB,CAExC,MAAMqX,EAAUrX,EAAG,aAAa,YAAY,GAAK,GACjD,UAAWuE,KAAQ8S,EAAQ,MAAM,GAAG,EAClC,GAAI9S,EAAK,KAAA,EAAO,WAAW,OAAO,EAAG,MAAO,GAE9C,UAAW5D,IAAM,CAAC,KAAM,KAAM,KAAM,IAAI,EAAG,CACzC,MAAMC,EAAIZ,EAAG,aAAa,cAAcW,CAAE,EAAE,EAC5C,GAAIC,GAAKA,EAAE,WAAW,OAAO,EAAG,MAAO,EACzC,CAMA,MAAMgiC,EAAQ5iC,EAAG,aAAa,UAAU,GAAK,GAC7C,UAAWuE,KAAQq+B,EAAM,MAAM,GAAG,EAChC,GAAIr+B,EAAK,OAAO,MAAM,KAAK,EAAE,CAAC,IAAM,OAAQ,MAAO,GAErD,UAAW5D,IAAM,CAAC,KAAM,KAAM,KAAM,IAAI,EAAG,CACzC,MAAMC,EAAIZ,EAAG,aAAa,YAAYW,CAAE,EAAE,EAC1C,GAAIC,GAAKA,EAAE,OAAO,MAAM,KAAK,EAAE,CAAC,IAAM,OAAQ,MAAO,EACvD,CACA,MAAO,EACT,sEAEoC,CAClC,KAAM,QACN,KAAKsL,EAAiC,CACpC,MAAMG,EAAWH,EAAI,SAAS,OAC3BlM,GAAOA,EAAG,aAAa,UAAU,GAAK,CAAC2iC,GAAW3iC,CAAE,CAAA,EAEvD,UAAWuC,KAAW8J,EAAU,CAC9B,MAAM7J,EAAQzC,EAAUwC,CAAO,EAC/B2J,EAAI,WAAW,KAAK3J,EAASC,EAAO,CAAC,CAAE,OAAAI,KAAa,CAClD,MAAMyX,EAAQtC,GAAWnV,EAAO,UAAU,CAAC,EAC3C,GAAI,CAACyX,EAAO,OACZ,MAAMzY,EAASwW,GAAW7V,EAAS8X,EAAM,KAAMnO,EAAI,KAAM,CACvD,KAAMmO,EAAM,KACZ,MAAOA,EAAM,KAAA,CACd,EACD,MAAO,IAAMzY,EAAO,OAAA,CACtB,CAAC,CACH,CACA,MAAO,IAAM,CAAC,CAChB,CACF"}