EhPeek

タッチ操作向けの E-H/ExH リーダー

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         EhPeek
// @version      260807.1338
// @description  A touch-optimized E-H/ExH viewer
// @description:ja  タッチ操作向けの E-H/ExH リーダー
// @description:zh-CN  为触屏优化的 E-H/ExH 阅读器
// @icon         https://raw.githubusercontent.com/yamipot/ehpeek/master/icon.svg
// @icon64       https://raw.githubusercontent.com/yamipot/ehpeek/master/icon.svg
// @license      MIT
// @namespace    https://github.com/yamipot/ehpeek
// @homepage     https://github.com/yamipot/ehpeek
// @supportURL   https://github.com/yamipot/ehpeek/issues
// @match        *://exhentai.org/*
// @match        *://exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion/*
// @match        *://e-hentai.org/*
// @match        *://*.exhentai.org/*
// @match        *://*.exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion/*
// @match        *://*.e-hentai.org/*
// @match        *://*.hath.network/*
// @exclude      *://forums.e-hentai.org/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_registerMenuCommand
// @grant        GM_download
// @run-at       document-start
// ==/UserScript==

"use strict";
(() => {
  var __defProp = Object.defineProperty;
  var __typeError = (msg) => {
    throw TypeError(msg);
  };
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
  var __export = (target, all) => {
    for (var name in all)
      __defProp(target, name, { get: all[name], enumerable: !0 });
  };
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value), __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)), __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value), __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);

  // node_modules/.pnpm/[email protected]/node_modules/solid-js/dist/solid.js
  var sharedConfig = {
    context: void 0,
    registry: void 0,
    effects: void 0,
    done: !1,
    getContextId() {
      return getContextId(this.context.count);
    },
    getNextContextId() {
      return getContextId(this.context.count++);
    }
  };
  function getContextId(count) {
    let num = String(count), len = num.length - 1;
    return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
  }
  function setHydrateContext(context) {
    sharedConfig.context = context;
  }
  function nextHydrateContext() {
    return {
      ...sharedConfig.context,
      id: sharedConfig.getNextContextId(),
      count: 0
    };
  }
  var IS_DEV = !1, equalFn = (a, b) => a === b, $PROXY = /* @__PURE__ */ Symbol("solid-proxy"), SUPPORTS_PROXY = typeof Proxy == "function", $TRACK = /* @__PURE__ */ Symbol("solid-track");
  var signalOptions = {
    equals: equalFn
  }, ERROR = null, runEffects = runQueue, STALE = 1, PENDING = 2, UNOWNED = {
    owned: null,
    cleanups: null,
    context: null,
    owner: null
  };
  var Owner = null, Transition = null, Scheduler = null, ExternalSourceConfig = null, Listener = null, Updates = null, Effects = null, ExecCount = 0;
  function createRoot(fn, detachedOwner) {
    let listener = Listener, owner = Owner, unowned = fn.length === 0, current = detachedOwner === void 0 ? owner : detachedOwner, root = unowned ? UNOWNED : {
      owned: null,
      cleanups: null,
      context: current ? current.context : null,
      owner: current
    }, updateFn = unowned ? fn : () => fn(() => untrack(() => cleanNode(root)));
    Owner = root, Listener = null;
    try {
      return runUpdates(updateFn, !0);
    } finally {
      Listener = listener, Owner = owner;
    }
  }
  function createSignal(value, options) {
    options = options ? Object.assign({}, signalOptions, options) : signalOptions;
    let s = {
      value,
      observers: null,
      observerSlots: null,
      comparator: options.equals || void 0
    }, setter = (value2) => (typeof value2 == "function" && (Transition && Transition.running && Transition.sources.has(s) ? value2 = value2(s.tValue) : value2 = value2(s.value)), writeSignal(s, value2));
    return [readSignal.bind(s), setter];
  }
  function createRenderEffect(fn, value, options) {
    let c = createComputation(fn, value, !1, STALE);
    Scheduler && Transition && Transition.running ? Updates.push(c) : updateComputation(c);
  }
  function createEffect(fn, value, options) {
    runEffects = runUserEffects;
    let c = createComputation(fn, value, !1, STALE), s = SuspenseContext && useContext(SuspenseContext);
    s && (c.suspense = s), (!options || !options.render) && (c.user = !0), Effects ? Effects.push(c) : updateComputation(c);
  }
  function createMemo(fn, value, options) {
    options = options ? Object.assign({}, signalOptions, options) : signalOptions;
    let c = createComputation(fn, value, !0, 0);
    return c.observers = null, c.observerSlots = null, c.comparator = options.equals || void 0, Scheduler && Transition && Transition.running ? (c.tState = STALE, Updates.push(c)) : updateComputation(c), readSignal.bind(c);
  }
  function batch(fn) {
    return runUpdates(fn, !1);
  }
  function untrack(fn) {
    if (!ExternalSourceConfig && Listener === null) return fn();
    let listener = Listener;
    Listener = null;
    try {
      return ExternalSourceConfig ? ExternalSourceConfig.untrack(fn) : fn();
    } finally {
      Listener = listener;
    }
  }
  function onMount(fn) {
    createEffect(() => untrack(fn));
  }
  function onCleanup(fn) {
    return Owner === null || (Owner.cleanups === null ? Owner.cleanups = [fn] : Owner.cleanups.push(fn)), fn;
  }
  function getListener() {
    return Listener;
  }
  function getOwner() {
    return Owner;
  }
  function runWithOwner(o, fn) {
    let prev = Owner, prevListener = Listener;
    Owner = o, Listener = null;
    try {
      return runUpdates(fn, !0);
    } catch (err) {
      handleError(err);
    } finally {
      Owner = prev, Listener = prevListener;
    }
  }
  function startTransition(fn) {
    if (Transition && Transition.running)
      return fn(), Transition.done;
    let l = Listener, o = Owner;
    return Promise.resolve().then(() => {
      Listener = l, Owner = o;
      let t;
      return (Scheduler || SuspenseContext) && (t = Transition || (Transition = {
        sources: /* @__PURE__ */ new Set(),
        effects: [],
        promises: /* @__PURE__ */ new Set(),
        disposed: /* @__PURE__ */ new Set(),
        queue: /* @__PURE__ */ new Set(),
        running: !0
      }), t.done || (t.done = new Promise((res) => t.resolve = res)), t.running = !0), runUpdates(fn, !1), Listener = Owner = null, t ? t.done : void 0;
    });
  }
  var [transPending, setTransPending] = /* @__PURE__ */ createSignal(!1);
  function createContext(defaultValue, options) {
    let id2 = /* @__PURE__ */ Symbol("context");
    return {
      id: id2,
      Provider: createProvider(id2),
      defaultValue
    };
  }
  function useContext(context) {
    let value;
    return Owner && Owner.context && (value = Owner.context[context.id]) !== void 0 ? value : context.defaultValue;
  }
  function children(fn) {
    let children2 = createMemo(fn), memo2 = createMemo(() => resolveChildren(children2()));
    return memo2.toArray = () => {
      let c = memo2();
      return Array.isArray(c) ? c : c != null ? [c] : [];
    }, memo2;
  }
  var SuspenseContext;
  function readSignal() {
    let runningTransition = Transition && Transition.running;
    if (this.sources && (runningTransition ? this.tState : this.state))
      if ((runningTransition ? this.tState : this.state) === STALE) updateComputation(this);
      else {
        let updates = Updates;
        Updates = null, runUpdates(() => lookUpstream(this), !1), Updates = updates;
      }
    if (Listener) {
      let observers = this.observers;
      if (!observers || observers[observers.length - 1] !== Listener) {
        let sSlot = observers ? observers.length : 0;
        Listener.sources ? (Listener.sources.push(this), Listener.sourceSlots.push(sSlot)) : (Listener.sources = [this], Listener.sourceSlots = [sSlot]), observers ? (observers.push(Listener), this.observerSlots.push(Listener.sources.length - 1)) : (this.observers = [Listener], this.observerSlots = [Listener.sources.length - 1]);
      }
    }
    return runningTransition && Transition.sources.has(this) ? this.tValue : this.value;
  }
  function writeSignal(node, value, isComp) {
    let current = Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value;
    if (!node.comparator || !node.comparator(current, value)) {
      if (Transition) {
        let TransitionRunning = Transition.running;
        (TransitionRunning || !isComp && Transition.sources.has(node)) && (Transition.sources.add(node), node.tValue = value), TransitionRunning || (node.value = value);
      } else node.value = value;
      node.observers && node.observers.length && runUpdates(() => {
        for (let i = 0; i < node.observers.length; i += 1) {
          let o = node.observers[i], TransitionRunning = Transition && Transition.running;
          TransitionRunning && Transition.disposed.has(o) || ((TransitionRunning ? !o.tState : !o.state) && (o.pure ? Updates.push(o) : Effects.push(o), o.observers && markDownstream(o)), TransitionRunning ? o.tState = STALE : o.state = STALE);
        }
        if (Updates.length > 1e6)
          throw Updates = [], new Error();
      }, !1);
    }
    return value;
  }
  function updateComputation(node) {
    if (!node.fn) return;
    cleanNode(node);
    let time = ExecCount;
    runComputation(node, Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value, time), Transition && !Transition.running && Transition.sources.has(node) && queueMicrotask(() => {
      runUpdates(() => {
        Transition && (Transition.running = !0), Listener = Owner = node, runComputation(node, node.tValue, time), Listener = Owner = null;
      }, !1);
    });
  }
  function runComputation(node, value, time) {
    let nextValue, owner = Owner, listener = Listener;
    Listener = Owner = node;
    try {
      nextValue = node.fn(value);
    } catch (err) {
      return node.pure && (Transition && Transition.running ? (node.tState = STALE, node.tOwned && node.tOwned.forEach(cleanNode), node.tOwned = void 0) : (node.state = STALE, node.owned && node.owned.forEach(cleanNode), node.owned = null)), node.updatedAt = time + 1, handleError(err);
    } finally {
      Listener = listener, Owner = owner;
    }
    (!node.updatedAt || node.updatedAt <= time) && (node.updatedAt != null && "observers" in node ? writeSignal(node, nextValue, !0) : Transition && Transition.running && node.pure ? (Transition.sources.has(node) || (node.value = nextValue), Transition.sources.add(node), node.tValue = nextValue) : node.value = nextValue, node.updatedAt = time);
  }
  function createComputation(fn, init, pure, state2 = STALE, options) {
    let c = {
      fn,
      state: state2,
      updatedAt: null,
      owned: null,
      sources: null,
      sourceSlots: null,
      cleanups: null,
      value: init,
      owner: Owner,
      context: Owner ? Owner.context : null,
      pure
    };
    if (Transition && Transition.running && (c.state = 0, c.tState = state2), Owner === null || Owner !== UNOWNED && (Transition && Transition.running && Owner.pure ? Owner.tOwned ? Owner.tOwned.push(c) : Owner.tOwned = [c] : Owner.owned ? Owner.owned.push(c) : Owner.owned = [c]), ExternalSourceConfig && c.fn) {
      let sourceFn = c.fn, [track, trigger] = createSignal(void 0, {
        equals: !1
      }), ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
      onCleanup(() => ordinary.dispose());
      let inTransition, triggerInTransition = () => startTransition(trigger).then(() => {
        inTransition && (inTransition.dispose(), inTransition = void 0);
      });
      c.fn = (x) => (track(), Transition && Transition.running ? (inTransition || (inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition)), inTransition.track(x)) : ordinary.track(x));
    }
    return c;
  }
  function runTop(node) {
    let runningTransition = Transition && Transition.running;
    if ((runningTransition ? node.tState : node.state) === 0) return;
    if ((runningTransition ? node.tState : node.state) === PENDING) return lookUpstream(node);
    if (node.suspense && untrack(node.suspense.inFallback)) return node.suspense.effects.push(node);
    let ancestors = [node];
    for (; (node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount); ) {
      if (runningTransition && Transition.disposed.has(node)) return;
      (runningTransition ? node.tState : node.state) && ancestors.push(node);
    }
    for (let i = ancestors.length - 1; i >= 0; i--) {
      if (node = ancestors[i], runningTransition) {
        let top = node, prev = ancestors[i + 1];
        for (; (top = top.owner) && top !== prev; )
          if (Transition.disposed.has(top)) return;
      }
      if ((runningTransition ? node.tState : node.state) === STALE)
        updateComputation(node);
      else if ((runningTransition ? node.tState : node.state) === PENDING) {
        let updates = Updates;
        Updates = null, runUpdates(() => lookUpstream(node, ancestors[0]), !1), Updates = updates;
      }
    }
  }
  function runUpdates(fn, init) {
    if (Updates) return fn();
    let wait = !1;
    init || (Updates = []), Effects ? wait = !0 : Effects = [], ExecCount++;
    try {
      let res = fn();
      return completeUpdates(wait), res;
    } catch (err) {
      wait || (Effects = null), Updates = null, handleError(err);
    }
  }
  function completeUpdates(wait) {
    if (Updates && (Scheduler && Transition && Transition.running ? scheduleQueue(Updates) : runQueue(Updates), Updates = null), wait) return;
    let res;
    if (Transition) {
      if (!Transition.promises.size && !Transition.queue.size) {
        let sources = Transition.sources, disposed = Transition.disposed;
        Effects.push.apply(Effects, Transition.effects), res = Transition.resolve;
        for (let e2 of Effects)
          "tState" in e2 && (e2.state = e2.tState), delete e2.tState;
        Transition = null, runUpdates(() => {
          for (let d of disposed) cleanNode(d);
          for (let v of sources) {
            if (v.value = v.tValue, v.owned)
              for (let i = 0, len = v.owned.length; i < len; i++) cleanNode(v.owned[i]);
            v.tOwned && (v.owned = v.tOwned), delete v.tValue, delete v.tOwned, v.tState = 0;
          }
          setTransPending(!1);
        }, !1);
      } else if (Transition.running) {
        Transition.running = !1, Transition.effects.push.apply(Transition.effects, Effects), Effects = null, setTransPending(!0);
        return;
      }
    }
    let e = Effects;
    Effects = null, e.length && runUpdates(() => runEffects(e), !1), res && res();
  }
  function runQueue(queue) {
    for (let i = 0; i < queue.length; i++) runTop(queue[i]);
  }
  function scheduleQueue(queue) {
    for (let i = 0; i < queue.length; i++) {
      let item = queue[i], tasks = Transition.queue;
      tasks.has(item) || (tasks.add(item), Scheduler(() => {
        tasks.delete(item), runUpdates(() => {
          Transition.running = !0, runTop(item);
        }, !1), Transition && (Transition.running = !1);
      }));
    }
  }
  function runUserEffects(queue) {
    let i, userLength = 0;
    for (i = 0; i < queue.length; i++) {
      let e = queue[i];
      e.user ? queue[userLength++] = e : runTop(e);
    }
    if (sharedConfig.context) {
      if (sharedConfig.count) {
        sharedConfig.effects || (sharedConfig.effects = []), sharedConfig.effects.push(...queue.slice(0, userLength));
        return;
      }
      setHydrateContext();
    }
    for (sharedConfig.effects && (sharedConfig.done || !sharedConfig.count) && (queue = [...sharedConfig.effects, ...queue], userLength += sharedConfig.effects.length, delete sharedConfig.effects), i = 0; i < userLength; i++) runTop(queue[i]);
  }
  function lookUpstream(node, ignore) {
    let runningTransition = Transition && Transition.running;
    runningTransition ? node.tState = 0 : node.state = 0;
    for (let i = 0; i < node.sources.length; i += 1) {
      let source = node.sources[i];
      if (source.sources) {
        let state2 = runningTransition ? source.tState : source.state;
        state2 === STALE ? source !== ignore && (!source.updatedAt || source.updatedAt < ExecCount) && runTop(source) : state2 === PENDING && lookUpstream(source, ignore);
      }
    }
  }
  function markDownstream(node) {
    let runningTransition = Transition && Transition.running;
    for (let i = 0; i < node.observers.length; i += 1) {
      let o = node.observers[i];
      (runningTransition ? !o.tState : !o.state) && (runningTransition ? o.tState = PENDING : o.state = PENDING, o.pure ? Updates.push(o) : Effects.push(o), o.observers && markDownstream(o));
    }
  }
  function cleanNode(node) {
    let i;
    if (node.sources)
      for (; node.sources.length; ) {
        let source = node.sources.pop(), index = node.sourceSlots.pop(), obs = source.observers;
        if (obs && obs.length) {
          let n = obs.pop(), s = source.observerSlots.pop();
          index < obs.length && (n.sourceSlots[s] = index, obs[index] = n, source.observerSlots[index] = s);
        }
      }
    if (node.tOwned) {
      for (i = node.tOwned.length - 1; i >= 0; i--) cleanNode(node.tOwned[i]);
      delete node.tOwned;
    }
    if (Transition && Transition.running && node.pure)
      reset(node, !0);
    else if (node.owned) {
      for (i = node.owned.length - 1; i >= 0; i--) cleanNode(node.owned[i]);
      node.owned = null;
    }
    if (node.cleanups) {
      for (i = node.cleanups.length - 1; i >= 0; i--) node.cleanups[i]();
      node.cleanups = null;
    }
    Transition && Transition.running ? node.tState = 0 : node.state = 0;
  }
  function reset(node, top) {
    if (top || (node.tState = 0, Transition.disposed.add(node)), node.owned)
      for (let i = 0; i < node.owned.length; i++) reset(node.owned[i]);
  }
  function castError(err) {
    return err instanceof Error ? err : new Error(typeof err == "string" ? err : "Unknown error", {
      cause: err
    });
  }
  function runErrors(err, fns, owner) {
    try {
      for (let f of fns) f(err);
    } catch (e) {
      handleError(e, owner && owner.owner || null);
    }
  }
  function handleError(err, owner = Owner) {
    let fns = ERROR && owner && owner.context && owner.context[ERROR], error = castError(err);
    if (!fns) throw error;
    Effects ? Effects.push({
      fn() {
        runErrors(error, fns, owner);
      },
      state: STALE
    }) : runErrors(error, fns, owner);
  }
  function resolveChildren(children2) {
    if (typeof children2 == "function" && !children2.length) return resolveChildren(children2());
    if (Array.isArray(children2)) {
      let results = [];
      for (let i = 0; i < children2.length; i++) {
        let result = resolveChildren(children2[i]);
        if (Array.isArray(result))
          if (result.length < 32768) results.push.apply(results, result);
          else for (let j = 0; j < result.length; j++) results.push(result[j]);
        else
          results.push(result);
      }
      return results;
    }
    return children2;
  }
  function createProvider(id2, options) {
    return function(props) {
      let res;
      return createRenderEffect(() => res = untrack(() => (Owner.context = {
        ...Owner.context,
        [id2]: props.value
      }, children(() => props.children))), void 0), res;
    };
  }
  var FALLBACK = /* @__PURE__ */ Symbol("fallback");
  function dispose(d) {
    for (let i = 0; i < d.length; i++) d[i]();
  }
  function mapArray(list, mapFn, options = {}) {
    let items = [], mapped = [], disposers = [], len = 0, indexes = mapFn.length > 1 ? [] : null;
    return onCleanup(() => dispose(disposers)), () => {
      let newItems = list() || [], newLen = newItems.length, i, j;
      return newItems[$TRACK], untrack(() => {
        let newIndices, newIndicesNext, temp, tempdisposers, tempIndexes, start, end, newEnd, item;
        if (newLen === 0)
          len !== 0 && (dispose(disposers), disposers = [], items = [], mapped = [], len = 0, indexes && (indexes = [])), options.fallback && (items = [FALLBACK], mapped[0] = createRoot((disposer) => (disposers[0] = disposer, options.fallback())), len = 1);
        else if (len === 0) {
          for (mapped = new Array(newLen), j = 0; j < newLen; j++)
            items[j] = newItems[j], mapped[j] = createRoot(mapper);
          len = newLen;
        } else {
          for (temp = new Array(newLen), tempdisposers = new Array(newLen), indexes && (tempIndexes = new Array(newLen)), start = 0, end = Math.min(len, newLen); start < end && items[start] === newItems[start]; start++) ;
          for (end = len - 1, newEnd = newLen - 1; end >= start && newEnd >= start && items[end] === newItems[newEnd]; end--, newEnd--)
            temp[newEnd] = mapped[end], tempdisposers[newEnd] = disposers[end], indexes && (tempIndexes[newEnd] = indexes[end]);
          for (newIndices = /* @__PURE__ */ new Map(), newIndicesNext = new Array(newEnd + 1), j = newEnd; j >= start; j--)
            item = newItems[j], i = newIndices.get(item), newIndicesNext[j] = i === void 0 ? -1 : i, newIndices.set(item, j);
          for (i = start; i <= end; i++)
            item = items[i], j = newIndices.get(item), j !== void 0 && j !== -1 ? (temp[j] = mapped[i], tempdisposers[j] = disposers[i], indexes && (tempIndexes[j] = indexes[i]), j = newIndicesNext[j], newIndices.set(item, j)) : disposers[i]();
          for (j = start; j < newLen; j++)
            j in temp ? (mapped[j] = temp[j], disposers[j] = tempdisposers[j], indexes && (indexes[j] = tempIndexes[j], indexes[j](j))) : mapped[j] = createRoot(mapper);
          mapped = mapped.slice(0, len = newLen), items = newItems.slice(0);
        }
        return mapped;
      });
      function mapper(disposer) {
        if (disposers[j] = disposer, indexes) {
          let [s, set] = createSignal(j);
          return indexes[j] = set, mapFn(newItems[j], s);
        }
        return mapFn(newItems[j]);
      }
    };
  }
  var hydrationEnabled = !1;
  function createComponent(Comp, props) {
    if (hydrationEnabled && sharedConfig.context) {
      let c = sharedConfig.context;
      setHydrateContext(nextHydrateContext());
      let r = untrack(() => Comp(props || {}));
      return setHydrateContext(c), r;
    }
    return untrack(() => Comp(props || {}));
  }
  function trueFn() {
    return !0;
  }
  var propTraps = {
    get(_, property, receiver) {
      return property === $PROXY ? receiver : _.get(property);
    },
    has(_, property) {
      return property === $PROXY ? !0 : _.has(property);
    },
    set: trueFn,
    deleteProperty: trueFn,
    getOwnPropertyDescriptor(_, property) {
      return {
        configurable: !0,
        enumerable: !0,
        get() {
          return _.get(property);
        },
        set: trueFn,
        deleteProperty: trueFn
      };
    },
    ownKeys(_) {
      return _.keys();
    }
  };
  function resolveSource(s) {
    return (s = typeof s == "function" ? s() : s) ? s : {};
  }
  function resolveSources() {
    for (let i = 0, length = this.length; i < length; ++i) {
      let v = this[i]();
      if (v !== void 0) return v;
    }
  }
  function mergeProps(...sources) {
    let proxy = !1;
    for (let i = 0; i < sources.length; i++) {
      let s = sources[i];
      proxy = proxy || !!s && $PROXY in s, sources[i] = typeof s == "function" ? (proxy = !0, createMemo(s)) : s;
    }
    if (SUPPORTS_PROXY && proxy)
      return new Proxy({
        get(property) {
          for (let i = sources.length - 1; i >= 0; i--) {
            let v = resolveSource(sources[i])[property];
            if (v !== void 0) return v;
          }
        },
        has(property) {
          for (let i = sources.length - 1; i >= 0; i--)
            if (property in resolveSource(sources[i])) return !0;
          return !1;
        },
        keys() {
          let keys = [];
          for (let i = 0; i < sources.length; i++) keys.push(...Object.keys(resolveSource(sources[i])));
          return [...new Set(keys)];
        }
      }, propTraps);
    let sourcesMap = {}, defined = /* @__PURE__ */ Object.create(null);
    for (let i = sources.length - 1; i >= 0; i--) {
      let source = sources[i];
      if (!source) continue;
      let sourceKeys = Object.getOwnPropertyNames(source);
      for (let i2 = sourceKeys.length - 1; i2 >= 0; i2--) {
        let key = sourceKeys[i2];
        if (key === "__proto__" || key === "constructor") continue;
        let desc = Object.getOwnPropertyDescriptor(source, key);
        if (!defined[key])
          defined[key] = desc.get ? {
            enumerable: !0,
            configurable: !0,
            get: resolveSources.bind(sourcesMap[key] = [desc.get.bind(source)])
          } : desc.value !== void 0 ? desc : void 0;
        else {
          let sources2 = sourcesMap[key];
          sources2 && (desc.get ? sources2.push(desc.get.bind(source)) : desc.value !== void 0 && sources2.push(() => desc.value));
        }
      }
    }
    let target = {}, definedKeys = Object.keys(defined);
    for (let i = definedKeys.length - 1; i >= 0; i--) {
      let key = definedKeys[i], desc = defined[key];
      desc && desc.get ? Object.defineProperty(target, key, desc) : target[key] = desc ? desc.value : void 0;
    }
    return target;
  }
  function splitProps(props, ...keys) {
    let len = keys.length;
    if (SUPPORTS_PROXY && $PROXY in props) {
      let blocked = len > 1 ? keys.flat() : keys[0], res = keys.map((k) => new Proxy({
        get(property) {
          return k.includes(property) ? props[property] : void 0;
        },
        has(property) {
          return k.includes(property) && property in props;
        },
        keys() {
          return k.filter((property) => property in props);
        }
      }, propTraps));
      return res.push(new Proxy({
        get(property) {
          return blocked.includes(property) ? void 0 : props[property];
        },
        has(property) {
          return blocked.includes(property) ? !1 : property in props;
        },
        keys() {
          return Object.keys(props).filter((k) => !blocked.includes(k));
        }
      }, propTraps)), res;
    }
    let objects = [];
    for (let i = 0; i <= len; i++)
      objects[i] = {};
    for (let propName of Object.getOwnPropertyNames(props)) {
      let keyIndex = len;
      for (let i = 0; i < keys.length; i++)
        if (keys[i].includes(propName)) {
          keyIndex = i;
          break;
        }
      let desc = Object.getOwnPropertyDescriptor(props, propName);
      !desc.get && !desc.set && desc.enumerable && desc.writable && desc.configurable ? objects[keyIndex][propName] = desc.value : Object.defineProperty(objects[keyIndex], propName, desc);
    }
    return objects;
  }
  var narrowedError = (name) => `Stale read from <${name}>.`;
  function For(props) {
    let fallback = "fallback" in props && {
      fallback: () => props.fallback
    };
    return createMemo(mapArray(() => props.each, props.children, fallback || void 0));
  }
  function Show(props) {
    let keyed = props.keyed, conditionValue = createMemo(() => props.when, void 0, void 0), condition = keyed ? conditionValue : createMemo(conditionValue, void 0, {
      equals: (a, b) => !a == !b
    });
    return createMemo(() => {
      let c = condition();
      if (c) {
        let child = props.children;
        return typeof child == "function" && child.length > 0 ? untrack(() => child(keyed ? c : () => {
          if (!untrack(condition)) throw narrowedError("Show");
          return conditionValue();
        })) : child;
      }
      return props.fallback;
    }, void 0, void 0);
  }

  // node_modules/.pnpm/[email protected]/node_modules/solid-js/web/dist/web.js
  var booleans = [
    "allowfullscreen",
    "async",
    "alpha",
    "autofocus",
    "autoplay",
    "checked",
    "controls",
    "default",
    "disabled",
    "formnovalidate",
    "hidden",
    "indeterminate",
    "inert",
    "ismap",
    "loop",
    "multiple",
    "muted",
    "nomodule",
    "novalidate",
    "open",
    "playsinline",
    "readonly",
    "required",
    "reversed",
    "seamless",
    "selected",
    "adauctionheaders",
    "browsingtopics",
    "credentialless",
    "defaultchecked",
    "defaultmuted",
    "defaultselected",
    "defer",
    "disablepictureinpicture",
    "disableremoteplayback",
    "preservespitch",
    "shadowrootclonable",
    "shadowrootcustomelementregistry",
    "shadowrootdelegatesfocus",
    "shadowrootserializable",
    "sharedstoragewritable"
  ], Properties = /* @__PURE__ */ new Set([
    "className",
    "value",
    "readOnly",
    "noValidate",
    "formNoValidate",
    "isMap",
    "noModule",
    "playsInline",
    "adAuctionHeaders",
    "allowFullscreen",
    "browsingTopics",
    "defaultChecked",
    "defaultMuted",
    "defaultSelected",
    "disablePictureInPicture",
    "disableRemotePlayback",
    "preservesPitch",
    "shadowRootClonable",
    "shadowRootCustomElementRegistry",
    "shadowRootDelegatesFocus",
    "shadowRootSerializable",
    "sharedStorageWritable",
    ...booleans
  ]), ChildProperties = /* @__PURE__ */ new Set(["innerHTML", "textContent", "innerText", "children"]), Aliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
    className: "class",
    htmlFor: "for"
  }), PropAliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
    class: "className",
    novalidate: {
      $: "noValidate",
      FORM: 1
    },
    formnovalidate: {
      $: "formNoValidate",
      BUTTON: 1,
      INPUT: 1
    },
    ismap: {
      $: "isMap",
      IMG: 1
    },
    nomodule: {
      $: "noModule",
      SCRIPT: 1
    },
    playsinline: {
      $: "playsInline",
      VIDEO: 1
    },
    readonly: {
      $: "readOnly",
      INPUT: 1,
      TEXTAREA: 1
    },
    adauctionheaders: {
      $: "adAuctionHeaders",
      IFRAME: 1
    },
    allowfullscreen: {
      $: "allowFullscreen",
      IFRAME: 1
    },
    browsingtopics: {
      $: "browsingTopics",
      IMG: 1
    },
    defaultchecked: {
      $: "defaultChecked",
      INPUT: 1
    },
    defaultmuted: {
      $: "defaultMuted",
      AUDIO: 1,
      VIDEO: 1
    },
    defaultselected: {
      $: "defaultSelected",
      OPTION: 1
    },
    disablepictureinpicture: {
      $: "disablePictureInPicture",
      VIDEO: 1
    },
    disableremoteplayback: {
      $: "disableRemotePlayback",
      AUDIO: 1,
      VIDEO: 1
    },
    preservespitch: {
      $: "preservesPitch",
      AUDIO: 1,
      VIDEO: 1
    },
    shadowrootclonable: {
      $: "shadowRootClonable",
      TEMPLATE: 1
    },
    shadowrootdelegatesfocus: {
      $: "shadowRootDelegatesFocus",
      TEMPLATE: 1
    },
    shadowrootserializable: {
      $: "shadowRootSerializable",
      TEMPLATE: 1
    },
    sharedstoragewritable: {
      $: "sharedStorageWritable",
      IFRAME: 1,
      IMG: 1
    }
  });
  function getPropAlias(prop, tagName) {
    let a = PropAliases[prop];
    return typeof a == "object" ? a[tagName] ? a.$ : void 0 : a;
  }
  var DelegatedEvents = /* @__PURE__ */ new Set(["beforeinput", "click", "dblclick", "contextmenu", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart"]), SVGElements = /* @__PURE__ */ new Set([
    "altGlyph",
    "altGlyphDef",
    "altGlyphItem",
    "animate",
    "animateColor",
    "animateMotion",
    "animateTransform",
    "circle",
    "clipPath",
    "color-profile",
    "cursor",
    "defs",
    "desc",
    "ellipse",
    "feBlend",
    "feColorMatrix",
    "feComponentTransfer",
    "feComposite",
    "feConvolveMatrix",
    "feDiffuseLighting",
    "feDisplacementMap",
    "feDistantLight",
    "feDropShadow",
    "feFlood",
    "feFuncA",
    "feFuncB",
    "feFuncG",
    "feFuncR",
    "feGaussianBlur",
    "feImage",
    "feMerge",
    "feMergeNode",
    "feMorphology",
    "feOffset",
    "fePointLight",
    "feSpecularLighting",
    "feSpotLight",
    "feTile",
    "feTurbulence",
    "filter",
    "font",
    "font-face",
    "font-face-format",
    "font-face-name",
    "font-face-src",
    "font-face-uri",
    "foreignObject",
    "g",
    "glyph",
    "glyphRef",
    "hkern",
    "image",
    "line",
    "linearGradient",
    "marker",
    "mask",
    "metadata",
    "missing-glyph",
    "mpath",
    "path",
    "pattern",
    "polygon",
    "polyline",
    "radialGradient",
    "rect",
    "set",
    "stop",
    "svg",
    "switch",
    "symbol",
    "text",
    "textPath",
    "tref",
    "tspan",
    "use",
    "view",
    "vkern"
  ]), SVGNamespace = {
    xlink: "http://www.w3.org/1999/xlink",
    xml: "http://www.w3.org/XML/1998/namespace"
  };
  var memo = (fn) => createMemo(() => fn());
  function reconcileArrays(parentNode, a, b) {
    let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = a[aEnd - 1].nextSibling, map = null;
    for (; aStart < aEnd || bStart < bEnd; ) {
      if (a[aStart] === b[bStart]) {
        aStart++, bStart++;
        continue;
      }
      for (; a[aEnd - 1] === b[bEnd - 1]; )
        aEnd--, bEnd--;
      if (aEnd === aStart) {
        let node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after;
        for (; bStart < bEnd; ) parentNode.insertBefore(b[bStart++], node);
      } else if (bEnd === bStart)
        for (; aStart < aEnd; )
          (!map || !map.has(a[aStart])) && a[aStart].remove(), aStart++;
      else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
        let node = a[--aEnd].nextSibling;
        parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling), parentNode.insertBefore(b[--bEnd], node), a[aEnd] = b[bEnd];
      } else {
        if (!map) {
          map = /* @__PURE__ */ new Map();
          let i = bStart;
          for (; i < bEnd; ) map.set(b[i], i++);
        }
        let index = map.get(a[aStart]);
        if (index != null)
          if (bStart < index && index < bEnd) {
            let i = aStart, sequence = 1, t;
            for (; ++i < aEnd && i < bEnd && !((t = map.get(a[i])) == null || t !== index + sequence); )
              sequence++;
            if (sequence > index - bStart) {
              let node = a[aStart];
              for (; bStart < index; ) parentNode.insertBefore(b[bStart++], node);
            } else parentNode.replaceChild(b[bStart++], a[aStart++]);
          } else aStart++;
        else a[aStart++].remove();
      }
    }
  }
  var $$EVENTS = "_$DX_DELEGATE";
  function render(code, element, init, options = {}) {
    let disposer;
    return createRoot((dispose2) => {
      disposer = dispose2, element === document ? code() : insert(element, code(), element.firstChild ? null : void 0, init);
    }, options.owner), () => {
      disposer(), element.textContent = "";
    };
  }
  function template(html, isImportNode, isSVG, isMathML) {
    let node, create = () => {
      let t = isMathML ? document.createElementNS("http://www.w3.org/1998/Math/MathML", "template") : document.createElement("template");
      return t.innerHTML = html, isSVG ? t.content.firstChild.firstChild : isMathML ? t.firstChild : t.content.firstChild;
    }, fn = isImportNode ? () => untrack(() => document.importNode(node || (node = create()), !0)) : () => (node || (node = create())).cloneNode(!0);
    return fn.cloneNode = fn, fn;
  }
  function delegateEvents(eventNames, document2 = window.document) {
    let e = document2[$$EVENTS] || (document2[$$EVENTS] = /* @__PURE__ */ new Set());
    for (let i = 0, l = eventNames.length; i < l; i++) {
      let name = eventNames[i];
      e.has(name) || (e.add(name), document2.addEventListener(name, eventHandler));
    }
  }
  function setAttribute(node, name, value) {
    isHydrating(node) || (value == null ? node.removeAttribute(name) : node.setAttribute(name, value));
  }
  function setAttributeNS(node, namespace, name, value) {
    isHydrating(node) || (value == null ? node.removeAttributeNS(namespace, name) : node.setAttributeNS(namespace, name, value));
  }
  function setBoolAttribute(node, name, value) {
    isHydrating(node) || (value ? node.setAttribute(name, "") : node.removeAttribute(name));
  }
  function className(node, value) {
    isHydrating(node) || (value == null ? node.removeAttribute("class") : node.className = value);
  }
  function addEventListener(node, name, handler, delegate) {
    if (delegate)
      Array.isArray(handler) ? (node[`$$${name}`] = handler[0], node[`$$${name}Data`] = handler[1]) : node[`$$${name}`] = handler;
    else if (Array.isArray(handler)) {
      let handlerFn = handler[0];
      node.addEventListener(name, handler[0] = (e) => handlerFn.call(node, handler[1], e));
    } else node.addEventListener(name, handler, typeof handler != "function" && handler);
  }
  function classList(node, value, prev = {}) {
    let classKeys = Object.keys(value || {}), prevKeys = Object.keys(prev), i, len;
    for (i = 0, len = prevKeys.length; i < len; i++) {
      let key = prevKeys[i];
      !key || key === "undefined" || value[key] || (toggleClassKey(node, key, !1), delete prev[key]);
    }
    for (i = 0, len = classKeys.length; i < len; i++) {
      let key = classKeys[i], classValue = !!value[key];
      !key || key === "undefined" || prev[key] === classValue || !classValue || (toggleClassKey(node, key, !0), prev[key] = classValue);
    }
    return prev;
  }
  function style(node, value, prev) {
    if (!value) return prev ? setAttribute(node, "style") : value;
    let nodeStyle = node.style;
    if (typeof value == "string") return nodeStyle.cssText = value;
    typeof prev == "string" && (nodeStyle.cssText = prev = void 0), prev || (prev = {}), value || (value = {});
    let v, s;
    for (s in prev)
      value[s] == null && nodeStyle.removeProperty(s), delete prev[s];
    for (s in value)
      v = value[s], v !== prev[s] && (nodeStyle.setProperty(s, v), prev[s] = v);
    return prev;
  }
  function setStyleProperty(node, name, value) {
    value != null ? node.style.setProperty(name, value) : node.style.removeProperty(name);
  }
  function spread(node, props = {}, isSVG, skipChildren) {
    let prevProps = {};
    return skipChildren || createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children)), createRenderEffect(() => typeof props.ref == "function" && use(props.ref, node)), createRenderEffect(() => assign(node, props, isSVG, !0, prevProps, !0)), prevProps;
  }
  function use(fn, element, arg) {
    return untrack(() => fn(element, arg));
  }
  function insert(parent, accessor, marker, initial) {
    if (marker !== void 0 && !initial && (initial = []), typeof accessor != "function") return insertExpression(parent, accessor, initial, marker);
    createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial);
  }
  function assign(node, props, isSVG, skipChildren, prevProps = {}, skipRef = !1) {
    props || (props = {});
    for (let prop in prevProps)
      if (!(prop in props)) {
        if (prop === "children") continue;
        prevProps[prop] = assignProp(node, prop, null, prevProps[prop], isSVG, skipRef, props);
      }
    for (let prop in props) {
      if (prop === "children") {
        skipChildren || insertExpression(node, props.children);
        continue;
      }
      let value = props[prop];
      prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG, skipRef, props);
    }
  }
  function getNextElement(template2) {
    let node, key;
    return !isHydrating() || !(node = sharedConfig.registry.get(key = getHydrationKey())) ? template2() : (sharedConfig.completed && sharedConfig.completed.add(node), sharedConfig.registry.delete(key), node);
  }
  function isHydrating(node) {
    return !!sharedConfig.context && !sharedConfig.done && (!node || node.isConnected);
  }
  function toPropertyName(name) {
    return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
  }
  function toggleClassKey(node, key, value) {
    let classNames = key.trim().split(/\s+/);
    for (let i = 0, nameLen = classNames.length; i < nameLen; i++) node.classList.toggle(classNames[i], value);
  }
  function assignProp(node, prop, value, prev, isSVG, skipRef, props) {
    let isCE, isProp, isChildProp, propAlias, forceProp;
    if (prop === "style") return style(node, value, prev);
    if (prop === "classList") return classList(node, value, prev);
    if (value === prev) return prev;
    if (prop === "ref")
      skipRef || value(node);
    else if (prop.slice(0, 3) === "on:") {
      let e = prop.slice(3);
      prev && node.removeEventListener(e, prev, typeof prev != "function" && prev), value && node.addEventListener(e, value, typeof value != "function" && value);
    } else if (prop.slice(0, 10) === "oncapture:") {
      let e = prop.slice(10);
      prev && node.removeEventListener(e, prev, !0), value && node.addEventListener(e, value, !0);
    } else if (prop.slice(0, 2) === "on") {
      let name = prop.slice(2).toLowerCase(), delegate = DelegatedEvents.has(name);
      if (!delegate && prev) {
        let h = Array.isArray(prev) ? prev[0] : prev;
        node.removeEventListener(name, h);
      }
      (delegate || value) && (addEventListener(node, name, value, delegate), delegate && delegateEvents([name]));
    } else if (prop.slice(0, 5) === "attr:")
      setAttribute(node, prop.slice(5), value);
    else if (prop.slice(0, 5) === "bool:")
      setBoolAttribute(node, prop.slice(5), value);
    else if ((forceProp = prop.slice(0, 5) === "prop:") || (isChildProp = ChildProperties.has(prop)) || !isSVG && ((propAlias = getPropAlias(prop, node.tagName)) || (isProp = Properties.has(prop))) || (isCE = node.nodeName.includes("-") || "is" in props)) {
      if (forceProp)
        prop = prop.slice(5), isProp = !0;
      else if (isHydrating(node)) return value;
      prop === "class" || prop === "className" ? className(node, value) : isCE && !isProp && !isChildProp ? node[toPropertyName(prop)] = value : node[propAlias || prop] = value;
    } else {
      let ns = isSVG && prop.indexOf(":") > -1 && SVGNamespace[prop.split(":")[0]];
      ns ? setAttributeNS(node, ns, prop, value) : setAttribute(node, Aliases[prop] || prop, value);
    }
    return value;
  }
  function eventHandler(e) {
    if (sharedConfig.registry && sharedConfig.events && sharedConfig.events.find(([el, ev]) => ev === e))
      return;
    let node = e.target, key = `$$${e.type}`, oriTarget = e.target, oriCurrentTarget = e.currentTarget, retarget = (value) => Object.defineProperty(e, "target", {
      configurable: !0,
      value
    }), handleNode = () => {
      let handler = node[key];
      if (handler && !node.disabled) {
        let data = node[`${key}Data`];
        if (data !== void 0 ? handler.call(node, data, e) : handler.call(node, e), e.cancelBubble) return;
      }
      return node.host && typeof node.host != "string" && !node.host._$host && node.contains(e.target) && retarget(node.host), !0;
    }, walkUpTree = () => {
      for (; handleNode() && (node = node._$host || node.parentNode || node.host); ) ;
    };
    if (Object.defineProperty(e, "currentTarget", {
      configurable: !0,
      get() {
        return node || document;
      }
    }), sharedConfig.registry && !sharedConfig.done && (sharedConfig.done = _$HY.done = !0), e.composedPath) {
      let path = e.composedPath();
      retarget(path[0]);
      for (let i = 0; i < path.length - 2 && (node = path[i], !!handleNode()); i++) {
        if (node._$host) {
          node = node._$host, walkUpTree();
          break;
        }
        if (node.parentNode === oriCurrentTarget)
          break;
      }
    } else walkUpTree();
    retarget(oriTarget);
  }
  function insertExpression(parent, value, current, marker, unwrapArray) {
    let hydrating = isHydrating(parent);
    if (hydrating) {
      !current && (current = [...parent.childNodes]);
      let cleaned = [];
      for (let i = 0; i < current.length; i++) {
        let node = current[i];
        node.nodeType === 8 && node.data.slice(0, 2) === "!$" ? node.remove() : cleaned.push(node);
      }
      current = cleaned;
    }
    for (; typeof current == "function"; ) current = current();
    if (value === current) return current;
    let t = typeof value, multi = marker !== void 0;
    if (parent = multi && current[0] && current[0].parentNode || parent, t === "string" || t === "number") {
      if (hydrating || t === "number" && (value = value.toString(), value === current))
        return current;
      if (multi) {
        let node = current[0];
        node && node.nodeType === 3 ? node.data !== value && (node.data = value) : node = document.createTextNode(value), current = cleanChildren(parent, current, marker, node);
      } else
        current !== "" && typeof current == "string" ? current = parent.firstChild.data = value : current = parent.textContent = value;
    } else if (value == null || t === "boolean") {
      if (hydrating) return current;
      current = cleanChildren(parent, current, marker);
    } else {
      if (t === "function")
        return createRenderEffect(() => {
          let v = value();
          for (; typeof v == "function"; ) v = v();
          current = insertExpression(parent, v, current, marker);
        }), () => current;
      if (Array.isArray(value)) {
        let array = [], currentArray = current && Array.isArray(current);
        if (normalizeIncomingArray(array, value, current, unwrapArray))
          return createRenderEffect(() => current = insertExpression(parent, array, current, marker, !0)), () => current;
        if (hydrating) {
          if (!array.length) return current;
          if (marker === void 0) return current = [...parent.childNodes];
          let node = array[0];
          if (node.parentNode !== parent) return current;
          let nodes = [node];
          for (; (node = node.nextSibling) !== marker; ) nodes.push(node);
          return current = nodes;
        }
        if (array.length === 0) {
          if (current = cleanChildren(parent, current, marker), multi) return current;
        } else currentArray ? current.length === 0 ? appendNodes(parent, array, marker) : reconcileArrays(parent, current, array) : (current && cleanChildren(parent), appendNodes(parent, array));
        current = array;
      } else if (value.nodeType) {
        if (hydrating && value.parentNode) return current = multi ? [value] : value;
        if (Array.isArray(current)) {
          if (multi) return current = cleanChildren(parent, current, marker, value);
          cleanChildren(parent, current, null, value);
        } else current == null || current === "" || !parent.firstChild ? parent.appendChild(value) : parent.replaceChild(value, parent.firstChild);
        current = value;
      }
    }
    return current;
  }
  function normalizeIncomingArray(normalized, array, current, unwrap2) {
    let dynamic = !1;
    for (let i = 0, len = array.length; i < len; i++) {
      let item = array[i], prev = current && current[normalized.length], t;
      if (!(item == null || item === !0 || item === !1)) if ((t = typeof item) == "object" && item.nodeType)
        normalized.push(item);
      else if (Array.isArray(item))
        dynamic = normalizeIncomingArray(normalized, item, prev) || dynamic;
      else if (t === "function")
        if (unwrap2) {
          for (; typeof item == "function"; ) item = item();
          dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item], Array.isArray(prev) ? prev : [prev]) || dynamic;
        } else
          normalized.push(item), dynamic = !0;
      else {
        let value = String(item);
        prev && prev.nodeType === 3 && prev.data === value ? normalized.push(prev) : normalized.push(document.createTextNode(value));
      }
    }
    return dynamic;
  }
  function appendNodes(parent, array, marker = null) {
    for (let i = 0, len = array.length; i < len; i++) parent.insertBefore(array[i], marker);
  }
  function cleanChildren(parent, current, marker, replacement) {
    if (marker === void 0) return parent.textContent = "";
    let node = replacement || document.createTextNode("");
    if (current.length) {
      let inserted = !1;
      for (let i = current.length - 1; i >= 0; i--) {
        let el = current[i];
        if (node !== el) {
          let isParent = el.parentNode === parent;
          !inserted && !i ? isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker) : isParent && el.remove();
        } else inserted = !0;
      }
    } else parent.insertBefore(node, marker);
    return [node];
  }
  function getHydrationKey() {
    return sharedConfig.getNextContextId();
  }
  var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
  function createElement(tagName, isSVG = !1, is = void 0) {
    return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName, {
      is
    });
  }
  function Portal(props) {
    let {
      useShadow
    } = props, marker = document.createTextNode(""), mount = () => props.mount || document.body, owner = getOwner(), content, hydrating = !!sharedConfig.context;
    return createEffect(() => {
      hydrating && (getOwner().user = hydrating = !1), content || (content = runWithOwner(owner, () => createMemo(() => props.children)));
      let el = mount();
      if (el instanceof HTMLHeadElement) {
        let [clean, setClean] = createSignal(!1), cleanup = () => setClean(!0);
        createRoot((dispose2) => insert(el, () => clean() ? dispose2() : content(), null)), onCleanup(cleanup);
      } else {
        let container = createElement(props.isSVG ? "g" : "div", props.isSVG), renderRoot = useShadow && container.attachShadow ? container.attachShadow({
          mode: "open"
        }) : container;
        Object.defineProperty(container, "_$host", {
          get() {
            return marker.parentNode;
          },
          configurable: !0
        }), insert(renderRoot, content), el.appendChild(container), props.ref && props.ref(container), onCleanup(() => el.contains(container) && el.removeChild(container));
      }
    }, void 0, {
      render: !hydrating
    }), marker;
  }
  function createDynamic(component, props) {
    let cached = createMemo(component);
    return createMemo(() => {
      let component2 = cached();
      switch (typeof component2) {
        case "function":
          return untrack(() => component2(props));
        case "string":
          let isSvg = SVGElements.has(component2), el = sharedConfig.context ? getNextElement() : createElement(component2, isSvg, untrack(() => props.is));
          return spread(el, props, isSvg), el;
      }
    });
  }
  function Dynamic(props) {
    let [, others] = splitProps(props, ["component"]);
    return createDynamic(() => props.component, others);
  }

  // src/eh/url.ts
  var EXHENTAI_HOST = "exhentai.org", EXHENTAI_ONION_HOST = "exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion";
  function ehSiteTheme(url = window.location.href) {
    let hostname = new URL(url, window.location.href).hostname;
    return hostname === EXHENTAI_HOST || hostname.endsWith(`.${EXHENTAI_HOST}`) || hostname === EXHENTAI_ONION_HOST || hostname.endsWith(`.${EXHENTAI_ONION_HOST}`) ? "exhentai" : "e-hentai";
  }
  function galleryIdentityFromUrl(url = window.location.href) {
    try {
      let match = new URL(url, window.location.href).pathname.match(/^\/g\/(\d+)\/([^/]+)/i), galleryId = Number(match?.[1]), token = match?.[2];
      return token && Number.isSafeInteger(galleryId) && galleryId > 0 ? { galleryId, token } : null;
    } catch {
      return null;
    }
  }
  function urlPath(url) {
    try {
      return new URL(url, window.location.href).pathname.toLowerCase();
    } catch {
      return "";
    }
  }
  function galleryTagNameFromUrl(url) {
    let encodedName = urlPath(url).match(/^\/tag\/(.+?)\/?$/i)?.[1];
    try {
      return encodedName ? decodeURIComponent(encodedName.replace(/\+/g, " ")) : null;
    } catch {
      return null;
    }
  }
  function isFullImageUrl(url) {
    return urlPath(url).includes("/fullimg");
  }
  function extractPageType(url = window.location.href) {
    try {
      let parsed = new URL(url, window.location.href), hash = new URLSearchParams(parsed.hash.replace(/^#/, ""));
      if (parsed.pathname === "/popular" && hash.has("ehpeek_history")) {
        let requestedPage = Number(hash.get("page") ?? "0");
        return {
          type: "readHistory",
          url: parsed.href,
          pageIndex: Number.isSafeInteger(requestedPage) && requestedPage >= 0 ? requestedPage : 0
        };
      }
      let galleryMatch = parsed.pathname.match(/^\/g\/(\d+)\/([^/]+)\/?$/i);
      if (galleryMatch) {
        let galleryId = Number(galleryMatch[1]), token = galleryMatch[2];
        if (token && Number.isFinite(galleryId) && galleryId > 0)
          return {
            type: "gallery",
            url: parsed.href,
            galleryId,
            token,
            previewIndex: previewPageIndex(parsed.href),
            peekPage: peekPageFromHash(parsed.hash)
          };
      }
      let imageMatch = parsed.pathname.match(/^\/s\/[^/]+\/(\d+)-(\d+)\/?$/i);
      if (imageMatch) {
        let galleryId = Number(imageMatch[1]), pageNum = Number(imageMatch[2]);
        if (Number.isFinite(galleryId) && galleryId > 0 && Number.isFinite(pageNum) && pageNum > 0)
          return {
            type: "image",
            url: parsed.href,
            galleryId,
            pageNum
          };
      }
      return parsed.pathname === "/favorites.php" ? {
        type: "favorites",
        url: parsed.href
      } : /^\/mytags\/?$/.test(parsed.pathname) ? {
        type: "myTags",
        url: parsed.href
      } : parsed.pathname === "/uconfig.php" ? {
        type: "settings",
        url: parsed.href
      } : parsed.pathname === "/" || parsed.pathname.startsWith("/tag/") || parsed.pathname.startsWith("/uploader/") || /^\/(?:popular|watched)\/?$/.test(parsed.pathname) ? {
        type: "search",
        url: parsed.href
      } : {
        type: "other",
        url: parsed.href
      };
    } catch {
      return {
        type: "other",
        url
      };
    }
  }
  function readHistoryUrl(pageIndex = 0) {
    let url = new URL("/popular", window.location.href);
    return url.hash = pageIndex > 0 ? `ehpeek_history&page=${pageIndex}` : "ehpeek_history", url.href;
  }
  function galleryPageNumber(url) {
    let page2 = extractPageType(url);
    return page2.type === "image" ? page2.pageNum : void 0;
  }
  function previewPageIndex(url = window.location.href) {
    try {
      let value = Number(new URL(url).searchParams.get("p") || "0");
      return Number.isFinite(value) && value >= 0 ? value : 0;
    } catch {
      return 0;
    }
  }
  function previewUrlForIndex(previewIndex, pageUrl = window.location.href) {
    let url = new URL(pageUrl);
    return previewIndex <= 0 ? url.searchParams.delete("p") : url.searchParams.set("p", String(previewIndex)), url.hash = "", url.href;
  }
  function previewPageIndexForGalleryPage(galleryPage, pageSize, maxPreviewIndex) {
    let previewIndex = Math.max(0, Math.floor((galleryPage - 1) / pageSize));
    return Math.min(previewIndex, maxPreviewIndex);
  }
  function peekPageFromHash(hash = window.location.hash) {
    let params = new URLSearchParams(hash.replace(/^#/, "")), page2 = Number(params.get("peek_page") || "");
    return Number.isFinite(page2) && page2 > 0 ? page2 : null;
  }
  function clearPeekLocation() {
    let url = new URL(window.location.href), params = new URLSearchParams(url.hash.replace(/^#/, ""));
    params.has("peek_page") && (params.delete("peek_page"), url.hash = params.toString(), window.history.replaceState(window.history.state, "", url.href));
  }
  function updatePeekLocation(pageNumber, pageSize, maxPreviewIndex) {
    if (!pageNumber || pageNumber <= 0)
      return;
    let url = new URL(window.location.href), params = new URLSearchParams(window.location.hash.replace(/^#/, "")), nextValue = String(pageNumber), nextPreviewIndex = previewPageIndexForGalleryPage(pageNumber, pageSize, maxPreviewIndex), changed = !1;
    nextPreviewIndex === 0 ? url.searchParams.has("p") && (url.searchParams.delete("p"), changed = !0) : url.searchParams.get("p") !== String(nextPreviewIndex) && (url.searchParams.set("p", String(nextPreviewIndex)), changed = !0), params.get("peek_page") !== nextValue && (params.set("peek_page", nextValue), changed = !0), changed && (url.hash = params.toString(), window.history.replaceState(window.history.state, "", url.href));
  }

  // src/eh/request.ts
  async function requestPage(url, options = {}) {
    let controller = new AbortController(), abort = () => controller.abort(), timeoutMs = options.timeoutMs === void 0 ? 3e4 : options.timeoutMs, timeout = timeoutMs === null ? null : window.setTimeout(abort, timeoutMs);
    options.signal?.aborted ? controller.abort() : options.signal?.addEventListener("abort", abort, { once: !0 });
    try {
      let response = await fetch(url, {
        method: options.method ?? "GET",
        body: options.body,
        credentials: "include",
        headers: options.headers,
        signal: controller.signal
      });
      if (!response.ok)
        throw new Error(`HTTP ${response.status}`);
      let html = await response.text();
      return {
        document: new DOMParser().parseFromString(html, "text/html"),
        url: response.url || url
      };
    } finally {
      timeout !== null && window.clearTimeout(timeout), options.signal?.removeEventListener("abort", abort);
    }
  }
  async function updateGalleryFavorite(actionUrl, value, note) {
    let body = new URLSearchParams();
    body.set("favcat", value), body.set("favnote", note), body.set("apply", "Apply Changes"), body.set("update", "1"), await requestPage(actionUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body
    });
  }
  async function addMyTag(tagName, tagSet, mode) {
    let body = new URLSearchParams();
    body.set("usertag_action", "add"), body.set("tagname_new", tagName), body.set("tagcolor_new", ""), body.set("tagweight_new", "10"), mode === "watched" ? body.set("tagwatch_new", "on") : mode === "hidden" && body.set("taghide_new", "on");
    let url = new URL("/mytags", window.location.origin);
    return url.searchParams.set("tagset", tagSet), requestPage(url.href, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body
    });
  }
  async function deleteMyTag(tagId, tagSet) {
    let body = new URLSearchParams();
    body.set("usertag_action", "mass"), body.set("usertag_target", "0"), body.append("modify_usertags[]", tagId);
    let url = new URL("/mytags", window.location.origin);
    return url.searchParams.set("tagset", tagSet), requestPage(url.href, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body
    });
  }

  // ehpeek-spectrum-ui-sizes:ehpeek:spectrum-ui-sizes
  var ehpeek_spectrum_ui_sizes_default = { control: { xs: "24px", sm: "32px", md: "40px", lg: "48px", xl: "56px" }, font: { xs: "10px", sm: "14px", md: "16px", lg: "20px", xl: "28px" }, icon: { xs: "14px", sm: "16px", md: "20px", lg: "22px", xl: "26px" }, space: { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px" }, radius: { xs: "3px", sm: "4px", md: "6px", lg: "8px", xl: "10px" } };

  // src/ui.ts
  var UI_ROOT_CLASS = "ehpeek-ui-root", UI_STATE_STYLE_ID = "ehpeek-ui-state", UI_SCALE_SELECTOR = ".ehpeek-ui-root, body.ehpeek-touch-gallery-page, .eh-syringe-lite-auto-complete-list", UI_SCALE_FACTORS = {
    xsmall: 0.8,
    small: 1,
    medium: 1.25,
    large: 1.5,
    xlarge: 1.8
  }, UI_SCALE_NAMES = Object.freeze(
    Object.keys(UI_SCALE_FACTORS)
  ), uiState;
  function configureUi(options) {
    uiState = { ...options }, applyUiStateClasses();
  }
  function markUiRoot(root) {
    root.parentElement?.closest(`.${UI_ROOT_CLASS}`) || root.classList.add(UI_ROOT_CLASS);
  }
  function setUiPointer(pointer) {
    let state2 = requireUiState();
    state2.pointer = pointer, applyUiStateClasses();
  }
  function nextUiScale(scale) {
    let index = UI_SCALE_NAMES.indexOf(scale);
    return UI_SCALE_NAMES[(index + 1) % UI_SCALE_NAMES.length];
  }
  function uiScaleLevel(scale) {
    return UI_SCALE_NAMES.indexOf(scale) + 1;
  }
  function applyUiScale(scale, root, pixelFactor = 1) {
    let factor = UI_SCALE_FACTORS[scale] * pixelFactor;
    if (!root) {
      applyGlobalUiScale(factor);
      return;
    }
    for (let [property, value] of uiScaleDeclarations(factor))
      root.style.setProperty(property, value);
  }
  function applyGlobalUiScale(factor) {
    let style2 = uiStateStyle(), declarations = uiScaleDeclarations(factor).map(([property, value]) => `${property}:${value}`).join(";");
    style2.textContent = `${UI_SCALE_SELECTOR}{${declarations}}`;
  }
  function applyUiStateClasses() {
    let state2 = requireUiState(), style2 = uiStateStyle();
    style2.classList.toggle("ehpeek-pointer-mouse", state2.pointer === "mouse"), style2.classList.toggle("ehpeek-site-e-hentai", state2.site === "e-hentai"), style2.classList.toggle("ehpeek-site-exhentai", state2.site === "exhentai");
  }
  function uiStateStyle() {
    let style2 = document.getElementById(UI_STATE_STYLE_ID);
    return style2 || (style2 = document.createElement("style"), style2.id = UI_STATE_STYLE_ID, (document.head ?? document.documentElement).append(style2)), style2;
  }
  function requireUiState() {
    if (!uiState)
      throw new Error("UI must be configured before it is initialized.");
    return uiState;
  }
  function uiScaleDeclarations(factor) {
    return [
      ...sizeScaleDeclarations("--ui-control-size", ehpeek_spectrum_ui_sizes_default.control, factor),
      ...hitSizeScaleDeclarations(ehpeek_spectrum_ui_sizes_default.control, factor),
      ...sizeScaleDeclarations("--ui-font-size", ehpeek_spectrum_ui_sizes_default.font, factor),
      ...sizeScaleDeclarations("--ui-icon-size", ehpeek_spectrum_ui_sizes_default.icon, factor),
      ...sizeScaleDeclarations("--ui-space", ehpeek_spectrum_ui_sizes_default.space, factor),
      ...sizeScaleDeclarations("--ui-radius", ehpeek_spectrum_ui_sizes_default.radius, factor)
    ];
  }
  function sizeScaleDeclarations(prefix, values, factor) {
    return Object.entries(values).map(([name, value]) => [
      `${prefix}-${name}`,
      `${scaledPixelValue(value, factor)}px`
    ]);
  }
  function hitSizeScaleDeclarations(values, factor) {
    return Object.entries(values).map(([name, value]) => [
      `--ui-hit-size-${name}`,
      `${Math.max(32, scaledPixelValue(value, factor))}px`
    ]);
  }
  function scaledPixelValue(value, factor) {
    return Math.round(pixelValue(value) * factor * 1e3) / 1e3;
  }
  function pixelValue(value) {
    let pixels = /^([\d.]+)px$/.exec(value)?.[1];
    if (pixels === void 0)
      throw new Error(`Expected a pixel UI size, received: ${value}`);
    return Number(pixels);
  }

  // src/eh/dom/core.ts
  var EHPEEK_ANCHOR_ATTRIBUTE = "data-ehpeek-anchor", EH_SYRINGE_IGNORE_SELECTOR = ".eh-syringe-ignore", mountedNodes = /* @__PURE__ */ new WeakMap();
  var managedBody = null, emptyDomApply = {}, emptyDomChilds = {};
  function defineDomNode() {
    return (selector, options = {}) => {
      let childs = options.childs ?? emptyDomChilds;
      return Object.assign({
        apply: options.apply ?? emptyDomApply,
        childs,
        kind: "node",
        selector
      }, childs);
    };
  }
  var query = defineDomNode(), anchor = defineDomNode(), area = defineDomNode(), button = defineDomNode(), cell = defineDomNode(), control = defineDomNode(), form = defineDomNode(), image = defineDomNode(), input = defineDomNode(), option = defineDomNode(), row = defineDomNode(), script = defineDomNode(), select = defineDomNode(), table = defineDomNode(), textarea = defineDomNode();
  function cls(name, options = {}) {
    return query(`.${name}`, options);
  }
  function id(name, options = {}) {
    return query(`#${name}`, options);
  }
  function tag(name, options = {}) {
    return defineDomNode()(name, options);
  }
  function domSelector(source) {
    return typeof source == "string" ? source : source.selector;
  }
  function originalPageNode(node) {
    return node.closest(EH_SYRINGE_IGNORE_SELECTOR) === null;
  }
  function anyDomNode() {
    return !0;
  }
  function createAnchor(name) {
    let selector = `[${EHPEEK_ANCHOR_ATTRIBUTE}="${CSS.escape(name)}"]`;
    if (document.querySelector(selector))
      return null;
    let anchor2 = document.createElement("div");
    return anchor2.setAttribute(EHPEEK_ANCHOR_ATTRIBUTE, name), DomNode.from(anchor2).inplace();
  }
  function createManagedElement(tagName, apply = emptyDomApply) {
    return ManagedDomNode.from(document.createElement(tagName), apply);
  }
  function documentBody() {
    return managedBody ?? (managedBody = DomNode.from(document.body).inplace()), managedBody;
  }
  var _node, _DomNode = class _DomNode {
    constructor(node) {
      __privateAdd(this, _node);
      __privateSet(this, _node, node);
    }
    static from(node) {
      return new _DomNode(node);
    }
    use(description) {
      return bindDom(description, () => [this]).bound;
    }
    one(source, filter = originalPageNode) {
      return Array.from(
        __privateGet(this, _node).querySelectorAll(domSelector(source)),
        _DomNode.from
      ).find(filter) ?? null;
    }
    all(source, filter = originalPageNode) {
      return Array.from(__privateGet(this, _node).querySelectorAll(domSelector(source))).map(_DomNode.from).filter(filter);
    }
    parent() {
      let parent = __privateGet(this, _node).parentElement;
      return parent ? _DomNode.from(parent) : null;
    }
    children() {
      return Array.from(__privateGet(this, _node).children, (child) => _DomNode.from(child));
    }
    closest(source) {
      let element = __privateGet(this, _node).closest(domSelector(source));
      return element ? _DomNode.from(element) : null;
    }
    matches(source) {
      return __privateGet(this, _node).matches(domSelector(source));
    }
    previous() {
      let previous = __privateGet(this, _node).previousElementSibling;
      return previous instanceof HTMLElement ? _DomNode.from(previous) : null;
    }
    form() {
      return __privateGet(this, _node).form ? _DomNode.from(__privateGet(this, _node).form) : null;
    }
    childElementCount() {
      return __privateGet(this, _node).childElementCount;
    }
    text() {
      return __privateGet(this, _node).textContent?.trim() ?? "";
    }
    attribute(name) {
      return __privateGet(this, _node).getAttribute(name);
    }
    hasAttribute(name) {
      return __privateGet(this, _node).hasAttribute(name);
    }
    attributeNames() {
      return __privateGet(this, _node).getAttributeNames();
    }
    hasClass(className2) {
      return __privateGet(this, _node).classList.contains(className2);
    }
    computedStyle() {
      return window.getComputedStyle(__privateGet(this, _node));
    }
    imageSize() {
      return {
        height: __privateGet(this, _node).naturalHeight || __privateGet(this, _node).height || Number(__privateGet(this, _node).getAttribute("height") || ""),
        width: __privateGet(this, _node).naturalWidth || __privateGet(this, _node).width || Number(__privateGet(this, _node).getAttribute("width") || "")
      };
    }
    inputValue() {
      return __privateGet(this, _node).value;
    }
    checked() {
      return __privateGet(this, _node).checked;
    }
    selected() {
      return __privateGet(this, _node).selected;
    }
    sameNode(other) {
      return __privateGet(this, _node) === __privateGet(other, _node);
    }
    observe(source, acquire, onManaged, options = { childList: !0, subtree: !0 }) {
      let seen = [], cleanups = [], scan = () => {
        for (let node of this.all(domSelector(source))) {
          if (seen.some((candidate) => candidate.sameNode(node)))
            continue;
          seen.push(node);
          let managed = acquire(node);
          if (!managed)
            continue;
          let cleanup = onManaged(managed);
          cleanup && cleanups.push(cleanup);
        }
      }, observer = new MutationObserver(scan);
      return scan(), observer.observe(__privateGet(this, _node), options), () => {
        observer.disconnect(), cleanups.forEach((cleanup) => cleanup());
      };
    }
    inplace(apply = emptyDomApply) {
      return ManagedDomNode.from(__privateGet(this, _node), apply);
    }
    move(apply = emptyDomApply) {
      let managed = this.inplace(apply);
      return managed.remove(), managed;
    }
    clone(applyOrDeep = emptyDomApply, deep = !0) {
      let apply = typeof applyOrDeep == "boolean" ? emptyDomApply : applyOrDeep, cloneDeep = typeof applyOrDeep == "boolean" ? applyOrDeep : deep;
      return ManagedDomNode.from(
        __privateGet(this, _node).cloneNode(cloneDeep),
        apply
      );
    }
  };
  _node = new WeakMap();
  var DomNode = _DomNode;
  function bindDom(description, scopes) {
    let children2 = [], invalidateChildren = () => {
      for (let child of children2)
        child.invalidate();
    }, definition = isDomDefinition(description) ? description : null, nodeController = definition ? bindDomNode(definition, scopes, invalidateChildren) : null, bound = nodeController?.bound ?? {}, childScopes = definition ? () => nodeController?.bound.all() ?? [] : scopes, childs = definition?.childs ?? description;
    for (let [name, child] of Object.entries(childs)) {
      if (name in bound)
        throw new Error(`Original DOM child name is reserved: ${name}`);
      let childController = bindDom(child, childScopes);
      children2.push(childController), Object.assign(bound, { [name]: childController.bound });
    }
    return {
      bound,
      invalidate: nodeController?.invalidate ?? invalidateChildren
    };
  }
  function isDomDefinition(description) {
    return "kind" in description && description.kind === "node";
  }
  function bindDomNode(description, scopes, invalidateChildren) {
    let cached, queryNodes = () => scopes().flatMap((scope) => scope.all(description.selector)), resolve = () => (cached ?? (cached = queryNodes()), cached);
    return {
      bound: {
        all: () => [...resolve()],
        clone: () => resolve()[0]?.clone(description.apply) ?? null,
        cloneAll: () => resolve().map((node) => node.clone(description.apply)),
        inplace: () => resolve()[0]?.inplace(description.apply) ?? null,
        inplaceAll: () => resolve().map((node) => node.inplace(description.apply)),
        move: () => resolve()[0]?.move(description.apply) ?? null,
        moveAll: () => resolve().map((node) => node.move(description.apply)),
        one: () => resolve()[0] ?? null,
        requery: () => (cached = queryNodes(), invalidateChildren(), [...cached])
      },
      invalidate: () => {
        cached = void 0, invalidateChildren();
      }
    };
  }
  var _apply, _node2, _ManagedDomNode = class _ManagedDomNode {
    constructor(element, apply) {
      __privateAdd(this, _apply);
      __privateAdd(this, _node2);
      __privateSet(this, _apply, apply), __privateSet(this, _node2, element), this.Component = () => __privateGet(this, _node2);
    }
    static from(element, apply = emptyDomApply) {
      return new _ManagedDomNode(element, apply);
    }
    apply(...names) {
      let classes = names.map((name) => {
        let className2 = __privateGet(this, _apply)[name];
        if (!className2)
          throw new Error(`Unknown original DOM application: ${name}`);
        return className2;
      });
      return __privateGet(this, _node2).classList.add(...classes), this;
    }
    all(source) {
      let apply = typeof source == "string" ? emptyDomApply : source.apply;
      return Array.from(
        __privateGet(this, _node2).querySelectorAll(domSelector(source)),
        (node) => _ManagedDomNode.from(node, apply)
      );
    }
    rect() {
      return __privateGet(this, _node2).getBoundingClientRect();
    }
    readAttribute(name) {
      return __privateGet(this, _node2).getAttribute(name);
    }
    imageSize() {
      return {
        height: __privateGet(this, _node2).naturalHeight || __privateGet(this, _node2).height || Number(__privateGet(this, _node2).getAttribute("height") || ""),
        width: __privateGet(this, _node2).naturalWidth || __privateGet(this, _node2).width || Number(__privateGet(this, _node2).getAttribute("width") || "")
      };
    }
    setAttributes(values) {
      for (let [name, value] of Object.entries(values))
        __privateGet(this, _node2).setAttribute(name, value);
      return this;
    }
    removeAttributes(...names) {
      for (let name of names)
        __privateGet(this, _node2).removeAttribute(name);
      return this;
    }
    addClasses(...names) {
      return __privateGet(this, _node2).classList.add(...names), this;
    }
    removeClasses(...names) {
      return __privateGet(this, _node2).classList.remove(...names), this;
    }
    replaceClasses(value) {
      return __privateGet(this, _node2).className = value, this;
    }
    styles(values, priority = "") {
      for (let [property, value] of Object.entries(values))
        __privateGet(this, _node2).style.setProperty(property, value, priority);
      return this;
    }
    removeStyles(...properties) {
      for (let property of properties)
        __privateGet(this, _node2).style.removeProperty(property);
      return this;
    }
    removeAllStyles() {
      return __privateGet(this, _node2).removeAttribute("style"), this;
    }
    attribute(name, value) {
      return __privateGet(this, _node2).setAttribute(name, value), this;
    }
    click() {
      __privateGet(this, _node2).click();
    }
    mount(view) {
      mountedNodes.get(__privateGet(this, _node2))?.(), __privateGet(this, _node2).replaceChildren(), markUiRoot(__privateGet(this, _node2)), mountedNodes.set(__privateGet(this, _node2), render(view, __privateGet(this, _node2)));
    }
    remove() {
      mountedNodes.get(__privateGet(this, _node2))?.(), mountedNodes.delete(__privateGet(this, _node2)), __privateGet(this, _node2).remove();
    }
    replaceWith(replacement) {
      __privateGet(this, _node2).replaceWith(
        replacement instanceof _ManagedDomNode ? __privateGet(replacement, _node2) : replacement
      );
    }
    before(sibling) {
      __privateGet(this, _node2).before(sibling instanceof _ManagedDomNode ? __privateGet(sibling, _node2) : sibling);
    }
    after(sibling) {
      __privateGet(this, _node2).after(sibling instanceof _ManagedDomNode ? __privateGet(sibling, _node2) : sibling);
    }
    append(...children2) {
      return __privateGet(this, _node2).append(...children2.map((child) => __privateGet(child, _node2))), this;
    }
    prepend(child) {
      __privateGet(this, _node2).prepend(child instanceof _ManagedDomNode ? __privateGet(child, _node2) : child);
    }
    setTextUnlessInput(text) {
      __privateGet(this, _node2) instanceof HTMLInputElement || (__privateGet(this, _node2).textContent = text);
    }
    setHidden(hidden) {
      return __privateGet(this, _node2).hidden = hidden, this;
    }
    replaceChildren(...children2) {
      __privateGet(this, _node2).replaceChildren(...children2.map((child) => child instanceof _ManagedDomNode ? __privateGet(child, _node2) : child));
    }
    listen(type, listener, options) {
      return __privateGet(this, _node2).addEventListener(type, listener, options), () => __privateGet(this, _node2).removeEventListener(type, listener, options);
    }
    observe(onChange, options = { childList: !0, subtree: !0 }) {
      let observer = new MutationObserver(onChange);
      return observer.observe(__privateGet(this, _node2), options), () => observer.disconnect();
    }
    focus() {
      __privateGet(this, _node2).focus();
    }
    scrollIntoView(options) {
      __privateGet(this, _node2).scrollIntoView(options);
    }
    isNode(node) {
      return __privateGet(this, _node2) === node;
    }
    contains(node) {
      return __privateGet(this, _node2).contains(node);
    }
    matches(source) {
      return __privateGet(this, _node2).matches(domSelector(source));
    }
    copyAttributesTo(target) {
      for (let attribute of Array.from(__privateGet(this, _node2).attributes))
        __privateGet(target, _node2).setAttribute(attribute.name, attribute.value);
    }
    setInputValue(value) {
      __privateGet(this, _node2).value = value;
    }
    inputValue() {
      return __privateGet(this, _node2).value;
    }
    setSelected(selected) {
      __privateGet(this, _node2).selected = selected;
    }
    dispatchInput() {
      __privateGet(this, _node2).dispatchEvent(new Event("input", { bubbles: !0 }));
    }
    mirrorContentTo(target) {
      let update = () => {
        target.replaceChildren(
          ...Array.from(__privateGet(this, _node2).childNodes, (node) => node.cloneNode(!0))
        );
        let language = __privateGet(this, _node2).getAttribute("lang");
        language ? target.setAttribute("lang", language) : target.removeAttribute("lang");
      };
      return update(), this.observe(update, {
        attributes: !0,
        attributeFilter: ["lang"],
        characterData: !0,
        childList: !0,
        subtree: !0
      });
    }
  };
  _apply = new WeakMap(), _node2 = new WeakMap();
  var ManagedDomNode = _ManagedDomNode;

  // src/eh/dom/domClass.ts
  var sharedApply = {
    coverlessSearchGrid: "ehpeek-expand-coverless-search-grid",
    constrainResultsToViewport: "ehpeek-constrain-results-to-viewport",
    galleryTagMenuItem: "ehpeek-layout-gallery-tag-menu-item",
    hideOriginalSearchAction: "ehpeek-hide-original-search-action",
    historyLabel: "ehpeek-prefix-read-history-label",
    liteSearchGrid: "ehpeek-layout-search-grid-lite",
    searchGrid: "ehpeek-layout-search-grid",
    searchResultColumns: "ehpeek-search-result-columns",
    stackSearchGridTags: "ehpeek-stack-search-grid-tags",
    tallSearchGridCover: "ehpeek-contain-tall-search-grid-cover"
  }, page = {
    footer: query("body > .dp"),
    html: tag("html", {
      apply: {
        constrainResults: sharedApply.constrainResultsToViewport,
        galleryTouchLayout: "ehpeek-touch-gallery-page",
        galleryWideLayout: "ehpeek-gallery-wide-layout-root"
      }
    }),
    body: tag("body", {
      apply: {
        constrainFavoritesNavigation: "ehpeek-constrain-favorites-navigation",
        constrainResults: sharedApply.constrainResultsToViewport,
        galleryTouchLayout: "ehpeek-touch-gallery-page",
        galleryWideLayout: "ehpeek-gallery-wide-layout-root",
        hidePreviewPageBars: "ehpeek-hide-original-preview-page-bars"
      }
    })
  }, common = {
    descendants: query("*"),
    galleryLink: anchor('a[href*="/g/"]'),
    image: image("img"),
    interactive: query(
      "a[href], button, input, select, textarea, label, [onclick]"
    ),
    links: anchor("a[href]"),
    scripts: script("script")
  }, ehSyringe = {
    root: cls("ehs-injected")
  }, myTags = {
    tags: id("usertags_outer", {
      childs: {
        items: query(":scope > [id^='usertag_']", {
          childs: {
            color: input("input[id^='tagcolor_']"),
            preview: query("[id^='tagpreview_'][title]")
          }
        })
      }
    }),
    options: option("#tagset_outer select option"),
    defaultColor: input("#tagcolor"),
    enabled: input("#tagset_enable")
  }, gallery = {
    actions: id("gd5", {
      apply: {
        expand: "ehpeek-expand-gallery-actions"
      },
      childs: {
        items: query("a, button, input[type='button'], input[type='submit']", {
          apply: {
            layout: "ehpeek-layout-gallery-action"
          }
        })
      }
    }),
    comments: id("cdiv", {
      apply: {
        touchScore: "ehpeek-enable-touch-comment-score"
      },
      childs: {
        showAll: anchor("#chd > :first-child a[href*='hc=1']"),
        score: cls("c5"),
        scoreComment: cls("c1", {
          childs: {
            details: query(".c7[id^='cvotes_']")
          }
        })
      }
    }),
    commentActions: id("postnewcomment"),
    favoriteDialog: {
      note: textarea("textarea[name='favnote']"),
      optionRow: query("div[style*='height']"),
      options: input("input[name='favcat']")
    },
    commentsAnchor: anchor('a[name="comments"]'),
    imagePage: {
      image: image("img#img"),
      links: anchor("a[href]")
    },
    info: {
      category: id("gdc", {
        childs: {
          appearance: query("[class*='ct']")
        }
      }),
      cover: id("gd1", {
        childs: {
          image: image("img", {
            apply: {
              fit: "ehpeek-fit-gallery-cover"
            }
          }),
          descendants: query("*")
        }
      }),
      details: id("gdd", {
        childs: {
          rows: row("tr", {
            childs: {
              cells: cell("td, th")
            }
          })
        }
      }),
      favorite: id("fav", {
        childs: {
          link: id("favoritelink"),
          titled: query("[title]")
        }
      }),
      hostFallback: id("gleft"),
      original: id("gmid"),
      rating: {
        actions: area('map[name="rating"] area'),
        count: id("rating_count"),
        image: id("rating_image"),
        label: id("rating_label"),
        rated: query(".irb, .irg, .irr")
      },
      tagMenu: id("tagmenu_act", {
        apply: {
          layout: "ehpeek-layout-gallery-tag-menu"
        },
        childs: {
          actions: anchor("a")
        }
      }),
      newTag: id("tagmenu_new", {
        apply: {
          layout: "ehpeek-layout-new-tag-form"
        },
        childs: {
          button: control("#newtagbutton"),
          field: input("#newtagfield"),
          form: form("form")
        }
      }),
      titleMain: id("gn"),
      titleSub: id("gj"),
      uploader: id("gdn", {
        childs: {
          link: anchor("a[href]")
        }
      })
    },
    preview: {
      description: cls("gpc"),
      imageLinks: anchor(
        "#gdt a[href], .gdtm a[href], .gdtl a[href], a[href*='/s/']"
      ),
      imageLinkHost: query("#gdt, .gdtm, .gdtl"),
      pageBarBottom: cls("ptb"),
      pageBarTop: cls("ptt"),
      thumbs: id("gdt", {
        apply: {
          swipe: "ehpeek-enable-preview-swipe-input"
        },
        childs: {
          images: image("img"),
          links: anchor("a[href]")
        }
      })
    },
    tagContainer: query("div.gt, div.gtl, div.gtw", {
      apply: {
        myTag: "ehpeek-color-my-tag"
      }
    }),
    tags: id("taglist", {
      childs: {
        links: anchor("a"),
        rows: row("tr", {
          childs: {
            namespace: query(".tc, td:first-child"),
            links: anchor("a")
          }
        })
      }
    })
  }, search = {
    controls: query("#toppane, .searchtext, .searchwarn, .searchnav, .ptt, .ptb"),
    displayMode: select("select[onchange*='inline_set=dm_']", {
      childs: {
        options: option("option")
      }
    }),
    favorites: {
      categories: query(".ido > .nosel", {
        apply: {
          hide: "ehpeek-hide-original-favorites-categories"
        },
        childs: {
          items: query(":scope > .fp, :scope > .fps", {
            childs: {
              indicator: cls("i")
            }
          })
        }
      }),
      input: input("input[name='f_search']"),
      selectedCategory: cls("fps")
    },
    input: input("#f_search, input[name='f_search']", {
      apply: {
        expand: "ehpeek-expand-search-input"
      }
    }),
    navigation: cls("searchnav", {
      childs: {
        first: anchor("a[id$='first'][href]"),
        previous: anchor("a[id$='prev'][href]"),
        next: anchor("a[id$='next'][href]"),
        last: anchor("a[id$='last'][href]"),
        links: anchor("a[href]")
      }
    }),
    navigationLink: anchor(
      ".searchnav a[id$='first'][href], .searchnav a[id$='prev'][href], .searchnav a[id$='next'][href], .searchnav a[id$='last'][href]"
    ),
    panel: {
      box: id("searchbox", {
        apply: {
          reset: "ehpeek-reset-search-box-layout"
        },
        childs: {
          advanced: id("advdiv", {
            apply: {
              expand: "ehpeek-expand-search-advanced-options"
            }
          }),
          categories: table("form > table", {
            apply: {
              layout: "ehpeek-layout-search-categories"
            }
          }),
          form: form("form", {
            apply: {
              stack: "ehpeek-stack-search-form"
            }
          })
        }
      }),
      clear: control("input[name='f_clear'], button[name='f_clear']", {
        apply: {
          hide: sharedApply.hideOriginalSearchAction
        }
      }),
      clearFallback: control("input[type='button'], button[type='button']", {
        apply: {
          hide: sharedApply.hideOriginalSearchAction
        }
      }),
      fileSearch: id("fsdiv", {
        apply: {
          expand: "ehpeek-expand-file-search"
        }
      }),
      optionLinks: anchor("a"),
      submit: control("input[name='f_apply'], button[name='f_apply']", {
        apply: {
          hide: sharedApply.hideOriginalSearchAction
        }
      }),
      submitFallback: control("input[type='submit'], button[type='submit']", {
        apply: {
          hide: sharedApply.hideOriginalSearchAction
        }
      })
    },
    rangeBar: id("rangebar"),
    removeHistory: control("[data-ehpeek-remove-history]"),
    results: cls("itg", {
      apply: {
        compactFavorites: "ehpeek-compact-all-favorites-results",
        containFavorites: "ehpeek-contain-favorites-results",
        containSearch: "ehpeek-contain-search-results",
        columns: sharedApply.searchResultColumns,
        grid: sharedApply.searchGrid,
        swipe: "ehpeek-enable-search-swipe-input"
      },
      childs: {
        body: query(":scope > tbody"),
        rows: row("tbody > tr", {
          apply: {
            coverless: sharedApply.coverlessSearchGrid
          },
          childs: {
            cover: query(":scope > .gl1e"),
            content: query(":scope > .gl2e", {
              childs: {
                detail: cls("gl4e", {
                  childs: {
                    tags: query(":scope > *", {
                      apply: {
                        stack: sharedApply.stackSearchGridTags
                      }
                    }),
                    title: query(":scope > .glink", {
                      apply: {
                        history: sharedApply.historyLabel
                      }
                    })
                  }
                }),
                metadata: cls("gl3e")
              }
            })
          }
        }),
        galleryLinks: anchor('a[href*="/g/"]'),
        links: anchor("a[href]"),
        titles: cls("glink", {
          apply: {
            history: "ehpeek-prefix-read-history-label"
          }
        })
      }
    }),
    resultText: cls("searchtext"),
    submit: control("input[name='f_apply'], button[name='f_apply']"),
    submitFallback: control("input[type='submit'], button[type='submit']")
  }, settings = {
    titleDefault: input("#tl_r"),
    titleJapanese: input("#tl_j")
  }, topBar = {
    galleryTitle: query("#gd2, h1"),
    navigation: id("nb", {
      childs: {
        links: anchor("a[href]", {
          apply: {
            layout: "ehpeek-layout-top-bar-menu-item"
          }
        })
      }
    })
  }, domClass = {
    common,
    ehSyringe,
    gallery,
    myTags,
    page,
    search,
    settings,
    topBar
  };

  // src/eh/dom/ehSyringe.ts
  var ehSyringe_exports = {};
  __export(ehSyringe_exports, {
    initialize: () => initialize
  });

  // locales/en.json
  var en_default = {
    metadata: {
      description: "A touch-optimized E-H/ExH viewer"
    },
    common: {
      actions: {
        apply: "Apply",
        close: "Close",
        confirm: "Confirm",
        current: "Current",
        default: "Default",
        submit: "Submit",
        zoomIn: "Zoom in",
        zoomOut: "Zoom out"
      },
      status: {
        failed: "Failed",
        loading: "Loading..."
      }
    },
    help: {
      title: "Help",
      sections: [
        {
          title: "Reader",
          items: [
            "**Tap** the center to show or hide the toolbar.",
            "**Swipe or scroll** in the reading direction; tap either side or use the **Arrow keys** to turn pages.",
            "In **Paged mode**, pull down or swipe sideways across the reading direction to open Scroll Preview.",
            "**Pinch** to zoom. With a mouse, **press and hold** an image or use **Ctrl/⌘ + wheel** to zoom; while zoomed, press and hold, double-click, or double-tap to exit."
          ]
        },
        {
          title: "Browse",
          items: [
            "Choose EhPeek or EhPeekLite from the **layout menu** to replace the original result layout.",
            "When **Enhance > Search Swipe** is enabled, **swipe** horizontally to change search result pages."
          ]
        },
        {
          title: "Gallery",
          items: [
            "When **Enhance > Preview Swipe** is enabled, **swipe** horizontally to change preview pages.",
            "The Page Bar in Gallery can be **dragged** to adjust the range."
          ]
        }
      ]
    },
    reader: {
      readingOptions: "Reading options",
      fullscreen: "Fullscreen",
      exitFullscreen: "Exit fullscreen",
      adjustScrollViewport: "Adjust Scroll viewport size",
      resizeScrollViewport: "Resize Scroll viewport",
      fit: "Fit",
      applyGlobally: "Set Default",
      pagedMode: "Paged mode",
      singlePageMode: "Single-page layout",
      doublePageMode: "Double-page layout",
      pairFirstAndSecondPages: "Pair 1+2",
      pairSecondAndThirdPages: "Pair 2+3",
      scrollMode: "Scroll mode",
      rightTapPrevious: `Right side action:
Previous page`,
      rightTapNext: `Right side action:
Next page`,
      directionRtl: `Reading direction:
 Right to left`,
      directionLtr: `Reading direction:
 Left to right`,
      directionTtb: `Reading direction:
 Top to bottom`,
      download: "Download",
      downloadHelpLabel: "Can't download?",
      downloadHelp: 'You may enable the browser download API in your userscript manager. For example, enable "Use browser download API" in Violentmonkey.',
      openImage: "Open image",
      displayedImageShort: "Displayed",
      originalImageShort: "Original",
      downloadDisplayedImage: "Displayed image",
      downloadOriginalImage: "Original image",
      originalImageSource: "Original source provided by E-Hentai",
      originalImageUnavailable: "Original image unavailable",
      startReading: "Read",
      continueReading: "Continue",
      endPage: "End",
      end: "End of gallery. Tap to exit.",
      reloadPage: "Reload page"
    },
    history: {
      actions: {
        clear: "Clear All",
        export: "Export",
        import: "Import",
        remove: "Delete"
      },
      clearConfirm: "Clear all reading history?",
      empty: "No reading history",
      exported: "History exported",
      importFailed: "History import failed",
      imported: "Imported {count} history entries",
      limit: "(max {limit})",
      visitedLabel: "VISITED",
      range: "{start}–{end} of {total} history entries",
      removeConfirm: "Remove this gallery from Read History?"
    },
    gallery: {
      pages: "Pages",
      notFavorited: "Not Favorited",
      rate: "Rate gallery",
      rateWithStars: "Rate gallery: {rating} stars",
      tagging: "Tagging",
      scrollPreview: "Scroll Preview",
      confirmScrollPreviewDirection: "Change Scroll Preview direction?",
      openScrollPreview: "Open full-screen Scroll Preview",
      scrollPreviewDirectionTtb: "Scroll Preview: top to bottom",
      scrollPreviewDirectionLtr: "Scroll Preview: left to right",
      scrollPreviewDirectionRtl: "Scroll Preview: right to left",
      favoriteTag: "Add My Tag",
      editFavoriteNote: "Edit Note",
      discardFavoriteNote: "Discard note edits?",
      removeFavoriteTag: "Remove My Tag",
      tagCollection: "Collection",
      tagBehavior: "Behavior",
      markTag: "Mark",
      watchTag: "Watch",
      hideTag: "Hide"
    },
    settings: {
      openSettings: "Settings",
      on: "On",
      off: "Off",
      discardChanges: "Discard unsaved settings changes?",
      general: "General",
      options: "Options",
      about: "About",
      licenses: "Licenses",
      readerLabel: "Reader",
      readerHelp: "Opens gallery images in EhPeek's reader",
      readerFullscreenLabel: "Open Reader in Fullscreen",
      readerFullscreenHelp: "Enters fullscreen when the Reader opens",
      exitReaderOnFullscreenExitLabel: "Close Reader on Fullscreen Exit",
      exitReaderOnFullscreenExitHelp: "Closes the Reader when fullscreen is exited",
      replacePreviewWithScrollLabel: "Embed Scroll Preview",
      replacePreviewWithScrollHelp: "Replaces the original gallery preview area with Scroll Preview",
      openGalleryInNewTabLabel: "Open Gallery in New Tab",
      openGalleryInNewTabHelp: "Opens gallery links in a new browser tab",
      uiControlsLabel: "UI Layout",
      uiScaleLabel: "UI Scale",
      leftHandedControlsLabel: "Left-handed controls",
      columnsLabel: "Two Columns",
      enhance: "Enhance",
      enhanceSearchLabel: "Search Swipe",
      enhanceSearchHelp: "Swipe between search result pages",
      enhanceThumbsLabel: "Preview Swipe",
      enhanceThumbsHelp: "Swipe between preview pages; makes the page bar draggable",
      myTagsLabel: "My Tags Color",
      myTagsHelp: "Colors my tags in galleries",
      historyLabel: "History",
      readHistoryLabel: "Read History",
      readHistoryHelp: "Adds galleries to Read History and remembers reading progress",
      includeUnreadHistoryLabel: "Include Unread History",
      includeUnreadHistoryHelp: "Records opened but unread galleries in Read History",
      searchHistoryLabel: "Search History",
      searchHistoryHelp: "Keeps a history of search keywords",
      touchUiLabel: "Touch UI",
      touchUiHelp: "Uses touch-friendly navigation UI"
    },
    search: {
      advancedOptions: "Advanced Options",
      categories: "Categories",
      fileSearch: "File Search"
    },
    errors: {
      imageNotFound: "Image not found",
      downloadFailed: "Download failed",
      loadFailed: "Load failed",
      imageLoadFailed: "Image load failed",
      searchPageContentNotFound: "Cannot find search page content"
    }
  };

  // locales/ja.json
  var ja_default = {
    metadata: {
      description: "タッチ操作向けの E-H/ExH リーダー"
    },
    common: {
      actions: {
        apply: "適用",
        close: "閉じる",
        confirm: "確定",
        current: "現在位置",
        default: "デフォルト",
        submit: "送信",
        zoomIn: "拡大",
        zoomOut: "縮小"
      },
      status: {
        failed: "失敗",
        loading: "読み込み中..."
      }
    },
    help: {
      title: "ヘルプ",
      sections: [
        {
          title: "リーダー",
          items: [
            "中央を**タップ**すると、ツールバーの表示と非表示を切り替えられます。",
            "閲覧方向に**スワイプまたはスクロール**します。左右をタップするか、**矢印キー**でもページをめくれます。",
            "**ページモード**では、下へ引くか閲覧方向と交差する向きにスワイプすると、スクロールプレビューを開けます。",
            "**ピンチ**で拡大縮小できます。マウスでは画像を**長押し**するか、**Ctrl/⌘ + ホイール**を使用します。拡大中に長押し、ダブルクリック、またはダブルタップすると終了します。"
          ]
        },
        {
          title: "ブラウズ",
          items: [
            "**レイアウトメニュー**から EhPeek または EhPeekLite を選択すると、元の検索結果レイアウトを置き換えます。",
            "**拡張 > 検索スワイプ**を有効にすると、**横方向にスワイプ**して検索結果ページを切り替えられます。"
          ]
        },
        {
          title: "ギャラリー",
          items: [
            "**拡張 > プレビュースワイプ**を有効にすると、**横方向にスワイプ**してプレビューページを切り替えられます。",
            "ギャラリーのページバーを**ドラッグ**して範囲を調整できます。"
          ]
        }
      ]
    },
    reader: {
      readingOptions: "閲覧オプション",
      fullscreen: "フルスクリーン",
      exitFullscreen: "フルスクリーンを終了",
      adjustScrollViewport: "スクロール表示領域のサイズを調整",
      resizeScrollViewport: "スクロール表示領域をリサイズ",
      fit: "フィット",
      applyGlobally: "デフォルトに設定",
      pagedMode: "ページモード",
      singlePageMode: "単ページレイアウト",
      doublePageMode: "見開きレイアウト",
      pairFirstAndSecondPages: "1+2ページを組み合わせる",
      pairSecondAndThirdPages: "2+3ページを組み合わせる",
      scrollMode: "スクロールモード",
      rightTapPrevious: `右側の操作:
前のページ`,
      rightTapNext: `右側の操作:
次のページ`,
      directionRtl: `閲覧方向:
 右から左`,
      directionLtr: `閲覧方向:
 左から右`,
      directionTtb: `閲覧方向:
 上から下`,
      download: "ダウンロード",
      downloadHelpLabel: "ダウンロードできませんか?",
      downloadHelp: "ユーザースクリプトマネージャーでブラウザーのダウンロード API を有効にできます。たとえば Violentmonkey では「ブラウザーのダウンロード API を使用」を有効にしてください。",
      openImage: "画像を開く",
      displayedImageShort: "表示中",
      originalImageShort: "オリジナル",
      downloadDisplayedImage: "表示中の画像",
      downloadOriginalImage: "オリジナル画像",
      originalImageSource: "E-Hentai が提供するオリジナル画像",
      originalImageUnavailable: "オリジナル画像は利用できません",
      startReading: "読む",
      continueReading: "続きから読む",
      endPage: "終了",
      end: "ギャラリーの最後です。タップして終了します。",
      reloadPage: "ページを再読み込み"
    },
    history: {
      actions: {
        clear: "すべて消去",
        export: "エクスポート",
        import: "インポート",
        remove: "削除"
      },
      clearConfirm: "閲覧履歴をすべて消去しますか?",
      empty: "閲覧履歴はありません",
      exported: "履歴をエクスポートしました",
      importFailed: "履歴のインポートに失敗しました",
      imported: "{count} 件の履歴をインポートしました",
      limit: "(最大 {limit} 件)",
      visitedLabel: "閲覧済み",
      range: "全 {total} 件中 {start}–{end} 件",
      removeConfirm: "このギャラリーを閲覧履歴から削除しますか?"
    },
    gallery: {
      pages: "ページ",
      notFavorited: "お気に入り未登録",
      rate: "ギャラリーを評価",
      rateWithStars: "ギャラリーを評価:{rating} 星",
      tagging: "タグ操作",
      scrollPreview: "スクロールプレビュー",
      confirmScrollPreviewDirection: "スクロールプレビューの方向を変更しますか?",
      openScrollPreview: "全画面スクロールプレビューを開く",
      scrollPreviewDirectionTtb: "スクロールプレビュー:上から下",
      scrollPreviewDirectionLtr: "スクロールプレビュー:左から右",
      scrollPreviewDirectionRtl: "スクロールプレビュー:右から左",
      favoriteTag: "マイタグを追加",
      editFavoriteNote: "メモを編集",
      discardFavoriteNote: "メモの変更を破棄しますか?",
      removeFavoriteTag: "マイタグを削除",
      tagCollection: "コレクション",
      tagBehavior: "動作",
      markTag: "マーク",
      watchTag: "ウォッチ",
      hideTag: "非表示"
    },
    settings: {
      openSettings: "設定",
      on: "オン",
      off: "オフ",
      discardChanges: "未適用の設定変更を破棄しますか?",
      general: "一般",
      options: "オプション",
      about: "情報",
      licenses: "ライセンス",
      readerLabel: "リーダー",
      readerHelp: "ギャラリー画像を EhPeek のリーダーで開きます",
      readerFullscreenLabel: "リーダーをフルスクリーンで開く",
      readerFullscreenHelp: "リーダーを開いたときにフルスクリーンにします",
      exitReaderOnFullscreenExitLabel: "フルスクリーン終了時にリーダーを閉じる",
      exitReaderOnFullscreenExitHelp: "フルスクリーンを終了するとリーダーを閉じます",
      replacePreviewWithScrollLabel: "スクロールプレビューを埋め込む",
      replacePreviewWithScrollHelp: "元のギャラリープレビュー領域をスクロールプレビューに置き換えます",
      openGalleryInNewTabLabel: "ギャラリーを新しいタブで開く",
      openGalleryInNewTabHelp: "ギャラリーリンクをブラウザーの新しいタブで開きます",
      uiControlsLabel: "UI レイアウト",
      uiScaleLabel: "UI スケール",
      leftHandedControlsLabel: "左手用コントロール",
      columnsLabel: "2 列",
      enhance: "拡張",
      enhanceSearchLabel: "検索スワイプ",
      enhanceSearchHelp: "スワイプして検索結果ページを切り替えます",
      enhanceThumbsLabel: "プレビュースワイプ",
      enhanceThumbsHelp: "スワイプしてプレビューページを切り替え、ページバーをドラッグ可能にします",
      myTagsLabel: "マイタグの色",
      myTagsHelp: "ギャラリー内のマイタグに色を付けます",
      historyLabel: "履歴",
      readHistoryLabel: "閲覧履歴",
      readHistoryHelp: "ギャラリーを閲覧履歴に追加し、閲覧進捗を保存します",
      includeUnreadHistoryLabel: "未読の履歴を含める",
      includeUnreadHistoryHelp: "開いたものの未読のギャラリーを閲覧履歴に記録します",
      searchHistoryLabel: "検索履歴",
      searchHistoryHelp: "検索キーワードの履歴を保存します",
      touchUiLabel: "タッチ UI",
      touchUiHelp: "タッチ操作に適したナビゲーション UI を使用します"
    },
    search: {
      advancedOptions: "詳細オプション",
      categories: "カテゴリ",
      fileSearch: "ファイル検索"
    },
    errors: {
      imageNotFound: "画像が見つかりません",
      downloadFailed: "ダウンロードに失敗しました",
      loadFailed: "読み込みに失敗しました",
      imageLoadFailed: "画像の読み込みに失敗しました",
      searchPageContentNotFound: "検索ページの内容が見つかりません"
    }
  };

  // locales/zh-CN.json
  var zh_CN_default = {
    metadata: {
      description: "为触屏优化的 E-H/ExH 阅读器"
    },
    common: {
      actions: {
        apply: "应用",
        close: "关闭",
        confirm: "确认",
        current: "当前位置",
        default: "默认",
        submit: "提交",
        zoomIn: "放大",
        zoomOut: "缩小"
      },
      status: {
        failed: "失败",
        loading: "加载中..."
      }
    },
    help: {
      title: "帮助",
      sections: [
        {
          title: "阅读器",
          items: [
            "**点击**中央区域可显示或隐藏工具栏。",
            "沿阅读方向**滑动或滚动**;点击两侧或使用**方向键**翻页。",
            "在**分页模式**下,下拉或沿阅读方向的垂直方向滑动可打开滚动预览。",
            "通过**双指捏合**缩放。使用鼠标时,可**长按**图像或使用 **Ctrl/⌘ + 滚轮**缩放;缩放后,长按、双击鼠标或双击屏幕可退出缩放。"
          ]
        },
        {
          title: "浏览",
          items: [
            "在**布局菜单**中选择 EhPeek 或 EhPeekLite,以替换原始结果布局。",
            "启用**增强 > 搜索滑动**后,可**水平滑动**切换搜索结果页。"
          ]
        },
        {
          title: "画廊",
          items: [
            "启用**增强 > 预览滑动**后,可**水平滑动**切换预览页。",
            "可以**拖动画廊中的页码条**来调整范围。"
          ]
        }
      ]
    },
    reader: {
      readingOptions: "阅读选项",
      fullscreen: "全屏",
      exitFullscreen: "退出全屏",
      adjustScrollViewport: "调整滚动视口大小",
      resizeScrollViewport: "调整滚动视口",
      fit: "适应",
      applyGlobally: "设为默认",
      pagedMode: "分页模式",
      singlePageMode: "单页布局",
      doublePageMode: "双页布局",
      pairFirstAndSecondPages: "组合第 1+2 页",
      pairSecondAndThirdPages: "组合第 2+3 页",
      scrollMode: "滚动模式",
      rightTapPrevious: `右侧操作:
上一页`,
      rightTapNext: `右侧操作:
下一页`,
      directionRtl: `阅读方向:
 从右向左`,
      directionLtr: `阅读方向:
 从左向右`,
      directionTtb: `阅读方向:
 从上向下`,
      download: "下载",
      downloadHelpLabel: "无法下载?",
      downloadHelp: "你可以在用户脚本管理器中启用浏览器下载 API。例如,在 Violentmonkey 中启用“使用浏览器下载 API”。",
      openImage: "打开图像",
      displayedImageShort: "当前显示",
      originalImageShort: "原图",
      downloadDisplayedImage: "当前显示的图像",
      downloadOriginalImage: "原始图像",
      originalImageSource: "由 E-Hentai 提供的原图来源",
      originalImageUnavailable: "原始图像不可用",
      startReading: "阅读",
      continueReading: "继续",
      endPage: "结束",
      end: "已到画廊末尾。点击退出。",
      reloadPage: "重新加载页面"
    },
    history: {
      actions: {
        clear: "全部清除",
        export: "导出",
        import: "导入",
        remove: "删除"
      },
      clearConfirm: "清除全部阅读历史?",
      empty: "没有阅读历史",
      exported: "历史记录已导出",
      importFailed: "历史记录导入失败",
      imported: "已导入 {count} 条历史记录",
      limit: "(最多 {limit} 条)",
      visitedLabel: "已访问",
      range: "第 {start}–{end} 条,共 {total} 条历史记录",
      removeConfirm: "从阅读历史中删除此画廊?"
    },
    gallery: {
      pages: "页",
      notFavorited: "未收藏",
      rate: "为画廊评分",
      rateWithStars: "为画廊评分:{rating} 星",
      tagging: "标签操作",
      scrollPreview: "滚动预览",
      confirmScrollPreviewDirection: "更改滚动预览方向?",
      openScrollPreview: "打开全屏滚动预览",
      scrollPreviewDirectionTtb: "滚动预览:从上向下",
      scrollPreviewDirectionLtr: "滚动预览:从左向右",
      scrollPreviewDirectionRtl: "滚动预览:从右向左",
      favoriteTag: "添加我的标签",
      editFavoriteNote: "编辑备注",
      discardFavoriteNote: "放弃备注修改?",
      removeFavoriteTag: "移除我的标签",
      tagCollection: "标签集",
      tagBehavior: "行为",
      markTag: "标记",
      watchTag: "关注",
      hideTag: "隐藏"
    },
    settings: {
      openSettings: "设置",
      on: "开",
      off: "关",
      discardChanges: "放弃尚未应用的设置修改?",
      general: "常规",
      options: "选项",
      about: "关于",
      licenses: "许可证",
      readerLabel: "阅读器",
      readerHelp: "使用 EhPeek 阅读器打开画廊图像",
      readerFullscreenLabel: "以全屏方式打开阅读器",
      readerFullscreenHelp: "打开阅读器时进入全屏",
      exitReaderOnFullscreenExitLabel: "退出全屏时关闭阅读器",
      exitReaderOnFullscreenExitHelp: "退出全屏后关闭阅读器",
      replacePreviewWithScrollLabel: "嵌入滚动预览",
      replacePreviewWithScrollHelp: "使用滚动预览替换原始画廊预览区域",
      openGalleryInNewTabLabel: "在新标签页中打开画廊",
      openGalleryInNewTabHelp: "在新的浏览器标签页中打开画廊链接",
      uiControlsLabel: "界面布局",
      uiScaleLabel: "界面缩放",
      leftHandedControlsLabel: "左手控制",
      columnsLabel: "双栏",
      enhance: "增强",
      enhanceSearchLabel: "搜索滑动",
      enhanceSearchHelp: "通过滑动切换搜索结果页",
      enhanceThumbsLabel: "预览滑动",
      enhanceThumbsHelp: "通过滑动切换预览页,并使页码条可拖动",
      myTagsLabel: "我的标签颜色",
      myTagsHelp: "在画廊中为我的标签着色",
      historyLabel: "历史记录",
      readHistoryLabel: "阅读历史",
      readHistoryHelp: "将画廊加入阅读历史并记住阅读进度",
      includeUnreadHistoryLabel: "包括未读记录",
      includeUnreadHistoryHelp: "将打开但尚未阅读的画廊记录到阅读历史",
      searchHistoryLabel: "搜索历史",
      searchHistoryHelp: "保存搜索关键词历史",
      touchUiLabel: "触控界面",
      touchUiHelp: "使用适合触控操作的导航界面"
    },
    search: {
      advancedOptions: "高级选项",
      categories: "分类",
      fileSearch: "文件搜索"
    },
    errors: {
      imageNotFound: "未找到图像",
      downloadFailed: "下载失败",
      loadFailed: "加载失败",
      imageLoadFailed: "图像加载失败",
      searchPageContentNotFound: "无法找到搜索页面内容"
    }
  };

  // src/i18n.ts
  var APP_LOCALES = ["en", "zh-CN", "ja"], APP_LOCALE_OPTIONS = [
    { label: "English", value: "en" },
    { label: "简体中文", value: "zh-CN" },
    { label: "日本語", value: "ja" }
  ], APP_LOCALE_SETTING_KEY = "ehpeek:language", DEFAULT_APP_LOCALE = "en", localeTexts = {
    en: en_default,
    "zh-CN": zh_CN_default,
    ja: ja_default
  }, storedLocale = GM_getValue(
    APP_LOCALE_SETTING_KEY,
    DEFAULT_APP_LOCALE
  ), appLocale = APP_LOCALES.includes(storedLocale) ? storedLocale : DEFAULT_APP_LOCALE, i18n_default = localeTexts[appLocale];

  // src/state/index.ts
  var touchUiDefault = window.matchMedia("(pointer: coarse)").matches, portraitUiScaleDefault = touchUiDefault ? "large" : "small", landscapeUiScaleDefault = touchUiDefault && Math.min(window.screen.width, window.screen.height) >= 600 ? "medium" : portraitUiScaleDefault, state = {
    app: {
      ehSyringeDetected: persisted("ehpeek:ehsyringe:detected", !1),
      locale: persistedEnum(
        APP_LOCALE_SETTING_KEY,
        DEFAULT_APP_LOCALE,
        APP_LOCALES
      ),
      leftHandedControls: persisted("ehpeek:left-handed-controls", !1),
      openGalleryInNewTab: persisted("ehpeek:open-gallery-in-new-tab", !1),
      portraitUiScale: persistedEnum("ehpeek:ui-scale:portrait", portraitUiScaleDefault, UI_SCALE_NAMES),
      landscapeUiScale: persistedEnum("ehpeek:ui-scale:landscape", landscapeUiScaleDefault, UI_SCALE_NAMES)
    },
    reader: {
      enabled: persisted("ehpeek:reader:enabled", !0),
      exitOnFullscreenExit: persisted("ehpeek:reader:exit-on-fullscreen-exit", !1),
      fullscreen: persisted("ehpeek:reader:fullscreen", !1),
      portraitControls: readerControls("portrait"),
      landscapeControls: readerControls("landscape"),
      scrollTtbScale: persisted("ehpeek:reader:scroll-ttb-scale", null),
      scrollHorizontalScale: persisted("ehpeek:reader:scroll-horizontal-scale", null)
    },
    gallery: {
      enhanceThumbs: persisted("ehpeek:enhance-thumbs:enabled", !0),
      replacePreviewWithScroll: persisted("ehpeek:scroll-preview:replace-original", !1),
      embeddedScrollPreviewSingleDirection: persisted(
        "ehpeek:gallery-scroll-preview:single-direction",
        "rtl"
      ),
      embeddedScrollPreviewColumnsDirection: persisted(
        "ehpeek:gallery-scroll-preview:columns-direction",
        "ttb"
      ),
      scrollPreviewDirection: persisted(
        "ehpeek:scroll-preview:direction",
        "ttb"
      ),
      myTags: persisted("ehpeek:my-tags:enabled", !0),
      myTagAppearances: localJson("ehpeek:my-tags", [], isMyTagAppearance),
      myTagSets: localJson("ehpeek:my-tag-sets", [], isMyTagSetOption),
      readHistory: persisted("ehpeek:read-history:enabled", !0),
      includeUnreadHistory: persisted("ehpeek:read-history:include-unread", !0),
      readHistoryCount: persisted("ehpeek:history-count", 0),
      titlePreference: localEnum(
        "ehpeek:gallery-title-preference",
        "main",
        ["main", "sub"]
      )
    },
    search: {
      enhance: persisted("ehpeek:enhance-search:enabled", !0),
      grid: localOptionalEnum(
        "ehpeek:search-grid",
        ["ehpeek", "ehpeek-lite"]
      ),
      history: persisted("ehpeek:search-history:enabled", !0),
      searchHistory: persisted("ehpeek:search:history", [])
    },
    touch: {
      enabled: persisted("ehpeek:touch-ui:enabled", touchUiDefault),
      portraitColumns: persisted("ehpeek:touch-ui:portrait-columns", !1),
      landscapeColumns: persisted("ehpeek:touch-ui:landscape-columns", !0)
    }
  };
  function currentReaderOrientation() {
    return window.matchMedia("(orientation: landscape)").matches ? "landscape" : "portrait";
  }
  function currentReaderControlsState() {
    return currentReaderOrientation() === "landscape" ? state.reader.landscapeControls : state.reader.portraitControls;
  }
  function loadSearchHistory() {
    let history = state.search.searchHistory.reload();
    return Array.isArray(history) ? history.filter((item) => typeof item == "string") : [];
  }
  function addSearchHistory(value) {
    let normalized = value.trim();
    if (!normalized)
      return loadSearchHistory();
    let history = [normalized, ...loadSearchHistory().filter((item) => item !== normalized)];
    return state.search.searchHistory.set(history), history;
  }
  function removeSearchHistory(value) {
    let history = loadSearchHistory().filter((item) => item !== value);
    return state.search.searchHistory.set(history), history;
  }
  function persisted(key, defaultValue) {
    let item = {
      defaultValue,
      value: GM_getValue(key, defaultValue),
      set(value) {
        item.value = value, GM_setValue(key, value);
      },
      reload() {
        return item.value = GM_getValue(key, defaultValue), item.value;
      }
    };
    return item;
  }
  function persistedEnum(key, defaultValue, values) {
    let read = () => {
      let value = GM_getValue(key, defaultValue);
      return values.includes(value) ? value : (GM_setValue(key, defaultValue), defaultValue);
    }, item = {
      defaultValue,
      value: read(),
      set(value) {
        item.value = value, GM_setValue(key, value);
      },
      reload() {
        return item.value = read(), item.value;
      }
    };
    return item;
  }
  function readerControls(orientation) {
    return {
      navigationMode: persisted(`ehpeek:reader:navigation-mode:${orientation}`, "scroll"),
      scrollDirection: persisted(`ehpeek:reader:scroll-direction:${orientation}`, "ttb"),
      pagedDirection: persisted(`ehpeek:reader:paged-direction:${orientation}`, "rtl"),
      pageLayout: persisted(`ehpeek:reader:page-layout:${orientation}`, "single"),
      rightTapAction: persisted(`ehpeek:reader:right-tap-action:${orientation}`, "previous")
    };
  }
  function normalizeReaderScrollSizeScale(scale) {
    return Number.isFinite(scale) ? Math.min(100, Math.max(1e-3, scale)) : 1;
  }
  function localOptionalEnum(key, values) {
    let read = () => {
      let value = window.localStorage.getItem(key);
      return values.includes(value) ? value : null;
    }, item = {
      defaultValue: null,
      value: read(),
      set(value) {
        item.value = value, value !== null ? window.localStorage.setItem(key, value) : window.localStorage.removeItem(key);
      },
      reload() {
        return item.value = read(), item.value;
      }
    };
    return item;
  }
  function localEnum(key, defaultValue, values) {
    let read = () => {
      let value = window.localStorage.getItem(key);
      return values.includes(value) ? value : defaultValue;
    }, item = {
      defaultValue,
      value: read(),
      set(value) {
        item.value = value, window.localStorage.setItem(key, value);
      },
      reload() {
        return item.value = read(), item.value;
      }
    };
    return item;
  }
  function localJson(key, defaultValue, valid) {
    let read = () => {
      try {
        let value = JSON.parse(window.localStorage.getItem(key) ?? "null");
        return Array.isArray(value) ? value.filter(valid) : defaultValue;
      } catch {
        return defaultValue;
      }
    }, item = {
      defaultValue,
      value: read(),
      set(value) {
        item.value = value, window.localStorage.setItem(key, JSON.stringify(value));
      },
      reload() {
        return item.value = read(), item.value;
      },
      clear() {
        item.value = defaultValue, window.localStorage.removeItem(key);
      },
      stored() {
        return window.localStorage.getItem(key) !== null;
      }
    };
    return item;
  }
  function isMyTagAppearance(value) {
    if (!value || typeof value != "object" || Array.isArray(value))
      return !1;
    let item = value;
    return typeof item.name == "string" && typeof item.backgroundColor == "string" && typeof item.color == "string" && typeof item.id == "string" && typeof item.tagSet == "string";
  }
  function isMyTagSetOption(value) {
    if (!value || typeof value != "object" || Array.isArray(value))
      return !1;
    let item = value;
    return typeof item.label == "string" && typeof item.selected == "boolean" && typeof item.value == "string";
  }

  // src/eh/dom/ehSyringe.ts
  var INJECTION_TIMEOUT_MS = 3e3;
  function initialize() {
    detect();
  }
  async function detect() {
    document.readyState === "loading" && await new Promise((resolve) => {
      document.addEventListener("DOMContentLoaded", () => resolve(), { once: !0 });
    });
    let detected = isInjected();
    return !detected && state.app.ehSyringeDetected.value && (await new Promise((resolve) => {
      window.setTimeout(resolve, INJECTION_TIMEOUT_MS);
    }), detected = isInjected()), state.app.ehSyringeDetected.value !== detected && state.app.ehSyringeDetected.set(detected), detected;
  }
  function isInjected() {
    return DomNode.from(document.documentElement).matches(domClass.ehSyringe.root);
  }

  // src/utils.ts
  function clamp(value, min, max) {
    return max < min ? min : Math.min(max, Math.max(min, value));
  }
  function normalizeUrl(url, baseUrl = window.location.href) {
    try {
      return new URL(url, baseUrl).href;
    } catch {
      return "";
    }
  }
  function normalizedAspectRatio(value, fallback) {
    return value && Number.isFinite(value) && value > 0 ? value : fallback;
  }
  function positiveNumber(value) {
    return value && Number.isFinite(value) && value > 0 ? value : null;
  }
  function stopEvent(event) {
    event.stopPropagation();
  }
  function registerGlobalStyle(id2, css) {
    if (!css || document.getElementById(id2))
      return;
    let style2 = document.createElement("style");
    style2.id = id2, style2.textContent = css, (document.head ?? document.documentElement).append(style2);
  }

  // src/eh/dom/gallery.ts
  function extractMyTagsPageData(root = document, tagSet) {
    let source = DomNode.from(root).use(domClass.myTags), tags = source.tags.one();
    if (!tags)
      throw new Error("The My Tags page could not be read.");
    let options = source.options.all().map((option2) => ({
      label: option2.text() || option2.inputValue(),
      selected: option2.selected(),
      value: option2.inputValue()
    })), activeTagSet = tagSet ?? options.find((option2) => option2.selected)?.value ?? "1", defaultColor = source.defaultColor.one()?.inputValue().trim() ?? "", output = [];
    for (let item of tags.all(domClass.myTags.tags.items)) {
      let preview = item.one(domClass.myTags.tags.items.preview), name = normalizeTagName(preview?.attribute("title") ?? "");
      if (!preview || !name)
        continue;
      let itemColor = item.one(domClass.myTags.tags.items.color)?.inputValue() ?? "", backgroundColor = normalizeTagColor(itemColor) || normalizeTagColor(defaultColor), id2 = item.attribute("id")?.match(/^usertag_(\d+)$/)?.[1] ?? "";
      id2 && output.push({
        name,
        backgroundColor,
        color: readableTagColor(backgroundColor),
        id: id2,
        tagSet: activeTagSet
      });
    }
    return {
      appearances: output,
      enabled: source.enabled.one()?.checked() ?? !0,
      options
    };
  }
  function normalizeTagName(value) {
    return value.trim().replace(/\s+/g, " ").toLowerCase();
  }
  function normalizeTagColor(value) {
    let color = value.trim();
    return /^#[\da-f]{6}$/i.test(color) ? color : "";
  }
  function readableTagColor(backgroundColor) {
    let red = Number.parseInt(backgroundColor.slice(1, 3), 16) / 255, green = Number.parseInt(backgroundColor.slice(3, 5), 16) / 255, blue = Number.parseInt(backgroundColor.slice(5, 7), 16) / 255, linear = (channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
    return 0.2126 * linear(red) + 0.7152 * linear(green) + 0.0722 * linear(blue) > 0.179 ? "#000000" : "#ffffff";
  }
  function mutateGalleryMyTags(appearances) {
    let byName = new Map(appearances.map((appearance) => [appearance.name, appearance])), source = DomNode.from(document).use(domClass.gallery), apply = () => {
      for (let tag2 of source.tags.links.requery()) {
        let name = galleryTagNameFromUrl(tag2.attribute("href") ?? ""), appearance = name ? byName.get(normalizeTagName(name)) : void 0;
        if (!appearance?.backgroundColor)
          continue;
        let container = tag2.closest(domClass.gallery.tagContainer);
        container && (container.inplace(domClass.gallery.tagContainer.apply).styles({
          "--ehpeek-my-tag-background": appearance.backgroundColor,
          "--ehpeek-my-tag-color": appearance.color
        }).apply("myTag"), tag2.inplace().setAttributes({
          "data-ehpeek-my-tag-id": appearance.id,
          "data-ehpeek-my-tag-set": appearance.tagSet
        }));
      }
    };
    return apply(), source.tags.inplace()?.observe(apply) ?? (() => {
    });
  }
  function manageGalleryContinueReadingButtonMount() {
    let managedHost = createManagedElement("div").replaceClasses("box-border w-full px-sm pt-sm pb-sm"), viewerOptions = DomNode.from(document).use(domClass.gallery).actions.inplace();
    return viewerOptions ? (viewerOptions.apply("expand").append(managedHost), managedHost) : (documentBody().append(managedHost), managedHost);
  }
  function manageGalleryPreview(root = document, baseUrl = window.location.href) {
    let source = DomNode.from(root).use(domClass.gallery.preview), currentUrl = new URL(baseUrl, window.location.href).href, currentIndex = previewPageIndex(currentUrl), pageDescriptionSource = source.description.one(), rangeText = pageDescriptionSource?.text() ?? "", rangeValues = rangeText.match(/([\d,]+)\s*-\s*([\d,]+)\D+([\d,]+)/)?.slice(1).map((value) => Number(value.replace(/,/g, ""))) ?? [], startImage = rangeValues[0], endImage = rangeValues[1], totalImages = rangeValues[2];
    if (startImage === void 0 || endImage === void 0 || totalImages === void 0 || !Number.isSafeInteger(startImage) || !Number.isSafeInteger(endImage) || !Number.isSafeInteger(totalImages) || startImage <= 0 || endImage <= 0 || totalImages <= 0 || endImage < startImage || totalImages < endImage)
      throw new Error("Cannot read the gallery preview image range.");
    let currentPageSize = endImage - startImage + 1, inferredFullPageSize = endImage === totalImages && currentIndex > 0 ? (totalImages - currentPageSize) / currentIndex : currentPageSize;
    if (!Number.isInteger(inferredFullPageSize) || inferredFullPageSize <= 0)
      throw new Error("Cannot determine the gallery preview page size.");
    let pageSize = inferredFullPageSize, maxIndex = Math.max(currentIndex, Math.ceil(totalImages / pageSize) - 1), seen = /* @__PURE__ */ new Set(), previewItems = source.imageLinks.all().flatMap((link) => {
      let url = normalizeUrl(link.attribute("href") || "", currentUrl), imagePage = extractPageType(url);
      if (imagePage.type !== "image" || seen.has(url))
        return [];
      seen.add(url);
      let image2 = link.one(domClass.common.image), size = image2?.imageSize(), backgroundStyle = (link.one("[style*='url(']") ?? link.closest("[style*='url(']"))?.attribute("style") ?? "", backgroundUrl = cssBackgroundUrl(backgroundStyle), imageSrc = image2?.attribute("src") || "", lazyImageSrc = image2?.attribute("data-src") || "", imageSource = imageSrc && !/blank\.gif(?:$|\?)/i.test(imageSrc) ? imageSrc : lazyImageSrc || imageSrc, thumbnail = backgroundUrl ? backgroundThumbnail(backgroundStyle, backgroundUrl, currentUrl, size) : imageThumbnail(imageSource, currentUrl, size);
      return [{
        aspectRatio: thumbnail.height / thumbnail.width,
        pageNum: imagePage.pageNum,
        pageUrl: url,
        thumbnail
      }];
    }).sort((left, right) => left.pageNum - right.pageNum), pages = previewItems.map((item) => ({
      aspectRatio: item.aspectRatio,
      pageNum: item.pageNum,
      url: item.pageUrl
    })), data = {
      currentIndex,
      currentUrl,
      descriptionText: rangeText,
      dominantAspectRatio: dominantPreviewAspectRatio(previewItems),
      endImage,
      maxIndex,
      pageSize,
      pages,
      previewItems,
      startImage,
      totalImages
    }, thumbsSource = source.thumbs.one(), pageBarTopSource = source.pageBarTop.one(), pageBarBottomSource = source.pageBarBottom.one(), createPageBarMount = (position) => createManagedElement("div").replaceClasses(
      `w-max max-w-full mx-auto overflow-x-auto touch-pan-y [-webkit-overflow-scrolling:touch] [&[data-dragging=true]]:select-none ${position === "top" ? "mt-2px mb-0" : "mt-0 mb-10px"}`
    ), elems = {
      mount: root === document && thumbsSource ? createManagedElement("div").replaceClasses("contents") : null,
      originalPageBarBottom: pageBarBottomSource?.inplace() ?? null,
      originalPageBarTop: pageBarTopSource?.inplace() ?? null,
      originalPageDescription: pageDescriptionSource?.inplace() ?? null,
      pageBarBottom: pageBarBottomSource ? createPageBarMount("bottom") : null,
      pageBarDescription: pageDescriptionSource && pageBarTopSource ? createManagedElement("div") : null,
      pageBarTop: pageBarTopSource ? createPageBarMount("top") : null,
      thumbImages: source.thumbs.images.inplaceAll(),
      thumbItems: thumbsSource?.children().map(
        (item) => root === document ? item.inplace() : item.move()
      ) ?? [],
      thumbs: root === document ? source.thumbs.inplace() : null
    };
    return elems.mount && elems.thumbs && elems.thumbs.before(elems.mount), { data, elems, handle: {
      /** Opens thumbnail image links in EhPeek Reader instead of original navigation. */
      interceptPreviewImageOpen(onOpen) {
        let handleClick = (event) => {
          let link = event.target instanceof Element ? DomNode.from(event.target).closest(domClass.common.links) : null, href = link?.attribute("href") ?? "";
          !link || extractPageType(href).type !== "image" || !link.one(domClass.common.image) && !link.closest(domClass.gallery.preview.imageLinkHost) || (event.preventDefault(), event.stopPropagation(), onOpen(normalizeUrl(href, currentUrl)));
        };
        return elems.thumbs?.listen("click", handleClick) ?? (() => {
        });
      },
      /** Makes thumbnail dragging available to the horizontal preview-page gesture. */
      ensurePreviewSwipeInput() {
        elems.thumbs?.apply("swipe");
        for (let image2 of elems.thumbImages)
          image2.setAttributes({ draggable: "false" });
      },
      /** Installs a fetched preview page into the currently visible thumbnail host. */
      replacePreviewThumbs(items) {
        elems.thumbs?.replaceChildren(...items);
      },
      /** Marks preview loading while retaining the currently visible thumbnails. */
      updatePreviewLoading(loading) {
        elems.thumbs?.attribute("aria-busy", String(loading));
      },
      /** Removes the original Preview UI after its data has been detached for Scroll Preview. */
      removeOriginalPreview() {
        elems.originalPageBarTop?.remove(), elems.originalPageBarBottom?.remove(), elems.originalPageDescription?.remove(), elems.thumbs?.remove();
      },
      /** Replaces both original page bars with mounts owned by EhPeek pagination. */
      installPreviewPageBars() {
        DomNode.from(document).use(domClass.page).body.inplace()?.apply("hidePreviewPageBars"), elems.originalPageBarTop && elems.pageBarTop && elems.originalPageBarTop.after(elems.pageBarTop), elems.originalPageBarBottom && elems.pageBarBottom && elems.originalPageBarBottom.after(elems.pageBarBottom), elems.originalPageDescription && elems.pageBarDescription && elems.pageBarTop && elems.pageBarTop.before(elems.pageBarDescription);
      },
      /** Brings the requested EhPeek page bar into view after preview navigation. */
      scrollPreviewPageBarIntoView(position) {
        (position === "top" ? elems.pageBarTop : elems.pageBarBottom)?.scrollIntoView({
          behavior: "smooth",
          block: position === "top" ? "start" : "end"
        });
      }
    } };
  }
  function dominantPreviewAspectRatio(items) {
    let buckets = /* @__PURE__ */ new Map(), dominant = null;
    for (let item of items) {
      let key = Math.round(item.aspectRatio * 10), bucket = buckets.get(key) ?? { count: 0, total: 0 };
      bucket.count += 1, bucket.total += item.aspectRatio, buckets.set(key, bucket), (!dominant || bucket.count > dominant.count) && (dominant = bucket);
    }
    if (!dominant)
      throw new Error("Cannot determine the gallery preview aspect ratio.");
    return dominant.total / dominant.count;
  }
  function cssBackgroundUrl(style2) {
    return style2.match(/url\(\s*(['"]?)(.*?)\1\s*\)/i)?.[2] ?? "";
  }
  function backgroundThumbnail(style2, url, baseUrl, fallbackSize) {
    let declaration = document.createElement("div").style;
    return declaration.cssText = style2, {
      backgroundPosition: declaration.backgroundPosition || "0 0",
      backgroundRepeat: declaration.backgroundRepeat || "no-repeat",
      backgroundSize: declaration.backgroundSize || "auto",
      height: cssPixelSize(declaration.height) ?? validThumbnailSize(fallbackSize?.height),
      kind: "background",
      url: normalizeUrl(url, baseUrl),
      width: cssPixelSize(declaration.width) ?? validThumbnailSize(fallbackSize?.width)
    };
  }
  function imageThumbnail(url, baseUrl, size) {
    return {
      backgroundPosition: "0 0",
      backgroundRepeat: "no-repeat",
      backgroundSize: "auto",
      height: validThumbnailSize(size?.height),
      kind: "image",
      url: url ? normalizeUrl(url, baseUrl) : "",
      width: validThumbnailSize(size?.width)
    };
  }
  function cssPixelSize(value) {
    if (!value.endsWith("px"))
      return null;
    let parsed = Number.parseFloat(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
  }
  function validThumbnailSize(value) {
    return value && Number.isFinite(value) && value > 0 ? value : 100;
  }
  async function loadGalleryPreviewPage(previewIndex, pageUrl) {
    let url = previewUrlForIndex(previewIndex, pageUrl), response = await requestPage(url);
    return manageGalleryPreview(response.document, response.url);
  }
  function extractImageGalleryPage(root = document) {
    for (let link of DomNode.from(root).use(domClass.common).links.all()) {
      let page2 = extractPageType(normalizeUrl(link.attribute("href") || ""));
      if (page2.type === "gallery")
        return page2;
    }
    return null;
  }
  async function loadEhImagePage(page2) {
    let response = await requestPage(page2.url), imagePage = DomNode.from(response.document).use(domClass.gallery.imagePage), image2 = imagePage.image.one(), imageUrl = normalizeUrl(
      image2?.attribute("src") || image2?.attribute("data-src") || "",
      page2.url
    );
    if (!imageUrl)
      throw new Error(i18n_default.errors.imageNotFound);
    let numberAttribute = (name) => {
      let value = Number(image2?.attribute(name));
      return Number.isFinite(value) && value > 0 ? value : null;
    };
    return {
      height: numberAttribute("height"),
      imageUrl,
      originalImageUrl: imagePage.links.all().map((link) => normalizeUrl(link.attribute("href") || "", page2.url)).find(isFullImageUrl) ?? null,
      width: numberAttribute("width")
    };
  }

  // src/eh/dom/galleryInfo.ts
  var GALLERY_CATEGORY_FLAGS = {
    ct1: 1,
    ct2: 2,
    ct3: 4,
    ct4: 8,
    ct5: 16,
    ct6: 32,
    ct7: 64,
    ct8: 128,
    ct9: 256,
    cta: 512
  };
  function extractGalleryHistoryInfo() {
    let page2 = DomNode.from(document), source = page2.use(domClass.gallery.info), category = source.category.one(), categoryClass = (category?.one(domClass.gallery.info.category.appearance)?.attribute("class") ?? category?.attribute("class") ?? "").split(/\s+/).find((className2) => /^ct[1-9a]$/.test(className2)), rows = source.details.rows.all().map((detailRow) => detailRow.all(domClass.gallery.info.details.rows.cells).slice(1).map((detailCell) => detailCell.text()).filter(Boolean).join(" ")), postedAt = page2.one(domClass.gallery.info.details, anyDomNode)?.all(domClass.gallery.info.details.rows.cells, anyDomNode).map((cell2) => parseGalleryPostedAt(cell2.text())).find((value) => value !== void 0), ratingMatch = (page2.all(domClass.common.scripts).map((pageScript) => pageScript.text()).find((script2) => script2.includes("display_rating")) ?? "").match(/\bdisplay_rating\s*=\s*(-?\d+(?:\.\d+)?)/), rating = Number(ratingMatch?.[1]), cover = source.cover.one(), coverUrl = source.cover.image.one()?.attribute("src") ?? "";
    if (!coverUrl && cover)
      for (let node of [cover, ...cover.all(domClass.common.descendants)]) {
        let match = node.computedStyle().backgroundImage.match(/url\(["']?(.+?)["']?\)/);
        if (match?.[1]) {
          coverUrl = match[1];
          break;
        }
      }
    return {
      category: category?.text() || void 0,
      categoryClass,
      coverUrl: coverUrl || void 0,
      language: rows[3] || void 0,
      postedAt,
      rating: ratingMatch && Number.isFinite(rating) ? rating : void 0,
      title: source.titleMain.one()?.text() || void 0,
      titleSub: source.titleSub.one()?.text() || void 0,
      uploader: source.uploader.one()?.text() || void 0
    };
  }
  function parseGalleryPostedAt(value) {
    let match = value?.match(
      /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})(?::(\d{2}))?$/
    );
    if (!match)
      return;
    let [, year, month, day, hour, minute, second = "0"] = match;
    return Date.UTC(
      Number(year),
      Number(month) - 1,
      Number(day),
      Number(hour),
      Number(minute),
      Number(second)
    );
  }
  function manageGalleryInfo(preview) {
    let mount = createAnchor("gallery-info");
    if (!mount)
      return null;
    let page2 = DomNode.from(document), gallery2 = page2.use(domClass.gallery), source = gallery2.info, original = source.original.one(), host = original?.parent() ?? source.hostFallback.one()?.parent() ?? null;
    if (!original || !host)
      return null;
    let readMeta = () => {
      let rows = source.details.rows.all().map((detailRow) => {
        let cells = detailRow.all(domClass.gallery.info.details.rows.cells);
        return {
          label: cells[0]?.text() ?? "",
          value: cells.slice(1).map((cell2) => cell2.text()).filter(Boolean).join(" ")
        };
      });
      return {
        favorited: rows[6]?.value ? [rows[6].label, rows[6].value].filter(Boolean).join(" ") : void 0,
        fileSize: rows[4]?.value,
        language: rows[3]?.value,
        parent: rows[1]?.value,
        posted: rows[0]?.value
      };
    }, readCategory = (node) => {
      let style2 = node?.computedStyle();
      return {
        "background-color": style2?.backgroundColor ?? "",
        "background-image": style2?.backgroundImage ?? "",
        "border-color": style2?.borderColor ?? "",
        color: style2?.color ?? ""
      };
    }, readCategoryUrl = (node) => {
      let categoryClass = node?.attribute("class")?.split(/\s+/).find((className2) => className2 in GALLERY_CATEGORY_FLAGS);
      if (!categoryClass)
        return null;
      let url = new URL("/", window.location.href);
      return url.searchParams.set(
        "f_cats",
        String(1023 - GALLERY_CATEGORY_FLAGS[categoryClass])
      ), url.href;
    }, readCoverUrl = (cover2, source2) => {
      let direct = source2?.attribute("src") ?? "";
      if (direct)
        return direct;
      for (let node of cover2 ? [cover2, ...cover2.all(domClass.common.descendants)] : []) {
        let match = node.computedStyle().backgroundImage.match(/url\(["']?(.+?)["']?\)/);
        if (match?.[1])
          return match[1];
      }
      return "";
    }, readFavorite = (element, scripts2) => {
      let displayed = element?.one(domClass.gallery.info.favorite.link)?.text() || element?.one(domClass.gallery.info.favorite.titled)?.attribute("title")?.trim() || "", slot = displayed.match(/(?:^|\D)([0-9])(?:\D|$)/)?.[1], favorited = slot !== void 0 || /^favorited$/i.test(displayed), match = (scripts2.find(
        (item) => item.includes("popbase") && item.includes("addfav")
      ) ?? "").match(
        /popbase\s*=\s*base_url\s*\+\s*"gallerypopups\.php\?gid=(\d+)&t=([^"]+)&act="/
      );
      return {
        actionUrl: match ? `/gallerypopups.php?gid=${match[1]}&t=${match[2]}&act=addfav` : "",
        color: slot === void 0 ? null : `var(--color-site-favorite-${slot})`,
        favorited,
        label: favorited ? displayed : i18n_default.gallery.notFavorited
      };
    }, readRating = (count, image2, labelNode, scripts2) => {
      let label = labelNode?.text() ?? "", match = (scripts2.find((item) => item.includes("display_rating")) ?? "").match(/\bdisplay_rating\s*=\s*(-?\d+(?:\.\d+)?)/), scriptValue = Number(match?.[1]), value = match && Number.isFinite(scriptValue) ? scriptValue : null;
      return label && value !== null ? {
        count: count?.text() ?? "",
        label,
        rated: image2?.matches(domClass.gallery.info.rating.rated) ?? !1,
        value
      } : null;
    }, readActions = () => gallery2.actions.items.all().filter((node) => {
      let href = node.attribute("href")?.trim() ?? "";
      return node.hasAttribute("onclick") || !!(href && href !== "#" && !/^javascript:/i.test(href));
    }).slice(0, 6), readTag = (tag2) => {
      let label = tag2.text() || tag2.attribute("ehs-tag")?.trim() || tag2.attribute("title")?.trim() || "", href = tag2.attribute("href") ?? "", name = galleryTagNameFromUrl(href);
      if (!label || !name || !href)
        return null;
      let container = tag2.closest(domClass.gallery.tagContainer) ?? tag2, tagStyle = tag2.computedStyle(), containerStyle = container.computedStyle(), myTagId = tag2.attribute("data-ehpeek-my-tag-id"), myTagSet = tag2.attribute("data-ehpeek-my-tag-set");
      return {
        data: {
          appearance: {
            backgroundColor: containerStyle.backgroundColor,
            borderColor: containerStyle.borderColor,
            color: tagStyle.color
          },
          label,
          myTag: myTagId && myTagSet ? { id: myTagId, tagSet: myTagSet } : null,
          name,
          url: href
        },
        source: tag2
      };
    }, readTagGroups = () => {
      let rows = gallery2.tags.rows.all();
      return rows.length > 0 ? rows.map((row2) => ({
        namespace: row2.one(domClass.gallery.tags.rows.namespace)?.text().replace(/:$/, "") || "tag",
        tags: row2.all(domClass.gallery.tags.rows.links).map(readTag).filter((tag2) => tag2 !== null).slice(0, 30)
      })).filter((group) => group.tags.length > 0) : [{
        namespace: "tag",
        tags: gallery2.tags.links.all().map(readTag).filter((tag2) => tag2 !== null).slice(0, 60)
      }].filter((group) => group.tags.length > 0);
    }, favoriteColor = (value) => {
      let slot = value.match(/^(?:fav)?([0-9])$/i)?.[1] ?? value.match(/^favorites?\s+([0-9])$/i)?.[1];
      return slot === void 0 ? null : `var(--color-site-favorite-${slot})`;
    }, readFavoriteDialog = (doc, favorited) => {
      let dialog = DomNode.from(doc).use(domClass.gallery.favoriteDialog), options = dialog.options.all().map((favoriteInput) => {
        let row2 = favoriteInput.closest(domClass.gallery.favoriteDialog.optionRow), value = favoriteInput.inputValue();
        return {
          color: favoriteColor(value),
          label: row2?.text().replace(/\s+/g, " ") || value,
          selected: favorited && favoriteInput.checked(),
          value
        };
      });
      return {
        note: dialog.note.one()?.inputValue() ?? "",
        options
      };
    }, manageTagGroups = () => readTagGroups().map((group) => ({
      namespace: group.namespace,
      tags: group.tags.map(({ data: tag2, source: source2 }) => ({
        ...tag2,
        contentSource: source2.inplace()
      }))
    })), meta = readMeta(), category = source.category.one(), categoryStyle = source.category.appearance.one() ?? category, cover = source.cover.one(), coverSource = source.cover.image.one(), favorite = source.favorite.one(), ratingCount = source.rating.count.one(), ratingImage = source.rating.image.one(), ratingLabel = source.rating.label.one(), ratingActions = source.rating.actions.all(), uploader = source.uploader.link.one(), newTagButton = source.newTag.button.one(), newTagField = source.newTag.field.one(), newTagForm = source.newTag.form.one(), scripts = page2.all(domClass.common.scripts).map((pageScript) => pageScript.text()), actionSources = readActions(), tagContentSources = [], tagGroups = readTagGroups().map((group) => ({
      namespace: group.namespace,
      tags: group.tags.map(({ data: tag2, source: source2 }) => {
        let contentSourceIndex = tagContentSources.push(source2) - 1;
        return { ...tag2, contentSourceIndex };
      })
    })), data = {
      category: category?.text() ?? "",
      categoryAppearance: readCategory(categoryStyle),
      categoryUrl: readCategoryUrl(categoryStyle),
      favorite: readFavorite(favorite, scripts),
      rating: readRating(ratingCount, ratingImage, ratingLabel, scripts),
      summary: [
        meta.language,
        preview?.totalImages ? `${preview.totalImages} ${i18n_default.gallery.pages.toLowerCase()}` : void 0,
        meta.fileSize,
        meta.favorited,
        meta.posted ?? meta.parent
      ].filter((value) => !!value).slice(0, 6).map((value) => ({ value })),
      tagGroups,
      titleMain: source.titleMain.one()?.text() ?? "",
      titleSub: source.titleSub.one()?.text() ?? "",
      uploader: uploader?.text() ?? "",
      uploaderUrl: uploader?.attribute("href") ?? ""
    }, coverUrl = readCoverUrl(cover, coverSource), managedCover = coverUrl ? source.cover.image.clone()?.replaceClasses("").apply("fit") ?? createManagedElement("img", { fit: "ehpeek-fit-gallery-cover" }).apply("fit") : null;
    managedCover?.removeAttributes("id", "style", "width", "height").setAttributes({ alt: "", decoding: "async", loading: "eager", src: coverUrl });
    let managedNewTag = newTagButton && newTagField && newTagForm ? source.newTag.move()?.apply("layout") ?? null : null, hostApply = { hide: "ehpeek-hide-original-gallery-info" };
    managedNewTag?.setHidden(!1).removeStyles("display");
    let elems = {
      actionItems: actionSources.map((item) => item.move(domClass.gallery.actions.items.apply).apply("layout")),
      cover: managedCover,
      host: host.inplace(hostApply).apply("hide"),
      mount,
      newTag: managedNewTag,
      ratingActions: ratingActions.map((action) => action.inplace()),
      tagContents: tagContentSources.map((source2) => source2.inplace()),
      tagList: gallery2.tags.inplace(),
      tagMenuAction: source.tagMenu.inplace()
    }, selectedTagSource = null, activateTagMenu = (source2) => {
      let stopNavigation = source2.listen("click", (event) => {
        event.preventDefault();
      }, { once: !0 });
      source2.click(), stopNavigation();
    };
    return { data, elems, handle: {
      /** Normalizes the original cover for GalleryInfoPanel's responsive layout. */
      /** Hides original GalleryInfo children and installs the component mount. */
      installGalleryInfoPanel() {
        elems.host.prepend(elems.mount);
      },
      /** Loads the original favorite categories and note for EhPeek's favorite modal. */
      async loadGalleryFavoriteDialog(actionUrl, favorited) {
        let response = await requestPage(actionUrl);
        return readFavoriteDialog(response.document, favorited);
      },
      /** Submits a tag to the chosen My Tags collection and validates the response. */
      async submitFavoriteTag(tag2, tagSet, mode) {
        let response = await addMyTag(tag2.name, tagSet, mode);
        return extractMyTagsPageData(response.document, tagSet);
      },
      /** Keeps component tag groups synchronized with original-page tag updates. */
      observeGalleryTagGroups(onChange) {
        return elems.tagList?.observe(() => {
          gallery2.tags.rows.requery(), gallery2.tags.links.requery(), onChange(manageTagGroups());
        }) ?? (() => {
        });
      },
      /** Activates E-H's original rating area and lets its page script submit the vote. */
      submitGalleryRating(value) {
        let rating = Math.round(value * 2);
        if (rating < 1 || rating > 10)
          throw new RangeError("Gallery rating must be between 0.5 and 5 stars.");
        let action = elems.ratingActions[rating - 1];
        if (!action)
          throw new Error("Gallery rating action is unavailable.");
        action.click();
      },
      /** Removes the selected tag from its stored My Tags collection. */
      async removeFavoriteTag(tag2) {
        if (!tag2.myTag)
          throw new Error("The tag is not in My Tags.");
        let response = await deleteMyTag(tag2.myTag.id, tag2.myTag.tagSet);
        return extractMyTagsPageData(response.document, tag2.myTag.tagSet);
      },
      /** Opens E-H's original tag actions and only adapts their presentation. */
      openGalleryTagMenu(tag2) {
        if (!elems.tagMenuAction)
          throw new Error("Gallery tag actions are unavailable.");
        activateTagMenu(tag2.contentSource), elems.newTag?.setHidden(!1).removeStyles("display");
        let actions = elems.tagMenuAction.all(domClass.gallery.info.tagMenu.actions);
        if (actions.length === 0)
          throw activateTagMenu(tag2.contentSource), elems.newTag?.setHidden(!1).removeStyles("display"), new Error("Gallery tag actions could not be opened.");
        selectedTagSource = tag2.contentSource, elems.tagMenuAction.apply("layout"), actions.find((action) => action.readAttribute("onclick")?.includes("toggle_tagmenu"))?.remove();
      },
      /** Closes E-H's selected tag without replacing its action DOM. */
      closeGalleryTagMenu() {
        selectedTagSource && activateTagMenu(selectedTagSource), elems.newTag?.setHidden(!1).removeStyles("display"), selectedTagSource = null;
      },
      /** Updates the Gallery favorite state through the original site endpoint. */
      updateGalleryFavorite
    } };
  }
  function mutateGalleryTouchLayout() {
    let page2 = DomNode.from(document).use(domClass.page), html = page2.html.inplace(), body = page2.body.inplace();
    if (!html || !body)
      throw new Error("Gallery page layout is unavailable.");
    html.apply("galleryTouchLayout"), body.apply("galleryTouchLayout");
  }
  function mutateGalleryWideLayout(info, preview, initiallyEnabled, replacesOriginalPreview) {
    let page2 = DomNode.from(document).use(domClass.page), source = DomNode.from(document).use(domClass.gallery), html = page2.html.inplace(), body = page2.body.inplace(), footer = page2.footer.inplace(), comments = source.comments.inplace(), commentsAnchor = source.commentsAnchor.inplace(), pageBarTopHost = source.preview.pageBarTop.one()?.parent()?.inplace() ?? null, pageBarBottomHost = source.preview.pageBarBottom.one()?.parent()?.inplace() ?? null, previewMount = preview.elems.mount, thumbs = preview.elems.thumbs;
    if (!html || !body || !comments || !previewMount || !thumbs)
      return null;
    let leftNodes = [info.elems.host, commentsAnchor, comments].filter((node) => node !== null), rightNodes = (replacesOriginalPreview ? [previewMount] : [pageBarTopHost, previewMount, thumbs, pageBarBottomHost]).filter((node) => node !== null), layout = null, positions = [], enabled = initiallyEnabled, update = () => {
      if (enabled && !layout) {
        if (layout = createAnchor("gallery-wide-layout")?.replaceClasses("ehpeek-touch-gallery-layout") ?? null, !layout)
          return;
        window.scrollTo(0, 0), html.apply("galleryWideLayout"), body.apply("galleryWideLayout");
        let left = createManagedElement("div").replaceClasses("ehpeek-touch-gallery-layout-left"), right = createManagedElement("div").replaceClasses("ehpeek-touch-gallery-layout-right");
        positions = [...leftNodes, ...rightNodes, footer].filter((node) => node !== null).map((node) => {
          let marker = createManagedElement("span").setHidden(!0);
          return node.before(marker), { marker, node };
        }), info.elems.host.before(layout), layout.append(left, right, ...footer ? [footer] : []), left.append(...leftNodes), right.append(...rightNodes);
        return;
      }
      if (!enabled && layout) {
        for (let { marker, node } of positions)
          marker.after(node), marker.remove();
        positions = [], layout.remove(), layout = null, html.removeClasses("ehpeek-gallery-wide-layout-root"), body.removeClasses("ehpeek-gallery-wide-layout-root");
      }
    };
    return update(), {
      updateEnabled(value) {
        enabled = value, update();
      }
    };
  }
  function manageGalleryCommentsTouch(onLoadError) {
    let gallery2 = DomNode.from(document).use(domClass.gallery), comments = gallery2.comments.inplace();
    comments?.apply("touchScore");
    let showAllSource = gallery2.comments.showAll.one(), showAll = showAllSource?.inplace() ?? null, showAllButton = showAllSource?.clone() ?? null, showAllUrl = showAll?.readAttribute("href"), loadingAll = !1;
    if (comments && showAll && showAllUrl) {
      showAllButton && gallery2.commentActions.inplace()?.append(showAllButton);
      let loadAll = (event) => {
        event.preventDefault(), !loadingAll && (loadingAll = !0, showAll.setAttributes({ "aria-busy": "true" }), showAllButton?.setAttributes({ "aria-busy": "true" }), requestPage(showAllUrl).then((response) => {
          let loaded = DomNode.from(response.document).use(domClass.gallery.comments).one();
          if (!loaded)
            throw new Error("Cannot read all gallery comments");
          comments.replaceChildren(...loaded.children().map((child) => child.move())), manageGalleryCommentsTouch(onLoadError);
        }).catch(onLoadError).finally(() => {
          loadingAll = !1, showAll.removeAttributes("aria-busy"), showAllButton?.removeAttributes("aria-busy");
        }));
      };
      showAll.listen("click", loadAll), showAllButton?.listen("click", loadAll);
    }
    let items = gallery2.comments.score.all().filter((trigger) => trigger.attribute("data-ehpeek-touch-comment-score") !== "true").map((trigger) => ({
      trigger,
      details: trigger.closest(domClass.gallery.comments.scoreComment)?.one(domClass.gallery.comments.scoreComment.details) ?? null
    })).filter((item) => item.details !== null).map(({ trigger, details }) => ({
      details: details.inplace(),
      detailsId: details.attribute("id") ?? "",
      expanded: !1,
      trigger: trigger.inplace()
    })), setExpanded = (item, expanded) => {
      item.expanded = expanded, item.trigger.attribute("aria-expanded", String(expanded)), item.details.attribute("aria-hidden", String(!expanded));
    };
    for (let item of items) {
      item.trigger.removeAttributes("onmouseover", "onmouseout", "onclick").setAttributes({
        "data-ehpeek-touch-comment-score": "true",
        role: "button",
        tabindex: "0",
        "aria-controls": item.detailsId
      }), setExpanded(item, !1);
      let toggle = (event) => {
        event.preventDefault(), event.stopImmediatePropagation();
        let shouldExpand = !item.expanded;
        for (let candidate of items)
          setExpanded(candidate, candidate === item && shouldExpand);
      };
      item.trigger.listen("click", toggle), item.trigger.listen("keydown", (event) => {
        (event.key === "Enter" || event.key === " ") && toggle(event);
      });
    }
  }

  // src/eh/dom/search.ts
  function createReadHistoryGridRow(item, titlePreference) {
    let info = item.info, metadataItems = [], appendMetadata = (value, className2) => {
      if (!value)
        return;
      let element = createManagedElement("div").replaceClasses(className2);
      element.setTextUnlessInput(value), metadataItems.push(element);
    };
    if (info?.category && info.categoryClass) {
      let category = createManagedElement("div").replaceClasses(`cn ${info.categoryClass} ehpeek-search-meta-category`);
      category.setTextUnlessInput(info.category), metadataItems.push(category);
    }
    if (appendMetadata(
      info?.postedAt === void 0 ? void 0 : new Date(info.postedAt).toISOString().slice(0, 16).replace("T", " "),
      "ehpeek-search-meta-posted"
    ), info?.rating !== void 0) {
      let rounded = Math.round(info.rating * 2) / 2, rating = createManagedElement("div").replaceClasses("ir ehpeek-search-meta-rating").styles({
        "background-position": `${-16 * (5 - Math.ceil(rounded))}px ${Number.isInteger(rounded) ? -1 : -21}px`,
        opacity: "1"
      });
      metadataItems.push(rating);
    }
    appendMetadata(info?.uploader, "ehpeek-search-meta-uploader"), appendMetadata(
      item.totalPages ? `${item.totalPages} ${i18n_default.gallery.pages.toLowerCase()}` : void 0,
      "ehpeek-search-meta-pages"
    );
    let historyLabel = item.currentPage > 0 ? `${item.currentPage} / ${item.totalPages ?? "?"}` : i18n_default.history.visitedLabel, removeButton = createManagedElement("button").setAttributes({ type: "button", "data-ehpeek-remove-history": "true" }).replaceClasses(
      "relative z-2 ui-hit-min-h-lg ui-py-xs ui-px-lg ui-rounded-md border border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] ehp-color-site-text font-inherit textsize-md font-700 text-center cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]"
    );
    removeButton.setTextUnlessInput(i18n_default.history.actions.remove);
    let historyActions = createManagedElement("div").replaceClasses("ehpeek-read-history-actions box-border flex items-center justify-end ui-gap-md ui-pr-sm ui-pb-xs").append(removeButton), titleText = titlePreference === "sub" ? info?.titleSub || info?.title : info?.title || info?.titleSub, galleryHref = new URL(
      `/g/${item.galleryId}/${item.token}/`,
      window.location.href
    ).href, row2 = createManagedElement("tr").setAttributes({
      "data-ehpeek-read-history": item.currentPage > 0 ? "reading" : "visited"
    }), thumbnailCell = createManagedElement("td").replaceClasses("gl1e"), thumbnail = createManagedElement("div"), image2 = info?.coverUrl ? createManagedElement("img").setAttributes({
      alt: titleText ?? "",
      loading: "lazy",
      src: info.coverUrl
    }) : null;
    image2 ? thumbnail.append(
      createManagedElement("a").attribute("href", galleryHref).append(image2)
    ) : thumbnailCell.setHidden(!0), thumbnailCell.append(thumbnail);
    let contentCell = createManagedElement("td").replaceClasses("gl2e"), galleryLink = createManagedElement("a").attribute("href", galleryHref), detail = createManagedElement("div").replaceClasses("gl4e h-full"), title = createManagedElement("div").replaceClasses(`glink ${sharedApply.historyLabel}`).setAttributes({ "data-ehpeek-history-label": historyLabel });
    title.setTextUnlessInput(titleText ?? ""), title.setHidden(!titleText);
    let metadata = createManagedElement("div").replaceClasses("gl3e");
    return metadata.append(...metadataItems), galleryLink.append(detail.append(title)), contentCell.append(
      createManagedElement("div").replaceClasses("h-full").append(metadata, galleryLink)
    ), row2.append(thumbnailCell, contentCell), {
      coverImage: image2,
      detail,
      galleryHref,
      galleryLink,
      metadata,
      row: row2,
      stackTags: !1,
      tags: [historyActions],
      title,
      titleText: titleText ?? "",
      withoutCover: !image2
    };
  }
  function manageReadHistoryPage(items, titlePreference, mode = "ehpeek-lite") {
    let page2 = DomNode.from(document), resultList = page2.use(domClass.search).results.one(), navigationTopMount = createAnchor("read-history-navigation-top"), navigationBottomMount = createAnchor("read-history-navigation-bottom");
    if (!resultList || !navigationTopMount || !navigationBottomMount)
      return null;
    let grids = manageReadHistoryGrids({
      items,
      mode,
      source: resultList,
      titlePreference
    });
    grids.elems.resultList.before(navigationTopMount), grids.elems.resultList.after(navigationBottomMount);
    for (let control2 of page2.all(domClass.search.controls, anyDomNode))
      control2.inplace().remove();
    let handle = {
      /** Replaces the visible History rows without navigating away from the current document. */
      updateReadHistoryItems: grids.handle.updateItems,
      /** Reports explicit removal requests without exposing History rows. */
      listenForReadHistoryRemoval: grids.handle.listenForItemRemoval,
      /** Keeps navigation anchored to the corresponding edge after an in-page page change. */
      scrollReadHistoryPage(position) {
        (position === "bottom" ? navigationBottomMount : navigationTopMount).scrollIntoView({
          behavior: "smooth",
          block: position === "bottom" ? "end" : "start"
        });
      },
      /** Switches the History result list between one and two result columns. */
      updateResultColumns(enabled) {
        enabled ? grids.elems.resultList.addClasses(sharedApply.searchResultColumns) : grids.elems.resultList.removeClasses(sharedApply.searchResultColumns);
      }
    };
    return {
      elems: {
        navigationBottomMount,
        navigationTopMount,
        resultList: grids.elems.resultList
      },
      handle
    };
  }
  function manageSearchResults() {
    let source = DomNode.from(document).use(domClass.search), resultSource = source.results.one();
    if (!resultSource)
      return null;
    let data = {
      nextUrl: source.navigation.next.one()?.attribute("href") ?? null,
      previousUrl: source.navigation.previous.one()?.attribute("href") ?? null
    }, resultHost = resultSource.parent()?.inplace() ?? null, elems = {
      resultList: resultSource.inplace(domClass.search.results.apply),
      searchInput: source.input.inplace()
    };
    return { data, elems, handle: {
      /** Routes the original pagination controls through the active page owner. */
      interceptSearchNavigation(onNavigate) {
        let handleClick = (event) => {
          let url = (event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.navigationLink) : null)?.attribute("href") ?? null;
          url && (event.preventDefault(), event.stopPropagation(), onNavigate(url));
        };
        return document.addEventListener("click", handleClick, !0), () => document.removeEventListener("click", handleClick, !0);
      },
      /** Replaces the current result page for enhanced swipe navigation. */
      async loadSearchPage(url) {
        let response = await requestPage(url);
        if (!replaceSearchPageContent(response.document))
          throw new Error(i18n_default.errors.searchPageContentNotFound);
        window.history.pushState(window.history.state, "", url);
      },
      /** Returns enhanced Search navigation to its input, or the page top when absent. */
      scrollSearchPageToInput() {
        elems.searchInput ? elems.searchInput.scrollIntoView({ block: "start", behavior: "auto" }) : window.scrollTo({ top: 0, behavior: "auto" });
      },
      /** Exposes result loading state without removing the current result list. */
      updateSearchLoading(busy) {
        busy ? elems.resultList.setAttributes({ "aria-busy": "true" }) : elems.resultList.removeAttributes("aria-busy");
      },
      /** Switches the EhPeek result list between one and two result columns. */
      updateResultColumns(enabled) {
        enabled ? elems.resultList.apply("columns") : elems.resultList.removeClasses(sharedApply.searchResultColumns);
      },
      /** Prevents result content from stealing a horizontal swipe gesture. */
      ensureSearchSwipeInput() {
        elems.resultList.apply("swipe");
      },
      /** Applies new-tab semantics at activation time so replaced result pages need no rebinding. */
      listenGalleryLinksOpenInNewTab() {
        if (!resultHost)
          return () => {
          };
        let handleClick = (event) => {
          let link = event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.results.galleryLinks) : null;
          link?.closest(domClass.search.results) && link.inplace().setAttributes({ target: "_blank", rel: "noopener noreferrer" });
        };
        return resultHost.listen("click", handleClick, !0);
      }
    } };
  }
  function manageSearchTextInput() {
    let inputSource = DomNode.from(document).use(domClass.search).input.one(), formSource = inputSource?.form() ?? null, submitSource = formSource?.one(domClass.search.submit) ?? inputSource?.parent()?.one(domClass.search.submitFallback) ?? null;
    if (!inputSource || !submitSource)
      return null;
    let elems = {
      form: formSource?.inplace() ?? null,
      input: inputSource.inplace(),
      submit: submitSource.inplace()
    };
    return { data: { value: elems.input.inputValue() }, elems, handle: {
      /** Connects the original input to EhPeek's history and suggestion overlay. */
      listenSearchHistoryOverlay(callbacks, overlay) {
        let update = () => callbacks.onInput(
          elems.input.inputValue(),
          document.activeElement === elems.input.Component()
        ), submitValue = () => callbacks.onSubmit(elems.input.inputValue()), positionChange = (event) => {
          let target = event.target;
          target instanceof Node && overlay()?.contains(target) || callbacks.onPositionChange();
        }, outsidePointer = (event) => {
          let target = event.target;
          target instanceof Node && (elems.input.isNode(target) || overlay()?.contains(target)) || callbacks.onOutsidePointer();
        }, disconnect = [
          elems.input.listen("input", update),
          elems.input.listen("focus", callbacks.onFocus),
          elems.input.listen("pointerdown", callbacks.onFocus),
          elems.input.listen("keydown", callbacks.onKeyDown),
          elems.submit.listen("click", submitValue),
          ...elems.form ? [elems.form.listen("submit", submitValue)] : []
        ];
        return document.addEventListener("pointerdown", outsidePointer, !0), document.addEventListener("scroll", positionChange, !0), window.addEventListener("resize", callbacks.onPositionChange), () => {
          disconnect.forEach((cleanup) => cleanup()), document.removeEventListener("pointerdown", outsidePointer, !0), document.removeEventListener("scroll", positionChange, !0), window.removeEventListener("resize", callbacks.onPositionChange);
        };
      },
      /** Locates the overlay directly below the original search input. */
      readSearchOverlayPosition() {
        let rect = elems.input.rect();
        return { left: rect.left, top: rect.bottom, width: rect.width };
      },
      /** Commits a history or suggestion choice through the original input events. */
      applySearchSelection(value) {
        elems.input.setInputValue(value), elems.input.dispatchInput(), elems.input.focus(), elems.input.Component().setSelectionRange(value.length, value.length);
      }
    } };
  }
  function manageReadHistoryGrids(options) {
    let resultList = createManagedElement("table").replaceClasses("itg"), body = createManagedElement("tbody"), visibleRows = [];
    resultList.append(body).addClasses(
      "overscroll-x-contain",
      "touch-pan-y",
      "[&[data-dragging=true]]:select-none"
    ), options.source.inplace().replaceWith(resultList);
    let updateItems = (items) => {
      visibleRows = items.map((item) => ({
        item,
        row: createReadHistoryGridRow(item, options.titlePreference)
      })), body.replaceChildren(...visibleRows.map(({ row: row2 }) => row2.row)), manageEhPeekGrid(
        resultList,
        visibleRows.map(({ row: row2 }) => row2),
        options.mode
      );
    };
    return updateItems(options.items), {
      elems: { resultList },
      handle: {
        updateItems,
        listenForItemRemoval(callback) {
          let itemForTarget = (target) => target instanceof Node ? visibleRows.find(({ row: row2 }) => row2.row.contains(target))?.item ?? null : null;
          return resultList.listen("click", (event) => {
            let item = (event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.removeHistory) : null) ? itemForTarget(event.target) : null;
            item && (event.preventDefault(), event.stopPropagation(), callback(item));
          });
        }
      }
    };
  }
  function manageSearchGrids(mode) {
    let source = DomNode.from(document).use(domClass.search), resultList = source.results.one();
    if (!resultList)
      return;
    let rows = source.results.rows.all().map(manageSearchGridRow).filter((row2) => row2 !== null);
    manageEhPeekGrid(
      resultList.inplace(),
      rows,
      mode
    );
    function manageSearchGridRow(row2) {
      let thumbnailCell = row2.one(domClass.search.results.rows.cover), contentCell = row2.one(domClass.search.results.rows.content), detail = contentCell?.one(domClass.search.results.rows.content.detail), metadata = contentCell?.one(domClass.search.results.rows.content.metadata);
      if (!thumbnailCell || !contentCell || !detail || !metadata)
        return null;
      let title = detail.one(domClass.search.results.rows.content.detail.title), parent = detail.parent(), galleryLink = parent?.matches(domClass.common.links) ? parent : null, tags = detail.children().filter((element) => !title?.sameNode(element)), coverImage = thumbnailCell.one(domClass.common.image), metadataItems = metadata.children(), category = metadataItems.find((item) => item.matches(':is(.cn, .cs, [class*="ct"])')), posted = metadataItems.find((item) => item.matches('[id^="posted_"]')), rating = metadataItems.find((item) => item.matches(".ir")), uploader = metadataItems.find((item) => item.one('a[href*="/uploader/"]') !== null), download = metadataItems.find((item) => item.matches(".gldown")), pages = download?.previous(), knownMetadata = [category, posted, rating, uploader, pages, download], extraMetadata = metadataItems.filter((item) => !knownMetadata.some((known) => known?.sameNode(item))), metadataFields = [
        [category, "ehpeek-search-meta-category"],
        [pages, "ehpeek-search-meta-pages"],
        [posted, "ehpeek-search-meta-posted"],
        [rating, "ehpeek-search-meta-rating"],
        [uploader, "ehpeek-search-meta-uploader"],
        [download, "ehpeek-search-meta-download"]
      ];
      for (let [field, className2] of metadataFields)
        field?.inplace().addClasses(className2);
      for (let field of extraMetadata)
        field.inplace().addClasses("ehpeek-search-meta-extra");
      return {
        coverImage: coverImage?.inplace() ?? null,
        detail: detail.inplace(),
        galleryHref: galleryLink?.attribute("href") ?? null,
        galleryLink: galleryLink?.inplace() ?? null,
        metadata: metadata.inplace(),
        row: row2.inplace(),
        stackTags: !0,
        tags: tags.map((item) => item.inplace()),
        title: title?.inplace() ?? null,
        titleText: title?.text() ?? "",
        withoutCover: !1
      };
    }
  }
  function manageEhPeekGrid(resultList, rows, mode = "ehpeek") {
    let liteTagPrefixes = {
      female: "f",
      male: "m",
      mixed: "x"
    };
    resultList.addClasses(sharedApply.searchGrid), DomNode.from(resultList.Component()).parent()?.inplace().addClasses("[container-type:inline-size]"), mode === "ehpeek-lite" && resultList.addClasses(sharedApply.liteSearchGrid);
    for (let row2 of rows)
      row2.row.addClasses(
        ...row2.withoutCover ? [sharedApply.coverlessSearchGrid] : []
      ), manageSearchGridCover(row2), manageEhPeekGridContent(row2);
    function manageSearchGridCover(source) {
      if (!source.coverImage)
        return;
      let update = () => {
        let size = source.coverImage?.imageSize();
        !!(size && size.width > 0 && size.height / size.width > 4) ? source.row.addClasses(sharedApply.tallSearchGridCover) : source.row.removeClasses(sharedApply.tallSearchGridCover);
      };
      update(), source.coverImage.listen("load", update, { once: !0 });
    }
    function manageEhPeekGridContent(source) {
      let { detail, galleryLink, metadata, row: row2, tags, title } = source;
      if (galleryLink && title && source.galleryHref) {
        let titleLink = createManagedElement("a").attribute("href", source.galleryHref).replaceClasses("block min-w-0 ehp-color-site-text no-underline");
        titleLink.append(title), galleryLink.before(detail), galleryLink.remove(), detail.replaceChildren(titleLink, metadata, ...tags), ensureEhPeekGridRowNavigation(
          row2,
          titleLink,
          source.galleryHref,
          source.titleText
        );
      } else title && title.after(metadata);
      if (source.stackTags)
        for (let tag2 of tags)
          tag2.addClasses(sharedApply.stackSearchGridTags), mode === "ehpeek-lite" && markLiteSearchTags(tag2);
    }
    function markLiteSearchTags(container) {
      for (let tag2 of container.all(
        ':is(.gt, .gtl, .gtw)[title*=":"]'
      )) {
        let namespace = tag2.readAttribute("title")?.split(":", 1)[0]?.trim(), prefix = namespace ? liteTagPrefixes[namespace.toLowerCase()] : null;
        prefix && tag2.attribute("data-ehpeek-lite-prefix", prefix);
      }
    }
    function ensureEhPeekGridRowNavigation(row2, galleryLink, galleryHref, title) {
      row2.attribute("data-ehpeek-pressable", "true");
      let overlay = createManagedElement("a", {
        cover: "ehpeek-cover-search-grid-row"
      }).attribute("href", galleryHref).attribute("aria-label", title || "Open gallery").replaceClasses("hidden search-panel-compact:block absolute inset-0 z-1").apply("cover");
      row2.append(overlay).listen("click", (event) => {
        (event.target instanceof Element ? DomNode.from(event.target) : null)?.closest(domClass.common.interactive) || galleryLink.click();
      });
    }
  }
  function mutateSearchReadHistoryAppearance(readProgressForGallery) {
    let resultList = DomNode.from(document).use(domClass.search).results.one();
    if (!resultList)
      return;
    let items = (resultList.one(domClass.search.results.body) ?? resultList).children();
    for (let item of items) {
      let galleryLinks = item.all(domClass.search.results.galleryLinks), galleryLink = galleryLinks.find((link) => !!link.text()) ?? galleryLinks[0];
      if (!galleryLink)
        continue;
      let identity = galleryIdentityFromUrl(galleryLink.attribute("href") ?? "");
      if (!identity)
        continue;
      let progress = readProgressForGallery(identity.galleryId, identity.token);
      if (!progress)
        continue;
      (item.one(domClass.search.results.titles) ?? galleryLink).inplace(domClass.search.results.titles.apply).setAttributes({
        "data-ehpeek-history-label": progress.pageNum > 0 ? `${progress.pageNum} / ${progress.totalPages ?? "?"}` : i18n_default.history.visitedLabel
      }).apply("history"), item.inplace().setAttributes({
        "data-ehpeek-read-history": progress.pageNum > 0 ? "reading" : "visited"
      });
    }
  }
  function mutateSearchGridModeSelect(selected, onEhPeekSelect, onOriginalSelect) {
    let selects = DomNode.from(document).use(domClass.search).displayMode.all();
    for (let source of selects) {
      let select2 = source.inplace();
      for (let { label, value } of [
        { label: "EhPeek", value: "ehpeek" },
        { label: "EhPeekLite", value: "ehpeek-lite" }
      ]) {
        let option2 = source.all(domClass.search.displayMode.options).find((item) => item.inputValue() === value)?.inplace() ?? null;
        option2 || (option2 = createManagedElement("option").attribute("value", value), option2.setTextUnlessInput(label), select2.append(option2)), option2.setSelected(selected === value);
      }
      source.attribute("data-ehpeek-grid-mode") !== "true" && (select2.attribute("data-ehpeek-grid-mode", "true"), select2.listen("change", (event) => {
        let value = select2.inputValue();
        if (value !== "ehpeek" && value !== "ehpeek-lite") {
          onOriginalSelect();
          return;
        }
        event.preventDefault(), event.stopImmediatePropagation(), onEhPeekSelect(value);
      }, !0));
    }
  }
  function replaceSearchPageContent(doc) {
    let currentList = DomNode.from(document).use(domClass.search).results.one(), incomingList = DomNode.from(doc).use(domClass.search).results.one();
    if (!currentList || !incomingList || !refreshSearchRangeBar(doc))
      return !1;
    replaceSearchResultText(doc), replaceSearchNavigationBars(doc);
    let current = currentList.inplace(), importedList = incomingList.clone();
    return current.replaceWith(importedList), !0;
  }
  function refreshSearchRangeBar(doc) {
    let current = DomNode.from(document).use(domClass.search).rangeBar.one(), incomingPage = DomNode.from(doc), incoming = incomingPage.use(domClass.search).rangeBar.one();
    if (!current && !incoming)
      return !0;
    if (!current || !incoming)
      return !1;
    let script2 = incomingPage.all(domClass.common.scripts).map((item) => item.text()).find((item) => item.includes("build_rangebar()")), rangeUrl = script2?.match(/\brangeurl\s*=\s*["']([^"']*)["']/)?.[1], rangeMin = Number(script2?.match(/\brangemin\s*=\s*(-?\d+)/)?.[1]), rangeMax = Number(script2?.match(/\brangemax\s*=\s*(-?\d+)/)?.[1]), rangeSpan = Number(script2?.match(/\brangespan\s*=\s*(-?\d+)/)?.[1]);
    if (rangeUrl === void 0 || !Number.isFinite(rangeMin) || !Number.isFinite(rangeMax) || !Number.isFinite(rangeSpan))
      return !1;
    let items = [];
    if (rangeSpan > 0)
      for (let index = 0; index < 99; index += rangeSpan) {
        let marker = createManagedElement("div");
        if ((index === 98 && rangeMin === 99 || index >= rangeMin && index <= rangeMax) && marker.attribute("data-inrange", "1"), !rangeUrl) {
          items.push(marker);
          continue;
        }
        let href = index === 0 ? rangeUrl : `${rangeUrl}${rangeUrl.includes("?") ? "&" : "?"}range=${index}`;
        items.push(createManagedElement("a").attribute("href", href).append(marker));
      }
    return current.inplace().replaceChildren(...items), !0;
  }
  function replaceSearchNavigationBars(doc) {
    let currentBars = DomNode.from(document).use(domClass.search).navigation.all(), incomingBars = DomNode.from(doc).use(domClass.search).navigation.all(), count = Math.min(currentBars.length, incomingBars.length);
    for (let index = 0; index < count; index += 1) {
      let currentSource = currentBars[index], incomingSource = incomingBars[index];
      if (!currentSource || !incomingSource)
        continue;
      let current = currentSource.inplace(), incoming = incomingSource.clone();
      current.replaceWith(incoming);
    }
  }
  function replaceSearchResultText(doc) {
    let current = DomNode.from(document).use(domClass.search).resultText.one(), incoming = DomNode.from(doc).use(domClass.search).resultText.one();
    if (!current || !incoming)
      return;
    let currentElement = current.inplace(), incomingElement = incoming.clone();
    currentElement.replaceWith(incomingElement);
  }
  function favoritesPageTouch() {
    let page2 = DomNode.from(document), pageSource = page2.use(domClass.page), source = page2.use(domClass.search);
    pageSource.html.inplace()?.apply("constrainResults"), pageSource.body.inplace()?.apply(
      "constrainResults",
      "constrainFavoritesNavigation"
    );
    let categories = source.favorites.categories.one(), categorySelect = categories ? manageFavoritesCategories(categories) : null, searchHostApply = { expand: "ehpeek-expand-favorites-search" };
    source.favorites.input.one()?.form()?.parent()?.inplace(searchHostApply).apply("expand");
    let resultSource = source.results.one();
    if (!resultSource)
      return categorySelect;
    let allSelected = categorySelect?.info.categories[0]?.selected === !0, resultList = resultSource.inplace(domClass.search.results.apply).apply("containFavorites");
    return allSelected && resultList.apply("compactFavorites"), categorySelect;
  }
  function manageFavoritesCategories(container) {
    let nodes = container.all(domClass.search.favorites.categories.items);
    if (nodes.length === 0)
      return null;
    let parsed = nodes.map((node) => {
      let children2 = node.children(), countText = children2[0]?.text() ?? "0", label = children2[children2.length - 1]?.text() || node.text(), count = Number(countText.replace(/,/g, "")), indicatorStyle = node.one(domClass.search.favorites.categories.items.indicator)?.computedStyle() ?? null;
      return {
        appearance: indicatorStyle ? {
          backgroundImage: indicatorStyle.backgroundImage,
          backgroundPosition: indicatorStyle.backgroundPosition,
          backgroundSize: indicatorStyle.backgroundSize
        } : null,
        count: Number.isFinite(count) ? count : 0,
        label,
        selected: node.matches(domClass.search.favorites.selectedCategory),
        source: node
      };
    }), all = parsed.find((category) => category.source.childElementCount() === 0), favorites = parsed.filter((category) => category !== all), total = favorites.reduce((sum, category) => sum + category.count, 0);
    container.inplace(domClass.search.favorites.categories.apply).apply("hide");
    let categories = [
      ...all ? [{ ...all, count: total }] : [],
      ...favorites
    ];
    return {
      info: {
        categories: categories.map(({ appearance, count, label, selected }) => ({
          appearance,
          count,
          label,
          selected
        }))
      },
      items: categories.map(({ source }) => source.inplace())
    };
  }
  function searchResultsPageTouch() {
    let page2 = DomNode.from(document), pageSource = page2.use(domClass.page), source = page2.use(domClass.search);
    pageSource.html.inplace()?.apply("constrainResults"), pageSource.body.inplace()?.apply("constrainResults");
    let resultSource = source.results.one();
    resultSource && resultSource.inplace(domClass.search.results.apply).apply("containSearch");
  }
  function manageTouchResultsPage(page2) {
    let apply = () => page2.type === "favorites" ? favoritesPageTouch() : ((page2.type === "search" || page2.type === "readHistory") && searchResultsPageTouch(), null), favoritesCategory = apply(), data = { favoritesCategory: favoritesCategory?.info ?? null }, elems = {
      favoriteCategoryItems: favoritesCategory?.items ?? []
    };
    return { data, elems, handle: {
      /** Activates E-H's original Favorites collection control. */
      activateFavoriteCategory(index) {
        elems.favoriteCategoryItems[index]?.click();
      },
      /** Reapplies TouchUI layout after the result list is replaced in place. */
      updateTouchResultsLayout() {
        let updated = apply();
        updated && elems.favoriteCategoryItems.splice(
          0,
          elems.favoriteCategoryItems.length,
          ...updated.items
        );
      }
    } };
  }

  // src/eh/dom/searchPanel.ts
  function manageSearchPanel() {
    let search2 = DomNode.from(document).use(domClass.search), source = search2.panel, searchInput = search2.input.one(), form2 = searchInput?.form() ?? null, standardSearchBox = source.box.one(), categories = source.box.categories.one(), advancedPanel = source.box.advanced.one(), optionLinks = advancedPanel?.previous() ?? null, fileSearch = source.fileSearch.one(), searchSubmit = form2?.one(domClass.search.submit) ?? searchInput?.parent()?.one(domClass.search.submitFallback) ?? null, clearButton = form2?.one(domClass.search.panel.clear) ?? searchInput?.parent()?.one(domClass.search.panel.clearFallback) ?? null;
    if (!searchInput || !form2 || !searchSubmit)
      return null;
    let mount = createAnchor("search-panel"), categoryToggleMount = categories && optionLinks ? createAnchor("search-category-toggle") : null, searchActionMount = createAnchor("search-action"), clearActionMount = clearButton ? createAnchor("search-clear-action") : null;
    if (!mount || !searchActionMount || clearButton && !clearActionMount)
      return null;
    let optionLinkItems = optionLinks?.all(domClass.search.panel.optionLinks) ?? [], advancedToggle = advancedPanel ? optionLinkItems[0] ?? null : null, fileSearchToggle = fileSearch ? optionLinkItems[advancedToggle ? 1 : 0] ?? null : null, advancedToggleMount = advancedToggle ? createAnchor("search-advanced-toggle") : null, fileSearchToggleMount = fileSearchToggle ? createAnchor("search-file-toggle") : null, searchControls = createManagedElement("div", {
      overlay: "ehpeek-overlay-search-actions"
    }).apply("overlay");
    searchSubmit.inplace(domClass.search.panel.submit.apply).apply("hide");
    let optionLinksApply = { wrap: "ehpeek-wrap-search-options" }, elems = {
      advancedPanel: source.box.advanced.inplace()?.apply("expand") ?? null,
      advancedToggle: advancedToggle?.inplace() ?? null,
      advancedToggleMount,
      categories: source.box.categories.inplace()?.apply("layout") ?? null,
      categoryToggleMount,
      clearActionMount,
      clearButton: clearButton?.inplace(domClass.search.panel.clear.apply).apply("hide") ?? null,
      fileSearch: source.fileSearch.inplace()?.apply("expand") ?? null,
      fileSearchToggle: fileSearchToggle?.inplace() ?? null,
      fileSearchToggleMount,
      form: form2.inplace(domClass.search.panel.box.form.apply),
      mount,
      optionLinks: optionLinks?.inplace(optionLinksApply).apply("wrap") ?? null,
      searchActionMount,
      searchBox: source.box.inplace()?.apply("reset") ?? searchControls,
      searchControls,
      searchInput: searchInput.inplace(domClass.search.input.apply).apply("expand")
    };
    (standardSearchBox ? elems.searchBox : elems.form).before(elems.mount), standardSearchBox && elems.searchBox.remove(), elems.searchInput.replaceWith(elems.searchControls), elems.searchControls.append(elems.searchInput), elems.clearButton && elems.clearActionMount && (elems.clearButton.remove(), elems.searchControls.append(elems.clearActionMount)), elems.searchControls.append(elems.searchActionMount), elems.categories && elems.optionLinks && elems.categoryToggleMount && (elems.optionLinks.after(elems.categories), elems.optionLinks.prepend(elems.categoryToggleMount)), elems.optionLinks && elems.advancedToggle && elems.advancedToggleMount && (elems.advancedToggle.after(elems.advancedToggleMount), elems.advancedToggle.remove()), elems.optionLinks && elems.fileSearchToggle && elems.fileSearchToggleMount && (elems.fileSearchToggle.after(elems.fileSearchToggleMount), elems.fileSearchToggle.remove()), elems.fileSearch?.remove();
    let formInsideSearchBox = source.box.form.one()?.sameNode(form2) ?? !1, formId = form2.attribute("id") || "ehpeek-search-form", data = {
      clearLabel: clearButton ? actionLabel(clearButton) : null,
      hasClear: elems.clearButton !== null && elems.clearActionMount !== null,
      searchLabel: actionLabel(searchSubmit)
    };
    elems.searchActionMount.addClasses("contents"), elems.clearActionMount?.addClasses("contents"), elems.form.apply("stack"), elems.searchControls.setAttributes({ "data-ehpeek-has-clear": String(data.hasClear) }), elems.categories?.setAttributes({ "aria-hidden": "true" });
    let handle = {
      /** Controls the original category table from EhPeek's category toggle. */
      updateCategoryVisibility(open) {
        elems.categories?.setAttributes({ "aria-hidden": String(!open) });
      },
      /** Activates E-H's original Search submit control. */
      activateSearch() {
        elems.form.all(
          `.${domClass.search.panel.submit.apply.hide}[type="submit"]`
        )[0]?.click();
      },
      /** Clears only the Search text without invoking E-H's page-navigation reset. */
      clearSearchText() {
        elems.searchInput.setInputValue(""), elems.searchInput.dispatchInput(), elems.searchInput.focus();
      },
      toggleAdvancedOptions() {
        elems.advancedToggle?.click();
      },
      toggleFileSearch() {
        elems.fileSearchToggle?.click();
      }
    };
    return formInsideSearchBox || (elems.form.setAttributes({ id: formId }), elems.searchInput.setAttributes({ form: formId }), elems.clearButton?.setAttributes({ form: formId })), { data, elems, handle };
  }
  function actionLabel(element) {
    return element.attribute("value") ?? element.text();
  }

  // src/eh/dom/settings.ts
  function extractGalleryTitlePreference() {
    let source = DomNode.from(document).use(domClass.settings), japaneseTitle = source.titleJapanese.one(), defaultTitle = source.titleDefault.one();
    return japaneseTitle?.checked() ? "sub" : defaultTitle?.checked() ? "main" : null;
  }

  // src/eh/dom/topBar.ts
  function manageSettingsMenuMount() {
    let page2 = DomNode.from(document), source = page2.use(domClass.topBar), thumbnailContainer = page2.use(domClass.gallery).preview.thumbs.one(), titleContainer = source.galleryTitle.one(), topNav = source.navigation.one(), anchor2 = thumbnailContainer ?? titleContainer;
    if (topNav) {
      let item2 = createManagedElement("div");
      return topNav.inplace().append(item2), item2;
    }
    if (!anchor2?.parent())
      return null;
    let item = createManagedElement("div").replaceClasses("text-right"), managedAnchor = anchor2.inplace();
    return thumbnailContainer ? managedAnchor.before(item) : managedAnchor.after(item), item;
  }
  function manageTopBar() {
    let mount = createAnchor("top-bar");
    if (!mount)
      return null;
    let source = DomNode.from(document).use(domClass.topBar), original = source.navigation.one(), links = source.navigation.links.all();
    if (!original || links.length === 0)
      return null;
    let data = {
      favoritesHref: new URL("/favorites.php", window.location.href).href,
      homeHref: links[0]?.attribute("href") ?? "/"
    }, elems = {
      mount,
      navItems: source.navigation.links.moveAll().map((link) => link.apply("layout"))
    };
    return original.inplace().replaceWith(elems.mount), {
      data,
      elems
    };
  }

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/defaultAttributes.mjs
  var defaultAttributes = {
    xmlns: "http://www.w3.org/2000/svg",
    width: 24,
    height: 24,
    viewBox: "0 0 24 24",
    fill: "none",
    stroke: "currentColor",
    "stroke-width": 2,
    "stroke-linecap": "round",
    "stroke-linejoin": "round"
  };

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/context.mjs
  var LucideContext = createContext({
    size: 24,
    color: "currentColor",
    strokeWidth: 2,
    absoluteStrokeWidth: !1,
    class: ""
  });

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/hasA11yProp.mjs
  var hasA11yProp = (props) => {
    for (let prop in props)
      if (prop.startsWith("aria-") || prop === "role" || prop === "title")
        return !0;
    return !1;
  };

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/mergeClasses.mjs
  var mergeClasses = (...classes) => classes.filter((className2, index, array) => !!className2 && className2.trim() !== "" && array.indexOf(className2) === index).join(" ").trim();

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toKebabCase.mjs
  var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toCamelCase.mjs
  var toCamelCase = (string) => string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase());

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toPascalCase.mjs
  var toPascalCase = (string) => {
    let camelCase = toCamelCase(string);
    return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
  };

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/Icon.mjs
  var _tmpl$ = /* @__PURE__ */ template("<svg>"), Icon = (props) => {
    let [localProps, rest] = splitProps(props, ["color", "size", "strokeWidth", "children", "class", "name", "iconNode", "absoluteStrokeWidth"]), globalProps = useContext(LucideContext);
    return (() => {
      var _el$ = _tmpl$();
      return spread(_el$, mergeProps(defaultAttributes, {
        get width() {
          return localProps.size ?? globalProps.size ?? defaultAttributes.width;
        },
        get height() {
          return localProps.size ?? globalProps.size ?? defaultAttributes.height;
        },
        get stroke() {
          return localProps.color ?? globalProps.color ?? defaultAttributes.stroke;
        },
        get "stroke-width"() {
          return memo(() => (localProps.absoluteStrokeWidth ?? globalProps.absoluteStrokeWidth) === !0)() ? Number(localProps.strokeWidth ?? globalProps.strokeWidth ?? defaultAttributes["stroke-width"]) * 24 / Number(localProps.size ?? globalProps.size) : Number(localProps.strokeWidth ?? globalProps.strokeWidth ?? defaultAttributes["stroke-width"]);
        },
        get class() {
          return mergeClasses("lucide", "lucide-icon", globalProps.class, ...localProps.name != null ? [`lucide-${toKebabCase(toPascalCase(localProps.name))}`, `lucide-${toKebabCase(localProps.name)}`] : [], localProps.class);
        },
        get "aria-hidden"() {
          return !localProps.children && !hasA11yProp(rest) ? "true" : void 0;
        }
      }, rest), !0, !0), insert(_el$, createComponent(For, {
        get each() {
          return localProps.iconNode;
        },
        children: ([elementName, attrs]) => createComponent(Dynamic, mergeProps({
          component: elementName
        }, attrs))
      })), _el$;
    })();
  };

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-down.mjs
  var iconNode = [["path", {
    d: "M12 5v14",
    key: "s699le"
  }], ["path", {
    d: "m19 12-7 7-7-7",
    key: "1idqje"
  }]], ArrowDown = (props) => createComponent(Icon, mergeProps(props, {
    iconNode,
    name: "arrow-down"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-left.mjs
  var iconNode2 = [["path", {
    d: "m12 19-7-7 7-7",
    key: "1l729n"
  }], ["path", {
    d: "M19 12H5",
    key: "x3x0zl"
  }]], ArrowLeft = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode2,
    name: "arrow-left"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-right.mjs
  var iconNode3 = [["path", {
    d: "M5 12h14",
    key: "1ays0h"
  }], ["path", {
    d: "m12 5 7 7-7 7",
    key: "xquz4c"
  }]], ArrowRight = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode3,
    name: "arrow-right"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-up.mjs
  var iconNode4 = [["path", {
    d: "m5 12 7-7 7 7",
    key: "hav0vg"
  }], ["path", {
    d: "M12 19V5",
    key: "x0mq9r"
  }]], ArrowUp = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode4,
    name: "arrow-up"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/book-open.mjs
  var iconNode5 = [["path", {
    d: "M12 5v16",
    key: "1f6ucr"
  }], ["path", {
    d: "M20.001 19A2 2 0 0022 17V5a2 2 0 00-1.999-2L16 3.002A5 5 0 0012 5a5 5 0 00-4-2H4a2 2 0 00-2 2v12a2 2 0 001.999 2H8a5 5 0 014 2 5 5 0 014-2z",
    key: "1fyvmf"
  }]], BookOpen = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode5,
    name: "book-open"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/check.mjs
  var iconNode6 = [["path", {
    d: "M20 6 9 17l-5-5",
    key: "1gmf2c"
  }]], Check = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode6,
    name: "check"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-left.mjs
  var iconNode7 = [["path", {
    d: "m15 18-6-6 6-6",
    key: "1wnfg3"
  }]], ChevronLeft = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode7,
    name: "chevron-left"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-right.mjs
  var iconNode8 = [["path", {
    d: "m9 18 6-6-6-6",
    key: "mthhwq"
  }]], ChevronRight = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode8,
    name: "chevron-right"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/columns-2.mjs
  var iconNode9 = [["rect", {
    width: "18",
    height: "18",
    x: "3",
    y: "3",
    rx: "2",
    key: "afitv7"
  }], ["path", {
    d: "M12 3v18",
    key: "108xh3"
  }]], Columns2 = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode9,
    name: "columns-2"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/download.mjs
  var iconNode10 = [["path", {
    d: "M12 15V3",
    key: "m9g1x1"
  }], ["path", {
    d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",
    key: "ih7n3h"
  }], ["path", {
    d: "m7 10 5 5 5-5",
    key: "brsn70"
  }]], Download = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode10,
    name: "download"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/ellipsis-vertical.mjs
  var iconNode11 = [["circle", {
    cx: "12",
    cy: "12",
    r: "1",
    key: "41hilf"
  }], ["circle", {
    cx: "12",
    cy: "5",
    r: "1",
    key: "gxeob9"
  }], ["circle", {
    cx: "12",
    cy: "19",
    r: "1",
    key: "lyex9k"
  }]], EllipsisVertical = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode11,
    name: "ellipsis-vertical"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/external-link.mjs
  var iconNode12 = [["path", {
    d: "M15 3h6v6",
    key: "1q9fwt"
  }], ["path", {
    d: "M10 14 21 3",
    key: "gplh6r"
  }], ["path", {
    d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
    key: "a6xqqp"
  }]], ExternalLink = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode12,
    name: "external-link"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/file.mjs
  var iconNode13 = [["path", {
    d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
    key: "1oefj6"
  }], ["path", {
    d: "M14 2v5a1 1 0 0 0 1 1h5",
    key: "wfsgrz"
  }]], File = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode13,
    name: "file"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/grid-2x2.mjs
  var iconNode14 = [["path", {
    d: "M12 3v18",
    key: "108xh3"
  }], ["path", {
    d: "M3 12h18",
    key: "1i2n21"
  }], ["rect", {
    x: "3",
    y: "3",
    width: "18",
    height: "18",
    rx: "2",
    key: "h1oib"
  }]], Grid2x2 = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode14,
    name: "grid-2x2"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/heart.mjs
  var iconNode15 = [["path", {
    d: "M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",
    key: "mvr1a0"
  }]], Heart = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode15,
    name: "heart"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/history.mjs
  var iconNode16 = [["path", {
    d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
    key: "1357e3"
  }], ["path", {
    d: "M3 3v5h5",
    key: "1xhq8a"
  }], ["path", {
    d: "M12 7v5l4 2",
    key: "1fdv2h"
  }]], History = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode16,
    name: "history"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/house.mjs
  var iconNode17 = [["path", {
    d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",
    key: "5wwlr5"
  }], ["path", {
    d: "M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
    key: "r6nss1"
  }]], House = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode17,
    name: "house"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/hand.mjs
  var iconNode18 = [["path", {
    d: "M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2",
    key: "1fvzgz"
  }], ["path", {
    d: "M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2",
    key: "1kc0my"
  }], ["path", {
    d: "M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8",
    key: "10h0bg"
  }], ["path", {
    d: "M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15",
    key: "1s1gnw"
  }]], Hand = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode18,
    name: "hand"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/info.mjs
  var iconNode19 = [["circle", {
    cx: "12",
    cy: "12",
    r: "10",
    key: "1mglay"
  }], ["path", {
    d: "M12 16v-4",
    key: "1dtifu"
  }], ["path", {
    d: "M12 8h.01",
    key: "e9boi3"
  }]], Info = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode19,
    name: "info"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/locate-fixed.mjs
  var iconNode20 = [["line", {
    x1: "2",
    x2: "5",
    y1: "12",
    y2: "12",
    key: "bvdh0s"
  }], ["line", {
    x1: "19",
    x2: "22",
    y1: "12",
    y2: "12",
    key: "1tbv5k"
  }], ["line", {
    x1: "12",
    x2: "12",
    y1: "2",
    y2: "5",
    key: "11lu5j"
  }], ["line", {
    x1: "12",
    x2: "12",
    y1: "19",
    y2: "22",
    key: "x3vr5v"
  }], ["circle", {
    cx: "12",
    cy: "12",
    r: "7",
    key: "fim9np"
  }], ["circle", {
    cx: "12",
    cy: "12",
    r: "3",
    key: "1v7zrd"
  }]], LocateFixed = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode20,
    name: "locate-fixed"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/maximize.mjs
  var iconNode21 = [["path", {
    d: "M8 3H5a2 2 0 0 0-2 2v3",
    key: "1dcmit"
  }], ["path", {
    d: "M21 8V5a2 2 0 0 0-2-2h-3",
    key: "1e4gt3"
  }], ["path", {
    d: "M3 16v3a2 2 0 0 0 2 2h3",
    key: "wsl5sc"
  }], ["path", {
    d: "M16 21h3a2 2 0 0 0 2-2v-3",
    key: "18trek"
  }]], Maximize = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode21,
    name: "maximize"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/minimize.mjs
  var iconNode22 = [["path", {
    d: "M8 3v3a2 2 0 0 1-2 2H3",
    key: "hohbtr"
  }], ["path", {
    d: "M21 8h-3a2 2 0 0 1-2-2V3",
    key: "5jw1f3"
  }], ["path", {
    d: "M3 16h3a2 2 0 0 1 2 2v3",
    key: "198tvr"
  }], ["path", {
    d: "M16 21v-3a2 2 0 0 1 2-2h3",
    key: "ph8mxp"
  }]], Minimize = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode22,
    name: "minimize"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-horizontal.mjs
  var iconNode23 = [["path", {
    d: "m18 8 4 4-4 4",
    key: "1ak13k"
  }], ["path", {
    d: "M2 12h20",
    key: "9i4pu4"
  }], ["path", {
    d: "m6 8-4 4 4 4",
    key: "15zrgr"
  }]], MoveHorizontal = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode23,
    name: "move-horizontal"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-vertical.mjs
  var iconNode24 = [["path", {
    d: "M12 2v20",
    key: "t6zp3m"
  }], ["path", {
    d: "m8 18 4 4 4-4",
    key: "bh5tu3"
  }], ["path", {
    d: "m8 6 4-4 4 4",
    key: "ybng9g"
  }]], MoveVertical = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode24,
    name: "move-vertical"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/palette.mjs
  var iconNode25 = [["path", {
    d: "M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",
    key: "e79jfc"
  }], ["circle", {
    cx: "13.5",
    cy: "6.5",
    r: ".5",
    fill: "currentColor",
    key: "1okk4w"
  }], ["circle", {
    cx: "17.5",
    cy: "10.5",
    r: ".5",
    fill: "currentColor",
    key: "f64h9f"
  }], ["circle", {
    cx: "6.5",
    cy: "12.5",
    r: ".5",
    fill: "currentColor",
    key: "qy21gx"
  }], ["circle", {
    cx: "8.5",
    cy: "7.5",
    r: ".5",
    fill: "currentColor",
    key: "fotxhn"
  }]], Palette = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode25,
    name: "palette"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/pencil.mjs
  var iconNode26 = [["path", {
    d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
    key: "1a8usu"
  }], ["path", {
    d: "m15 5 4 4",
    key: "1mk7zo"
  }]], Pencil = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode26,
    name: "pencil"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/play.mjs
  var iconNode27 = [["path", {
    d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",
    key: "10ikf1"
  }]], Play = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode27,
    name: "play"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/refresh-cw.mjs
  var iconNode28 = [["path", {
    d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
    key: "v9h5vc"
  }], ["path", {
    d: "M21 3v5h-5",
    key: "1q7to0"
  }], ["path", {
    d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",
    key: "3uifl3"
  }], ["path", {
    d: "M8 16H3v5",
    key: "1cv678"
  }]], RefreshCw = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode28,
    name: "refresh-cw"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/rows-3.mjs
  var iconNode29 = [["rect", {
    width: "18",
    height: "18",
    x: "3",
    y: "3",
    rx: "2",
    key: "afitv7"
  }], ["path", {
    d: "M21 9H3",
    key: "1338ky"
  }], ["path", {
    d: "M21 15H3",
    key: "9uk58r"
  }]], Rows3 = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode29,
    name: "rows-3"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/scan-line.mjs
  var iconNode30 = [["path", {
    d: "M3 7V5a2 2 0 0 1 2-2h2",
    key: "aa7l1z"
  }], ["path", {
    d: "M17 3h2a2 2 0 0 1 2 2v2",
    key: "4qcy5o"
  }], ["path", {
    d: "M21 17v2a2 2 0 0 1-2 2h-2",
    key: "6vwrx8"
  }], ["path", {
    d: "M7 21H5a2 2 0 0 1-2-2v-2",
    key: "ioqczr"
  }], ["path", {
    d: "M7 12h10",
    key: "b7w52i"
  }]], ScanLine = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode30,
    name: "scan-line"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/search.mjs
  var iconNode31 = [["path", {
    d: "m21 21-4.34-4.34",
    key: "14j7rj"
  }], ["circle", {
    cx: "11",
    cy: "11",
    r: "8",
    key: "4ej97u"
  }]], Search = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode31,
    name: "search"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/settings.mjs
  var iconNode32 = [["path", {
    d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
    key: "1i5ecw"
  }], ["circle", {
    cx: "12",
    cy: "12",
    r: "3",
    key: "1v7zrd"
  }]], Settings = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode32,
    name: "settings"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/sparkles.mjs
  var iconNode33 = [["path", {
    d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
    key: "1s2grr"
  }], ["path", {
    d: "M20 2v4",
    key: "1rf3ol"
  }], ["path", {
    d: "M22 4h-4",
    key: "gwowj6"
  }], ["circle", {
    cx: "4",
    cy: "20",
    r: "2",
    key: "6kqj1y"
  }]], Sparkles = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode33,
    name: "sparkles"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/star.mjs
  var iconNode34 = [["path", {
    d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",
    key: "r04s7s"
  }]], Star = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode34,
    name: "star"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/x.mjs
  var iconNode35 = [["path", {
    d: "M18 6 6 18",
    key: "1bl5f8"
  }], ["path", {
    d: "m6 6 12 12",
    key: "d8bk6v"
  }]], X = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode35,
    name: "x"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-in.mjs
  var iconNode36 = [["circle", {
    cx: "11",
    cy: "11",
    r: "8",
    key: "4ej97u"
  }], ["line", {
    x1: "21",
    x2: "16.65",
    y1: "21",
    y2: "16.65",
    key: "13gj7c"
  }], ["line", {
    x1: "11",
    x2: "11",
    y1: "8",
    y2: "14",
    key: "1vmskp"
  }], ["line", {
    x1: "8",
    x2: "14",
    y1: "11",
    y2: "11",
    key: "durymu"
  }]], ZoomIn = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode36,
    name: "zoom-in"
  }));

  // node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-out.mjs
  var iconNode37 = [["circle", {
    cx: "11",
    cy: "11",
    r: "8",
    key: "4ej97u"
  }], ["line", {
    x1: "21",
    x2: "16.65",
    y1: "21",
    y2: "16.65",
    key: "13gj7c"
  }], ["line", {
    x1: "8",
    x2: "14",
    y1: "11",
    y2: "11",
    key: "durymu"
  }]], ZoomOut = (props) => createComponent(Icon, mergeProps(props, {
    iconNode: iconNode37,
    name: "zoom-out"
  }));

  // src/components/Widgets/Icon.tsx
  var _tmpl$2 = /* @__PURE__ */ template('<svg class="ehpeek-icon block flex-none"viewBox="0 0 24 24"fill=none stroke=currentColor stroke-linecap=round stroke-linejoin=round data-icon-name=panda-peek aria-hidden=true>'), _tmpl$22 = /* @__PURE__ */ template("<svg><path fill=currentColor stroke=none></svg>", !1, !0, !1), _tmpl$3 = /* @__PURE__ */ template("<svg><path></svg>", !1, !0, !1);
  function Icon2(props) {
    let component = createMemo(() => props.name === "panda-peek" ? void 0 : LUCIDE_ICONS[props.name]), filled = createMemo(() => props.filled && FILLABLE_ICONS.has(props.name)), size = createMemo(() => typeof props.size == "number" ? `${props.size}px` : props.size ?? "var(--ui-icon-size-md)");
    return [createComponent(Dynamic, {
      get component() {
        return component();
      },
      class: "ehpeek-icon block flex-none",
      get size() {
        return size();
      },
      get style() {
        return {
          width: size(),
          height: size()
        };
      },
      color: "currentColor",
      get fill() {
        return filled() ? "currentColor" : "none";
      },
      get stroke() {
        return filled() ? "none" : "currentColor";
      },
      get strokeWidth() {
        return props.strokeWidth ?? 2;
      },
      get "data-icon-name"() {
        return props.name;
      }
    }), createComponent(Show, {
      get when() {
        return props.name === "panda-peek";
      },
      get children() {
        return createComponent(PandaPeekIcon, {
          get size() {
            return size();
          },
          get strokeWidth() {
            return props.strokeWidth ?? 2;
          }
        });
      }
    })];
  }
  var LUCIDE_ICONS = {
    "arrow-left": ArrowLeft,
    "arrow-right": ArrowRight,
    "arrow-down": ArrowDown,
    "arrow-up": ArrowUp,
    "arrows-horizontal": MoveHorizontal,
    "arrows-vertical": MoveVertical,
    "book-open": BookOpen,
    check: Check,
    "chevron-left": ChevronLeft,
    "chevron-right": ChevronRight,
    close: X,
    download: Download,
    edit: Pencil,
    "external-link": ExternalLink,
    fullscreen: Maximize,
    "fullscreen-exit": Minimize,
    grid: Grid2x2,
    hand: Hand,
    heart: Heart,
    history: History,
    home: House,
    info: Info,
    locate: LocateFixed,
    menu: EllipsisVertical,
    page: File,
    palette: Palette,
    pages: Columns2,
    play: Play,
    refresh: RefreshCw,
    search: Search,
    settings: Settings,
    sparkles: Sparkles,
    "scroll-continuous": Rows3,
    star: Star,
    viewport: ScanLine,
    "zoom-in": ZoomIn,
    "zoom-out": ZoomOut
  }, FILLABLE_ICONS = /* @__PURE__ */ new Set(["heart", "star"]), PANDA_FILLED_PATHS = ["M7.2 3.2a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8Z", "M16.8 3.2a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8Z", "M7.6 9.8c.5-1.2 1.6-1.8 2.6-1.3s1.3 1.8.8 3-1.6 1.8-2.6 1.3-1.3-1.8-.8-3Z", "M13.8 8.5c1-.5 2.1.1 2.6 1.3s.2 2.5-.8 3-2.1-.1-2.6-1.3-.2-2.5.8-3Z", "M10.9 13.6c0-.6.5-.9 1.1-.9s1.1.3 1.1.9-.5 1-1.1 1-1.1-.4-1.1-1Z", "M5.2 13.7a2.8 1.9 0 1 0 0 3.8 2.8 1.9 0 0 0 0-3.8Z", "M18.8 14.1a2.8 1.9 0 1 0 0 3.8 2.8 1.9 0 0 0 0-3.8Z"], PANDA_PATHS = ["M5 17c-.8-6.4 2.1-10.8 7-10.8s7.8 4.4 7 10.8", "M12 14.6v.7c0 .7-.6 1.2-1.3 1.2m1.3-1.2c0 .7.6 1.2 1.3 1.2", "M2 17h20"];
  function PandaPeekIcon(props) {
    return (() => {
      var _el$ = _tmpl$2();
      return insert(_el$, createComponent(For, {
        each: PANDA_FILLED_PATHS,
        children: (path) => (() => {
          var _el$2 = _tmpl$22();
          return setAttribute(_el$2, "d", path), _el$2;
        })()
      }), null), insert(_el$, createComponent(For, {
        each: PANDA_PATHS,
        children: (path) => (() => {
          var _el$3 = _tmpl$3();
          return setAttribute(_el$3, "d", path), _el$3;
        })()
      }), null), createRenderEffect((_p$) => {
        var _v$ = props.size, _v$2 = props.size, _v$3 = props.strokeWidth;
        return _v$ !== _p$.e && setStyleProperty(_el$, "width", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "height", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "stroke-width", _p$.a = _v$3), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$;
    })();
  }

  // src/components/WelcomeIcon.tsx
  var _tmpl$4 = /* @__PURE__ */ template('<div role=status aria-live=polite><span class="inline-flex items-center justify-center ehp-color-site-text"><span class="inline-block box-border w-[var(--ui-icon-size-xl)] h-[var(--ui-icon-size-xl)] animate-spin rounded-full border-4 border-solid ehp-color-spinner"aria-hidden=true>');
  function WelcomeIcon(props) {
    let label = () => props.label ?? i18n_default.common.status.loading, showIcon = () => props.showIcon !== !1, placementClass = () => props.embedded ? "relative box-border w-full border-0 bg-transparent ui-px-lg ui-py-md" : "fixed left-1/2 top-1/2 z-[1200] -translate-x-1/2 -translate-y-1/2 ui-rounded-lg border ehp-color-site-border bg-[var(--color-loading)] ui-px-xl ui-py-lg shadow-[0_6px_20px_var(--color-shadow-floating)]";
    return (() => {
      var _el$ = _tmpl$4(), _el$2 = _el$.firstChild;
      return insert(_el$, (() => {
        var _c$ = memo(() => !!showIcon());
        return () => _c$() ? createComponent(Icon2, {
          name: "panda-peek",
          size: "var(--ui-control-size-xl)",
          strokeWidth: 1.6
        }) : null;
      })(), _el$2), createRenderEffect((_p$) => {
        var _v$ = `${placementClass()} flex select-none flex-col items-center ui-gap-lg ehp-color-site-accent pointer-events-none`, _v$2 = label();
        return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "aria-label", _p$.t = _v$2), _p$;
      }, {
        e: void 0,
        t: void 0
      }), _el$;
    })();
  }

  // src/components/Widgets/Loading.tsx
  function LoadingOverlay(props) {
    return createComponent(Show, {
      get when() {
        return props.visible;
      },
      get children() {
        return createComponent(WelcomeIcon, {
          get label() {
            return props.label;
          }
        });
      }
    });
  }

  // src/components/PointerGesture.tsx
  var DEFAULT_TAP_MOVE_THRESHOLD_PX = 8, DEFAULT_DRAG_START_THRESHOLD_PX = 8, DEFAULT_DRAG_INTENT_RATIO = 1, MOUSE_POINTER_ID = -1, PointerGesture = class {
    constructor(target, callbacks) {
      __publicField(this, "pinchPointers", /* @__PURE__ */ new Map());
      __publicField(this, "drag", null);
      __publicField(this, "holdTimer", null);
      __publicField(this, "suppressClick", !1);
      __publicField(this, "suppressClickTimer", null);
      __publicField(this, "pinch", null);
      __publicField(this, "onDragStart", (event) => {
        this.drag?.canDrag && event.preventDefault();
      });
      __publicField(this, "onClick", (event) => {
        this.suppressClick && (this.clearClickSuppression(), event.preventDefault(), event.stopImmediatePropagation());
      });
      __publicField(this, "onClickSuppressionPointerDown", () => {
        this.clearClickSuppression();
      });
      __publicField(this, "onContextMenu", () => {
        this.drag?.active || (this.cancel(), this.clearPinch());
      });
      __publicField(this, "onPointerDown", (event) => {
        if (event.pointerType === "mouse" && event.button !== 0 || this.trackPinchPointerDown(event) || this.pinch || this.drag)
          return;
        let callbacks = this.callbacks(), canDrag = callbacks.shouldCaptureDrag?.(event) ?? !0;
        (canDrag || (callbacks.shouldObserveTap?.(event) ?? !1)) && (this.start(event.pointerId, event.pointerType, event.clientX, event.clientY, event, canDrag), event.pointerType === "mouse" && this.addMouseListeners());
      });
      __publicField(this, "onMouseDown", (event) => {
        event.button !== 0 || typeof PointerEvent < "u" || this.drag || !(this.callbacks().shouldCaptureDrag?.(event) ?? !0) || (this.start(MOUSE_POINTER_ID, "mouse", event.clientX, event.clientY, event, !0), this.addMouseListeners());
      });
      __publicField(this, "onPointerMove", (event) => {
        !this.drag || event.pointerId !== this.drag.pointerId || this.drag.pointerType === "mouse" || this.move(event.clientX, event.clientY, event);
      });
      __publicField(this, "onPointerUp", (event) => {
        !this.drag || event.pointerId !== this.drag.pointerId || (this.finish(event.clientX, event.clientY, event), this.releasePinchPointer(event));
      });
      __publicField(this, "onPointerCancel", (event) => {
        !this.drag || event.pointerId !== this.drag.pointerId || (this.finish(event.clientX, event.clientY, event, !0), this.releasePinchPointer(event));
      });
      __publicField(this, "onMouseMove", (event) => {
        !this.drag || this.drag.pointerType !== "mouse" || this.move(event.clientX, event.clientY, event);
      });
      __publicField(this, "onMouseUp", (event) => {
        !this.drag || this.drag.pointerType !== "mouse" || this.finish(event.clientX, event.clientY, event);
      });
      __publicField(this, "onPinchPointerMove", (event) => {
        if (!this.pinch || !this.pinchPointers.has(event.pointerId))
          return;
        this.pinchPointers.set(event.pointerId, {
          clientX: event.clientX,
          clientY: event.clientY
        });
        let snapshot = this.pinchSnapshot();
        snapshot && (this.callbacks().onPinchMove?.({
          ...snapshot,
          scale: snapshot.distance / this.pinch.startDistance
        }, event), event.preventDefault());
      });
      __publicField(this, "onPinchPointerEnd", (event) => {
        this.pinchPointers.has(event.pointerId) && (this.pinchPointers.delete(event.pointerId), !(!this.pinch || this.pinchPointers.size >= 2) && (this.callbacks().onPinchEnd?.(), this.clearPinch(), event.preventDefault()));
      });
      this.target = target, this.callbacks = callbacks, this.setDragging(!1), target.addEventListener("pointerdown", this.onPointerDown), target.addEventListener("mousedown", this.onMouseDown), target.addEventListener("dragstart", this.onDragStart), target.addEventListener("contextmenu", this.onContextMenu);
    }
    dispose() {
      this.drag && this.releaseCapture(this.drag), this.drag = null, this.clearHold(), this.setDragging(!1), this.clearPinch(), this.removePointerListeners(), this.removeMouseListeners(), this.target.removeEventListener("pointerdown", this.onPointerDown), this.target.removeEventListener("mousedown", this.onMouseDown), this.target.removeEventListener("dragstart", this.onDragStart), this.target.removeEventListener("contextmenu", this.onContextMenu), this.clearClickSuppression();
    }
    isDragging() {
      return this.drag?.active === !0;
    }
    cancel(preservePinchPointers = !1) {
      let drag = this.drag;
      drag && (this.releaseCapture(drag), preservePinchPointers || this.pinchPointers.delete(drag.pointerId), this.drag = null, this.clearHold(), this.setDragging(!1), this.removePointerListeners(), this.removeMouseListeners());
    }
    start(pointerId, pointerType, clientX, clientY, event, canDrag) {
      this.drag = {
        active: !1,
        canDrag,
        captureTarget: null,
        pointerId,
        pointerType,
        startClientX: clientX,
        startClientY: clientY,
        lastClientX: clientX,
        lastClientY: clientY,
        lastMoveTime: event.timeStamp,
        holdConsumed: !1,
        startTarget: event.target,
        tapCancelled: !1,
        velocityX: 0,
        velocityY: 0
      };
      let captureTarget = event.target;
      canDrag && "pointerId" in event && typeof captureTarget?.setPointerCapture == "function" && (captureTarget.setPointerCapture(pointerId), this.drag.captureTarget = captureTarget), this.addPointerListeners(), this.startHold(this.drag, event);
    }
    move(clientX, clientY, event) {
      let drag = this.drag;
      if (!drag)
        return;
      if (drag.holdConsumed) {
        event.preventDefault();
        return;
      }
      let dx = clientX - drag.startClientX, dy = clientY - drag.startClientY, tapMoveThreshold = this.tapMoveThreshold();
      if ((Math.abs(dx) >= tapMoveThreshold || Math.abs(dy) >= tapMoveThreshold) && (drag.tapCancelled = !0, this.clearHold()), !drag.canDrag) {
        this.updateLastMove(drag, clientX, clientY, event);
        return;
      }
      let intent = this.dragIntent(dx, dy);
      if (!drag.active && intent === "cancel") {
        this.cancel();
        return;
      }
      if (!drag.active && intent !== "start") {
        this.updateLastMove(drag, clientX, clientY, event);
        return;
      }
      drag.active || this.activateDrag(drag, event);
      let elapsed = Math.max(1, event.timeStamp - drag.lastMoveTime);
      drag.velocityX = (clientX - drag.lastClientX) / elapsed, drag.velocityY = (clientY - drag.lastClientY) / elapsed, drag.lastClientX = clientX, drag.lastClientY = clientY, drag.lastMoveTime = event.timeStamp, this.callbacks().onMove?.({
        pointerId: drag.pointerId,
        clientX,
        clientY,
        dx: clientX - drag.startClientX,
        dy: clientY - drag.startClientY,
        velocityX: drag.velocityX,
        velocityY: drag.velocityY
      }, event), event.preventDefault();
    }
    finish(clientX, clientY, event, cancelled = !1) {
      let drag = this.drag;
      if (!drag)
        return;
      this.drag = null, this.clearHold(), this.setDragging(!1), this.releaseCapture(drag), this.removePointerListeners(), this.removeMouseListeners();
      let info = {
        pointerId: drag.pointerId,
        clientX,
        clientY,
        dx: clientX - drag.startClientX,
        dy: clientY - drag.startClientY,
        velocityX: drag.velocityX,
        velocityY: drag.velocityY
      };
      if (drag.holdConsumed) {
        this.suppressNextClick();
        return;
      }
      let tapMoveThreshold = this.tapMoveThreshold(), isTap = !drag.tapCancelled && Math.abs(info.dx) < tapMoveThreshold && Math.abs(info.dy) < tapMoveThreshold;
      if (!cancelled && !drag.active && isTap && this.callbacks().onTap?.({
        ...info,
        startTarget: drag.startTarget
      }, event), drag.active) {
        if (cancelled) {
          this.callbacks().onEnd?.({
            ...info,
            dx: 0,
            dy: 0,
            velocityX: 0,
            velocityY: 0
          }, event);
          return;
        }
        this.suppressNextClick(), this.callbacks().onEnd?.(info, event);
      }
    }
    addPointerListeners() {
      document.addEventListener("pointermove", this.onPointerMove, !0), document.addEventListener("pointerup", this.onPointerUp, !0), document.addEventListener("pointercancel", this.onPointerCancel, !0);
    }
    removePointerListeners() {
      document.removeEventListener("pointermove", this.onPointerMove, !0), document.removeEventListener("pointerup", this.onPointerUp, !0), document.removeEventListener("pointercancel", this.onPointerCancel, !0);
    }
    addMouseListeners() {
      window.addEventListener("mousemove", this.onMouseMove, !0), window.addEventListener("mouseup", this.onMouseUp, !0);
    }
    removeMouseListeners() {
      window.removeEventListener("mousemove", this.onMouseMove, !0), window.removeEventListener("mouseup", this.onMouseUp, !0);
    }
    trackPinchPointerDown(event) {
      let callbacks = this.callbacks();
      if (!callbacks.onPinchStart || event.pointerType === "mouse" || (this.pinchPointers.set(event.pointerId, {
        clientX: event.clientX,
        clientY: event.clientY
      }), this.pinch || this.pinchPointers.size !== 2))
        return !1;
      let snapshot = this.pinchSnapshot();
      return snapshot ? callbacks.onPinchStart(snapshot, event) ? (this.cancel(!0), this.pinch = {
        startDistance: snapshot.distance
      }, this.addPinchListeners(), event.preventDefault(), event.stopPropagation(), !0) : (this.pinchPointers.delete(event.pointerId), !1) : !1;
    }
    addPinchListeners() {
      document.addEventListener("pointermove", this.onPinchPointerMove, !0), document.addEventListener("pointerup", this.onPinchPointerEnd, !0), document.addEventListener("pointercancel", this.onPinchPointerEnd, !0);
    }
    removePinchListeners() {
      document.removeEventListener("pointermove", this.onPinchPointerMove, !0), document.removeEventListener("pointerup", this.onPinchPointerEnd, !0), document.removeEventListener("pointercancel", this.onPinchPointerEnd, !0);
    }
    clearPinch() {
      this.pinch = null, this.pinchPointers.clear(), this.removePinchListeners();
    }
    releasePinchPointer(event) {
      this.pinch || this.pinchPointers.delete(event.pointerId);
    }
    pinchSnapshot() {
      let points = Array.from(this.pinchPointers.values()), first = points[0], second = points[1];
      if (!first || !second)
        return null;
      let dx = second.clientX - first.clientX, dy = second.clientY - first.clientY;
      return {
        clientX: (first.clientX + second.clientX) / 2,
        clientY: (first.clientY + second.clientY) / 2,
        distance: Math.hypot(dx, dy)
      };
    }
    tapMoveThreshold() {
      return this.callbacks().tapMoveThreshold ?? DEFAULT_TAP_MOVE_THRESHOLD_PX;
    }
    startHold(drag, event) {
      let callbacks = this.callbacks();
      callbacks.holdDelay === void 0 || !callbacks.onHold || (this.holdTimer = window.setTimeout(() => {
        if (this.holdTimer = null, this.drag !== drag || drag.active || drag.tapCancelled)
          return;
        let result = this.callbacks().onHold?.({
          clientX: drag.startClientX,
          clientY: drag.startClientY,
          pointerId: drag.pointerId
        }, event);
        result && (drag.tapCancelled = !0, result === "consume" ? drag.holdConsumed = !0 : this.activateDrag(drag, event));
      }, callbacks.holdDelay));
    }
    clearHold() {
      this.holdTimer !== null && (window.clearTimeout(this.holdTimer), this.holdTimer = null);
    }
    dragStartThreshold() {
      return this.callbacks().dragStartThreshold ?? DEFAULT_DRAG_START_THRESHOLD_PX;
    }
    dragIntentRatio() {
      return this.callbacks().dragIntentRatio ?? DEFAULT_DRAG_INTENT_RATIO;
    }
    dragAxis() {
      return this.callbacks().dragAxis ?? "any";
    }
    dragIntent(dx, dy) {
      let absX = Math.abs(dx), absY = Math.abs(dy), threshold = this.dragStartThreshold(), ratio = this.dragIntentRatio();
      return this.dragAxis() === "x" ? absY >= threshold && absY > absX ? "cancel" : absX >= threshold && absX >= absY * ratio ? "start" : "pending" : this.dragAxis() === "y" ? absX >= threshold && absX > absY ? "cancel" : absY >= threshold && absY >= absX * ratio ? "start" : "pending" : Math.hypot(dx, dy) >= threshold ? "start" : "pending";
    }
    activateDrag(drag, event) {
      drag.active = !0, this.setDragging(!0), drag.pointerType === "mouse" && window.getSelection()?.removeAllRanges(), this.callbacks().onStart?.({
        pointerId: drag.pointerId,
        clientX: drag.startClientX,
        clientY: drag.startClientY
      }, event), event.preventDefault();
    }
    updateLastMove(drag, clientX, clientY, event) {
      let elapsed = Math.max(1, event.timeStamp - drag.lastMoveTime);
      drag.velocityX = (clientX - drag.lastClientX) / elapsed, drag.velocityY = (clientY - drag.lastClientY) / elapsed, drag.lastClientX = clientX, drag.lastClientY = clientY, drag.lastMoveTime = event.timeStamp;
    }
    suppressNextClick() {
      this.suppressClick = !0, this.target.addEventListener("click", this.onClick, !0), this.target.addEventListener("mousedown", this.onClickSuppressionPointerDown, !0), this.target.addEventListener("pointerdown", this.onClickSuppressionPointerDown, !0), this.suppressClickTimer !== null && window.clearTimeout(this.suppressClickTimer), this.suppressClickTimer = window.setTimeout(() => {
        this.clearClickSuppression();
      }, 400);
    }
    clearClickSuppression() {
      this.suppressClick = !1, this.target.removeEventListener("click", this.onClick, !0), this.target.removeEventListener("mousedown", this.onClickSuppressionPointerDown, !0), this.target.removeEventListener("pointerdown", this.onClickSuppressionPointerDown, !0), this.suppressClickTimer !== null && (window.clearTimeout(this.suppressClickTimer), this.suppressClickTimer = null);
    }
    setDragging(dragging) {
      this.target.dataset.dragging = String(dragging);
    }
    releaseCapture(drag) {
      drag.captureTarget?.hasPointerCapture(drag.pointerId) && drag.captureTarget.releasePointerCapture(drag.pointerId);
    }
  };
  function createPointerGestureElement(target, callbacks) {
    let gesture = null;
    return createEffect(() => {
      let element = target();
      element && (gesture = new PointerGesture(element, callbacks), onCleanup(() => {
        gesture?.dispose(), gesture = null;
      }));
    }), () => gesture?.isDragging() ?? !1;
  }

  // src/components/Widgets/SwipeIndicator.tsx
  var _tmpl$5 = /* @__PURE__ */ template('<div class="fixed top-1/2 z-overlay flex w-42px h-108px items-center justify-center border border-[var(--color-site-swipe-border)] rounded-full bg-[var(--color-site-swipe-background)] text-[var(--color-site-text)] shadow-[0_6px_20px_var(--color-shadow-floating)] pointer-events-none select-none transition-opacity duration-120 ease-in-out"style=backdrop-filter:blur(8px)>'), HIDE_PROGRESS = 1e-3;
  function SwipeIndicator(props) {
    let progress = createMemo(() => Math.min(1, Math.max(0, props.state.progress))), hidden = createMemo(() => progress() <= HIDE_PROGRESS), pull = createMemo(() => Math.round(48 * progress())), offset = createMemo(() => props.state.direction === "left" ? 42 - pull() : pull() - 42), iconName = createMemo(() => props.state.blocked ? "close" : props.state.direction === "left" ? "chevron-left" : "chevron-right");
    return (() => {
      var _el$ = _tmpl$5();
      return insert(_el$, createComponent(Icon2, {
        get name() {
          return iconName();
        },
        size: 36
      })), createRenderEffect((_p$) => {
        var _v$ = hidden() ? "true" : "false", _v$2 = hidden() ? "none" : "flex", _v$3 = props.state.direction === "right" ? "6px" : "", _v$4 = hidden() ? "0" : String(0.35 + progress() * 0.65), _v$5 = props.state.direction === "left" ? "6px" : "", _v$6 = `translate(${offset()}px, -50%)`;
        return _v$ !== _p$.e && setAttribute(_el$, "aria-hidden", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "display", _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$, "left", _p$.a = _v$3), _v$4 !== _p$.o && setStyleProperty(_el$, "opacity", _p$.o = _v$4), _v$5 !== _p$.i && setStyleProperty(_el$, "right", _p$.i = _v$5), _v$6 !== _p$.n && setStyleProperty(_el$, "transform", _p$.n = _v$6), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0
      }), _el$;
    })();
  }

  // src/components/Enhance/PageSwipe.tsx
  var SWIPE_MIN_DISTANCE = 96, SWIPE_INTENT_DISTANCE = 28, HORIZONTAL_INTENT_RATIO = 2.2, SWIPE_MAX_VERTICAL_RATIO = 0.38;
  function PageSwipe(props) {
    let [indicator, setIndicator] = createSignal({
      blocked: !1,
      direction: "left",
      progress: 0
    }), directionFor = (dx) => dx < 0 ? "next" : "previous", reset2 = () => setIndicator((current) => ({
      ...current,
      blocked: !1,
      progress: 0
    }));
    return createPointerGestureElement(() => props.target(), () => ({
      onStart: reset2,
      onMove: (info) => {
        let direction = directionFor(info.dx);
        setIndicator({
          blocked: !props.canNavigate(direction),
          direction: direction === "next" ? "left" : "right",
          progress: Math.min(1, Math.max(0, (Math.abs(info.dx) - SWIPE_INTENT_DISTANCE) / (SWIPE_MIN_DISTANCE - SWIPE_INTENT_DISTANCE)))
        });
      },
      onEnd: (info, event) => {
        navigate(info, event), reset2();
      },
      dragAxis: "x",
      dragIntentRatio: HORIZONTAL_INTENT_RATIO,
      dragStartThreshold: SWIPE_INTENT_DISTANCE
    })), createComponent(SwipeIndicator, {
      get state() {
        return indicator();
      }
    });
    function navigate(info, event) {
      let absX = Math.abs(info.dx), absY = Math.abs(info.dy), direction = directionFor(info.dx);
      absX < SWIPE_MIN_DISTANCE || absY > absX * SWIPE_MAX_VERTICAL_RATIO || !props.canNavigate(direction) || (event.preventDefault(), props.onNavigate(direction));
    }
  }

  // src/components/Enhance/EnhanceSearchGrids.tsx
  function EnhanceSearchGrids(props) {
    let [gestureTarget, setGestureTarget] = createSignal(null), [loading, setLoading] = createSignal(!1), source = untrack(() => props.source), navigationLoading = !1, swipeUrl = (direction) => direction === "next" ? source.data.nextUrl : source.data.previousUrl, navigate = async (url) => {
      if (!navigationLoading) {
        navigationLoading = !0, setLoading(!0), source.handle.updateSearchLoading(!0);
        try {
          await source.handle.loadSearchPage(url);
          let nextSource = manageSearchResults();
          if (!nextSource)
            throw new Error(i18n_default.errors.searchPageContentNotFound);
          source = nextSource, props.onPageChange(source), source.handle.ensureSearchSwipeInput(), setGestureTarget(source.elems.resultList.Component()), source.handle.scrollSearchPageToInput();
        } catch (error) {
          console.error("[ehpeek]", error);
        } finally {
          navigationLoading = !1, setLoading(!1), source.handle.updateSearchLoading(!1);
        }
      }
    }, onNavigation = (url) => {
      navigate(url);
    };
    return onMount(() => {
      source.handle.ensureSearchSwipeInput(), setGestureTarget(source.elems.resultList.Component()), onCleanup(source.handle.interceptSearchNavigation(onNavigation));
    }), [createComponent(PageSwipe, {
      canNavigate: (direction) => !!swipeUrl(direction),
      onNavigate: (direction) => {
        let url = swipeUrl(direction);
        url && navigate(url);
      },
      target: gestureTarget
    }), createComponent(LoadingOverlay, {
      get label() {
        return i18n_default.common.status.loading;
      },
      get visible() {
        return loading();
      }
    })];
  }

  // src/components/Enhance/ScrollPageBar.tsx
  var _tmpl$6 = /* @__PURE__ */ template('<div class="w-full ui-mb-xs text-center textsize-sm">'), _tmpl$23 = /* @__PURE__ */ template('<a class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-transparent !text-[var(--color-site-text)] visited:!text-[var(--color-site-text)] hover:!bg-[var(--color-site-item-hover)] hover:!text-[var(--color-site-text)] active:!text-[var(--color-site-text)]">'), _tmpl$32 = /* @__PURE__ */ template('<td class="!ui-hit-w-sm !ui-hit-h-sm !p-0 ui-rounded-sm cursor-pointer text-center align-middle select-none">'), _tmpl$42 = /* @__PURE__ */ template("<span>"), _tmpl$52 = /* @__PURE__ */ template('<td class="!ui-hit-w-sm !ui-hit-h-sm !p-0 ui-rounded-sm cursor-pointer text-center align-middle select-none cursor-default"><span class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-transparent !text-[var(--color-site-text)] visited:!text-[var(--color-site-text)] hover:!bg-[var(--color-site-item-hover)] hover:!text-[var(--color-site-text)] active:!text-[var(--color-site-text)] invisible">'), _tmpl$62 = /* @__PURE__ */ template('<div><table class="border-separate border-spacing-[var(--ui-space-xs)]"><tbody><tr>'), _tmpl$7 = /* @__PURE__ */ template('<span class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)]"aria-current=page>'), DRAG_PIXEL_STEP = 18;
  var PAGE_BAR_LINK_CLASS = "flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline";
  var PAGE_BAR_CURRENT_COLOR_CLASS = "!border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)]", PAGE_BAR_DISABLED_COLOR_CLASS = "!border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)] opacity-40 cursor-default";
  function GalleryPageDescription(props) {
    return (() => {
      var _el$ = _tmpl$6();
      return insert(_el$, () => props.text), _el$;
    })();
  }
  function ScrollPageBar(props) {
    let maxIndex = createMemo(() => Math.max(0, props.maxIndex)), currentIndex = createMemo(() => clamp(props.currentIndex, 0, maxIndex())), [visibleCenterIndex, setVisibleCenterIndex] = createSignal(untrack(currentIndex)), gestureHost, dragStartVisibleCenterIndex = untrack(visibleCenterIndex), draggable = () => maxIndex() + 1 > 7, slots = createMemo(() => pageSlots(visibleCenterIndex(), maxIndex())), firstSlotIndex = createMemo(() => slots()[0] ?? currentIndex()), lastSlotIndex = createMemo(() => slots()[slots().length - 1] ?? currentIndex()), currentBeforeWindow = () => currentIndex() < firstSlotIndex(), currentAfterWindow = () => currentIndex() > lastSlotIndex(), scrollTargetForIndex = (pageIndex) => pageIndex === currentIndex() - 1 || pageIndex === maxIndex() ? "bottom" : "top";
    createEffect(() => {
      setVisibleCenterIndex(currentIndex());
    });
    let linkCell = (text, pageIndex, itemState = () => "link") => {
      let resolvedText = () => typeof text == "function" ? text() : text, resolvedPageIndex = () => typeof pageIndex == "function" ? pageIndex() : pageIndex;
      return (() => {
        var _el$2 = _tmpl$32();
        return insert(_el$2, createComponent(Show, {
          get when() {
            return itemState() === "link";
          },
          get fallback() {
            return (() => {
              var _el$4 = _tmpl$42();
              return insert(_el$4, resolvedText), createRenderEffect((_p$) => {
                var _v$ = `${PAGE_BAR_LINK_CLASS} ${itemState() === "current" ? PAGE_BAR_CURRENT_COLOR_CLASS : PAGE_BAR_DISABLED_COLOR_CLASS}`, _v$2 = itemState() === "current" ? "page" : void 0, _v$3 = itemState() === "disabled" ? "true" : void 0;
                return _v$ !== _p$.e && className(_el$4, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$4, "aria-current", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$4, "aria-disabled", _p$.a = _v$3), _p$;
              }, {
                e: void 0,
                t: void 0,
                a: void 0
              }), _el$4;
            })();
          },
          get children() {
            var _el$3 = _tmpl$23();
            return _el$3.$$click = (event) => {
              event.preventDefault(), event.stopPropagation(), props.onNavigate(resolvedPageIndex(), scrollTargetForIndex(resolvedPageIndex()));
            }, setAttribute(_el$3, "draggable", !1), insert(_el$3, resolvedText), createRenderEffect(() => setAttribute(_el$3, "href", props.urlForIndex(resolvedPageIndex()))), _el$3;
          }
        })), _el$2;
      })();
    }, emptyCell = () => (() => {
      var _el$5 = _tmpl$52(), _el$6 = _el$5.firstChild;
      return _el$5;
    })();
    return createPointerGestureElement(() => gestureHost, () => ({
      shouldCaptureDrag: draggable,
      dragAxis: "x",
      onStart: () => {
        dragStartVisibleCenterIndex = visibleCenterIndex();
      },
      onMove: (info) => {
        if (Math.abs(info.dx) < Math.abs(info.dy))
          return;
        let nextIndex = clamp(dragStartVisibleCenterIndex - acceleratedPageOffset(info.dx), 0, maxIndex());
        nextIndex !== visibleCenterIndex() && setVisibleCenterIndex(nextIndex);
      }
    })), (() => {
      var _el$7 = _tmpl$62(), _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _ref$ = gestureHost;
      return typeof _ref$ == "function" ? use(_ref$, _el$7) : gestureHost = _el$7, insert(_el$0, () => linkCell("<<", 0, () => currentIndex() === 0 ? "disabled" : "link"), null), insert(_el$0, createComponent(Show, {
        get when() {
          return currentBeforeWindow();
        },
        get fallback() {
          return emptyCell();
        },
        get children() {
          return linkCell(() => String(currentIndex() + 1), currentIndex, () => "current");
        }
      }), null), insert(_el$0, () => linkCell("<", () => Math.max(0, currentIndex() - 1), () => currentIndex() === 0 ? "disabled" : "link"), null), insert(_el$0, createComponent(For, {
        get each() {
          return slots();
        },
        children: (pageIndex) => {
          let itemState = createMemo(() => pageIndex === currentIndex() ? "current" : "link");
          return pageIndex !== null ? (() => {
            var _el$1 = _tmpl$32();
            return insert(_el$1, createComponent(Show, {
              get when() {
                return itemState() === "link";
              },
              get fallback() {
                return (() => {
                  var _el$11 = _tmpl$7();
                  return insert(_el$11, pageIndex + 1), _el$11;
                })();
              },
              get children() {
                var _el$10 = _tmpl$23();
                return _el$10.$$click = (event) => {
                  event.preventDefault(), event.stopPropagation(), props.onNavigate(pageIndex, scrollTargetForIndex(pageIndex));
                }, setAttribute(_el$10, "draggable", !1), insert(_el$10, pageIndex + 1), createRenderEffect(() => setAttribute(_el$10, "href", props.urlForIndex(pageIndex))), _el$10;
              }
            })), _el$1;
          })() : emptyCell();
        }
      }), null), insert(_el$0, () => linkCell(">", () => Math.min(maxIndex(), currentIndex() + 1), () => currentIndex() === maxIndex() ? "disabled" : "link"), null), insert(_el$0, createComponent(Show, {
        get when() {
          return currentAfterWindow();
        },
        get fallback() {
          return emptyCell();
        },
        get children() {
          return linkCell(() => String(currentIndex() + 1), currentIndex, () => "current");
        }
      }), null), insert(_el$0, () => linkCell(">>", maxIndex, () => currentIndex() === maxIndex() ? "disabled" : "link"), null), _el$7;
    })();
  }
  function pageSlots(visibleCenterIndex, maxIndex) {
    if (maxIndex + 1 <= 7)
      return range(0, maxIndex);
    let visibleStartIndex = clamp(visibleCenterIndex - 3, -1, maxIndex - 5);
    return range(visibleStartIndex, visibleStartIndex + 6).map((pageIndex) => pageIndex >= 0 && pageIndex <= maxIndex ? pageIndex : null);
  }
  function range(start, end) {
    let output = [];
    for (let index = start; index <= end; index += 1)
      output.push(index);
    return output;
  }
  function acceleratedPageOffset(dx) {
    let distance = Math.abs(dx), direction = dx > 0 ? 1 : -1, pages = Math.floor((distance / DRAG_PIXEL_STEP) ** 1.35);
    return direction * pages;
  }
  delegateEvents(["click"]);

  // src/components/Enhance/EnhanceThumbsGrids.tsx
  var SWIPE_MIN_DISTANCE2 = 96, SWIPE_INTENT_DISTANCE2 = 28, HORIZONTAL_INTENT_RATIO2 = 2.2, SWIPE_MAX_VERTICAL_RATIO2 = 0.38;
  function ThumbsGrids(props) {
    let pageBarSource = untrack(() => props.previewCache.current()), [pageBarCurrentIndex, setPageBarCurrentIndex] = createSignal(pageBarSource.data.currentIndex), [swipeIndicatorState, setSwipeIndicatorState] = createSignal({
      blocked: !1,
      direction: "left",
      progress: 0
    }), pageBarMaxIndex = () => props.previewCache.current().data.maxIndex, requestPreviewPage = (previewIndex, scrollToPageBar) => {
      let current = props.previewCache.current(), onLoadError = props.onLoadError;
      pageBarSource.handle.scrollPreviewPageBarIntoView(scrollToPageBar), previewIndex !== current.data.currentIndex && (setPageBarCurrentIndex(previewIndex), props.previewCache.select(previewIndex).then((next) => {
        untrack(() => props.previewCache.current()) === next && pageBarSource.handle.scrollPreviewPageBarIntoView(scrollToPageBar);
      }, (error) => {
        let cacheIndex = untrack(() => props.previewCache.current().data.currentIndex);
        setPageBarCurrentIndex((currentIndex) => currentIndex === previewIndex ? cacheIndex : currentIndex), onLoadError(error);
      }));
    }, swipeIndexForDelta = (dx) => {
      let current = props.previewCache.current().data, nextIndex = dx < 0 ? current.currentIndex + 1 : current.currentIndex - 1;
      return nextIndex < 0 || nextIndex > current.maxIndex ? null : nextIndex;
    }, hideSwipeIndicator = () => {
      setSwipeIndicatorState((current) => ({
        ...current,
        blocked: !1,
        progress: 0
      }));
    }, updateSwipeIndicator = (info) => {
      setSwipeIndicatorState({
        blocked: swipeIndexForDelta(info.dx) === null,
        direction: info.dx < 0 ? "left" : "right",
        progress: Math.min(1, Math.max(0, (Math.abs(info.dx) - SWIPE_INTENT_DISTANCE2) / (SWIPE_MIN_DISTANCE2 - SWIPE_INTENT_DISTANCE2)))
      });
    }, navigateBySwipe = (info, event) => {
      let absX = Math.abs(info.dx), absY = Math.abs(info.dy);
      if (absX < SWIPE_MIN_DISTANCE2 || absY > absX * SWIPE_MAX_VERTICAL_RATIO2)
        return;
      let previewIndex = swipeIndexForDelta(info.dx);
      previewIndex !== null && (event.preventDefault(), requestPreviewPage(previewIndex, info.dx < 0 ? "top" : "bottom"));
    }, actions = {
      gotoPreview: setPageBarCurrentIndex
    };
    untrack(() => props.coordinator).attachThumbs(actions), createEffect((previous) => {
      let current = props.previewCache.current();
      return setPageBarCurrentIndex(current.data.currentIndex), current.handle.ensurePreviewSwipeInput(), current !== previous && pageBarSource.handle.replacePreviewThumbs(current.elems.thumbItems), current;
    }, pageBarSource), createEffect(() => {
      pageBarSource.handle.updatePreviewLoading(props.previewCache.loading());
    }), onCleanup(() => {
      pageBarSource.handle.updatePreviewLoading(!1);
    }), createPointerGestureElement(() => pageBarSource.elems.thumbs?.Component() ?? null, () => ({
      onStart: hideSwipeIndicator,
      onMove: updateSwipeIndicator,
      onEnd: (info, event) => {
        navigateBySwipe(info, event), hideSwipeIndicator();
      },
      dragAxis: "x",
      dragIntentRatio: HORIZONTAL_INTENT_RATIO2,
      dragStartThreshold: SWIPE_INTENT_DISTANCE2
    })), pageBarSource.handle.installPreviewPageBars(), pageBarSource.elems.pageBarDescription?.mount(() => createComponent(GalleryPageDescription, {
      get text() {
        return props.previewCache.current().data.descriptionText;
      }
    }));
    for (let element of [pageBarSource.elems.pageBarTop, pageBarSource.elems.pageBarBottom])
      element && element.mount(() => createComponent(ScrollPageBar, {
        get currentIndex() {
          return pageBarCurrentIndex();
        },
        get maxIndex() {
          return pageBarMaxIndex();
        },
        onNavigate: requestPreviewPage,
        urlForIndex: (index) => previewUrlForIndex(index, props.previewCache.current().data.currentUrl)
      }));
    return onCleanup(() => {
      pageBarSource.elems.pageBarDescription?.remove(), pageBarSource.elems.pageBarTop?.remove(), pageBarSource.elems.pageBarBottom?.remove();
    }), [createComponent(LoadingOverlay, {
      get label() {
        return i18n_default.common.status.loading;
      },
      get visible() {
        return props.previewCache.loading();
      }
    }), createComponent(SwipeIndicator, {
      get state() {
        return swipeIndicatorState();
      }
    })];
  }

  // src/App/viewport.ts
  function lockPageThemeColor(color) {
    let existing = document.querySelector(
      'meta[name="theme-color"]'
    ), meta = existing ?? document.createElement("meta"), previousContent = existing?.getAttribute("content") ?? null;
    return existing || (meta.name = "theme-color", document.head.append(meta)), meta.content = color, () => {
      existing ? previousContent === null ? meta.removeAttribute("content") : meta.content = previousContent : meta.remove();
    };
  }
  function lockPageScroll() {
    let documentElement = document.documentElement, body = document.body, documentOverflow = documentElement.style.overflow, bodyOverflow = body.style.overflow;
    return documentElement.style.overflow = "hidden", body.style.overflow = "hidden", () => {
      documentElement.style.overflow = documentOverflow, body.style.overflow = bodyOverflow;
    };
  }
  function prepareFullscreenSnapshot() {
    let existing = document.querySelector(
      'meta[name="viewport"]'
    ), meta = existing ?? document.createElement("meta"), scale = Math.max(0.1, window.visualViewport?.scale ?? 1), snapshot = {
      content: existing?.getAttribute("content") ?? null,
      created: !existing,
      meta,
      scale,
      scrollX: window.scrollX,
      scrollY: window.scrollY
    };
    return existing || (meta.name = "viewport", document.head.append(meta)), meta.content = lockedViewportContent(snapshot.content, scale), snapshot;
  }
  async function restorePageViewport(snapshot) {
    await nextAnimationFrame(), restoreViewportMeta(snapshot), await nextAnimationFrame(), snapshot.meta.isConnected || (snapshot.meta.name = "viewport", document.head.append(snapshot.meta)), snapshot.meta.content = lockedViewportContent(snapshot.content, snapshot.scale), await waitForViewportSettled(), restoreViewportMeta(snapshot), await nextAnimationFrame(), await nextAnimationFrame(), window.scrollTo(snapshot.scrollX, snapshot.scrollY);
  }
  function restoreViewportMeta(snapshot) {
    snapshot.created ? snapshot.meta.remove() : snapshot.content === null ? snapshot.meta.removeAttribute("content") : snapshot.meta.content = snapshot.content;
  }
  function createFullscreenController(target, onScaleChange = () => {
  }) {
    let snapshot = null, restorePromise = null, active = () => {
      let fullscreenElement = document.fullscreenElement;
      return fullscreenElement === target || fullscreenElement instanceof HTMLElement && fullscreenElement.contains(target);
    }, restore = () => {
      if (restorePromise)
        return restorePromise;
      onScaleChange(1);
      let captured = snapshot;
      return captured ? (restorePromise = waitForViewportSettled().then(() => restorePageViewport(captured)).finally(() => {
        restorePromise = null;
      }), restorePromise) : Promise.resolve();
    };
    return {
      active,
      enter: async () => {
        if (document.fullscreenElement || !document.fullscreenEnabled)
          return;
        await restorePromise, snapshot = prepareFullscreenSnapshot();
        let scaleBefore = snapshot.scale;
        try {
          await target.requestFullscreen(), await nextAnimationFrame();
          let scaleAfter = Math.max(0.01, window.visualViewport?.scale ?? 1), scale = Math.min(1, Math.max(0.1, scaleBefore / scaleAfter));
          onScaleChange(scale);
        } catch (error) {
          throw await restore(), error;
        }
      },
      exit: async () => {
        active() && await document.exitFullscreen(), await restore(), onScaleChange(1);
      },
      restore,
      subscribe: (callback) => {
        let onChange = () => {
          let fullscreenActive = active();
          fullscreenActive || (onScaleChange(1), restore()), callback(fullscreenActive);
        };
        return document.addEventListener("fullscreenchange", onChange), () => document.removeEventListener("fullscreenchange", onChange);
      }
    };
  }
  function nextAnimationFrame() {
    return new Promise((resolve) => {
      window.requestAnimationFrame(() => resolve());
    });
  }
  function lockedViewportContent(content, scale) {
    let preserved = (content ?? "").split(",").map((item) => item.trim()).filter(
      (item) => item && !/^(?:initial-scale|minimum-scale|maximum-scale|user-scalable|viewport-fit)\s*=/i.test(item)
    ), value = String(Math.round(scale * 1e3) / 1e3);
    return [
      ...preserved,
      `initial-scale=${value}`,
      `minimum-scale=${value}`,
      `maximum-scale=${value}`,
      "user-scalable=no",
      "viewport-fit=cover"
    ].join(", ");
  }
  async function waitForViewportSettled() {
    await nextAnimationFrame(), await new Promise((resolve) => {
      let viewport = window.visualViewport, quietTimer = window.setTimeout(finish, 80), timeoutTimer = window.setTimeout(finish, 500), onResize = () => {
        window.clearTimeout(quietTimer), quietTimer = window.setTimeout(finish, 80);
      };
      function finish() {
        viewport?.removeEventListener("resize", onResize), window.clearTimeout(quietTimer), window.clearTimeout(timeoutTimer), resolve();
      }
      viewport?.addEventListener("resize", onResize);
    }), await nextAnimationFrame();
  }

  // src/App/OverlayHost.tsx
  function createOverlayHost(parent, initialUiScale) {
    let element = document.createElement("div");
    element.dataset.ehpeekOverlayHost = "true", parent.append(element), markUiRoot(element);
    let uiScale = initialUiScale, fullscreenScale = 1, [fullscreenPixelScale, setFullscreenPixelScale] = createSignal(1), applyScale = () => applyUiScale(uiScale, element, fullscreenScale), fullscreen = createFullscreenController(element, (factor) => {
      fullscreenScale = factor, setFullscreenPixelScale(factor), applyScale();
    });
    return applyScale(), {
      element,
      fullscreen,
      fullscreenPixelScale,
      setUiScale: (scale) => {
        uiScale = scale, applyScale();
      }
    };
  }
  var OverlayHostContext = createContext();
  function OverlayHostProvider(props) {
    let host = untrack(() => props.host);
    return createComponent(OverlayHostContext.Provider, {
      value: host,
      get children() {
        return props.children;
      }
    });
  }
  function OverlayPortal(props) {
    let host = useOverlayHost();
    return createComponent(Portal, {
      get mount() {
        return host.element;
      },
      get children() {
        return props.children;
      }
    });
  }
  function useOverlayHost() {
    let host = useContext(OverlayHostContext);
    if (!host)
      throw new Error("OverlayHostProvider is required for overlay content.");
    return host;
  }

  // src/components/animation.ts
  var SCROLL_ANIMATION_MS = 180, SCROLL_EASING_POWER = 3, ANIMATION_FRAME_MIN_DELTA_MS = 1, ANIMATION_FRAME_MAX_DELTA_MS = 32, SCROLL_FLING_MIN_VELOCITY = 0.35, SCROLL_FLING_STOP_VELOCITY = 0.02, SCROLL_FLING_DECAY = 45e-4, ScrollAnimator = class {
    constructor(axis) {
      this.axis = axis;
      this.frame = null;
    }
    scrollTo(scroller, target, motion = "instant", onComplete) {
      if (this.cancel(), motion !== "animated") {
        this.setScrollPosition(scroller, target), onComplete?.();
        return;
      }
      this.scrollWithRaf(scroller, target, onComplete);
    }
    cancel() {
      this.frame !== null && (window.cancelAnimationFrame(this.frame), this.frame = null);
    }
    scrollWithRaf(scroller, target, onComplete) {
      let start = this.scrollPosition(scroller), delta = target - start, lastFrameTime = performance.now(), animationTime = 0, step = (time) => {
        let elapsed = clamp(time - lastFrameTime, ANIMATION_FRAME_MIN_DELTA_MS, ANIMATION_FRAME_MAX_DELTA_MS);
        lastFrameTime = time, animationTime += elapsed;
        let progress = clamp(animationTime / SCROLL_ANIMATION_MS, 0, 1), eased = 1 - Math.pow(1 - progress, SCROLL_EASING_POWER);
        if (this.setScrollPosition(scroller, start + delta * eased), progress >= 1) {
          this.frame = null, onComplete?.();
          return;
        }
        this.frame = window.requestAnimationFrame(step);
      };
      this.frame = window.requestAnimationFrame(step);
    }
    scrollPosition(scroller) {
      return this.axis === "x" ? scroller.scrollLeft : scroller.scrollTop;
    }
    setScrollPosition(scroller, value) {
      this.axis === "x" ? scroller.scrollLeft = value : scroller.scrollTop = value;
    }
  }, ScrollFlingAnimator = class {
    constructor() {
      this.frame = null;
      this.velocity = 0;
      this.lastFrameTime = 0;
    }
    start(options) {
      this.cancel();
      let initialVelocity = options.maxVelocity ? clamp(options.initialVelocity, -options.maxVelocity, options.maxVelocity) : options.initialVelocity;
      if (Math.abs(initialVelocity) < SCROLL_FLING_MIN_VELOCITY)
        return;
      this.velocity = initialVelocity, this.lastFrameTime = performance.now();
      let step = (time) => {
        if (!options.canRun()) {
          this.cancel();
          return;
        }
        let elapsed = clamp(time - this.lastFrameTime, ANIMATION_FRAME_MIN_DELTA_MS, ANIMATION_FRAME_MAX_DELTA_MS);
        this.lastFrameTime = time;
        let previousPosition = options.axis === "x" ? options.scroller.scrollLeft : options.scroller.scrollTop;
        if (options.setScrollPosition(previousPosition + this.velocity * elapsed), (options.axis === "x" ? options.scroller.scrollLeft : options.scroller.scrollTop) === previousPosition) {
          this.cancel(), options.onStop();
          return;
        }
        if (this.velocity *= Math.exp(-SCROLL_FLING_DECAY * elapsed), Math.abs(this.velocity) < SCROLL_FLING_STOP_VELOCITY) {
          this.cancel(), options.onStop();
          return;
        }
        this.frame = window.requestAnimationFrame(step);
      };
      this.frame = window.requestAnimationFrame(step);
    }
    cancel() {
      this.frame !== null && (window.cancelAnimationFrame(this.frame), this.frame = null), this.velocity = 0;
    }
  };

  // src/components/Widgets/PositionBar.tsx
  var _tmpl$8 = /* @__PURE__ */ template("<div aria-orientation=horizontal role=scrollbar><div></div><div><span style=transform-origin:bottom>"), _tmpl$24 = /* @__PURE__ */ template("<div aria-orientation=vertical role=scrollbar><div></div><div><span style=transform-origin:right>"), VERTICAL_FILL = {
    narrow: {
      collapsed: "w-8px",
      expanded: "w-16px"
    },
    normal: {
      collapsed: "w-24px",
      expanded: "w-32px"
    }
  }, HORIZONTAL_FILL = {
    narrow: "h-8px",
    normal: "h-24px"
  }, POSITION_BAR_FILL = "bg-[var(--color-reader-scrollbar,var(--color-muted))]", POSITION_BAR_TRACK = "bg-[var(--color-reader-border,var(--color-border))]";
  function PositionBar(props) {
    let [dragging, setDragging] = createSignal(!1), track, thumb, dragOffset = 0, axis = untrack(() => props.axis), thickness = untrack(() => props.thickness ?? "normal"), horizontal = axis === "horizontal", minValue = () => props.minValue ?? 1, valueRange = () => Math.max(0, props.maxValue - minValue()), expanded = () => !!props.expanded || dragging(), visible = () => props.visible !== !1 || dragging(), logicalPosition = () => valueRange() === 0 ? 0 : (props.currentValue - minValue()) / valueRange() * 100, visualPosition = () => horizontal && props.reversed ? 100 - logicalPosition() : logicalPosition(), thumbRatio = () => clamp(props.visibleRatio ?? (props.visibleValueCount ?? 1) / Math.max(1, valueRange() + 1), 0, 1), draggable = () => valueRange() > 0 && thumbRatio() < 1, coordinate = (event) => horizontal ? event.clientX : event.clientY, valueAt = (pointerCoordinate) => {
      let trackRect = track.getBoundingClientRect(), trackStart = horizontal ? trackRect.left : trackRect.top, trackLength = horizontal ? trackRect.width : trackRect.height, thumbLength = horizontal ? thumb.offsetWidth : thumb.offsetHeight, visualRatio = clamp((pointerCoordinate - trackStart - dragOffset) / Math.max(1, trackLength - thumbLength), 0, 1), ratio = horizontal && props.reversed ? 1 - visualRatio : visualRatio;
      return Math.round(minValue() + ratio * valueRange());
    }, inputAt = (event) => {
      let value = valueAt(coordinate(event));
      return props.onInput(value), value;
    }, onPointerDown = (event) => {
      if (event.preventDefault(), event.stopPropagation(), !draggable())
        return;
      let thumbPressed = event.target instanceof Node && thumb.contains(event.target);
      if (!thumbPressed && props.trackClickEnabled === !1)
        return;
      setDragging(!0), track.setPointerCapture(event.pointerId);
      let thumbRect = thumb.getBoundingClientRect();
      dragOffset = thumbPressed ? coordinate(event) - (horizontal ? thumbRect.left : thumbRect.top) : (horizontal ? thumbRect.width : thumbRect.height) / 2, props.onPointerDown?.(event), inputAt(event);
    }, onPointerMove = (event) => {
      dragging() && inputAt(event);
    }, onPointerUp = (event) => {
      if (!dragging())
        return;
      setDragging(!1);
      let value = inputAt(event);
      track.releasePointerCapture(event.pointerId), props.onCommit?.(value);
    }, onPointerCancel = (event) => {
      dragging() && (setDragging(!1), track.releasePointerCapture(event.pointerId), props.onCommit?.(props.currentValue));
    }, stopClick = (event) => event.stopPropagation(), stopContextMenu = (event) => {
      event.preventDefault(), event.stopPropagation();
    }, stopWheel = (event) => event.stopPropagation(), renderHorizontal = () => (() => {
      var _el$ = _tmpl$8(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild;
      _el$.addEventListener("wheel", stopWheel), _el$.$$pointerup = onPointerUp, _el$.$$pointermove = onPointerMove, _el$.$$pointerdown = onPointerDown, _el$.addEventListener("pointercancel", onPointerCancel), _el$.$$contextmenu = stopContextMenu, _el$.$$click = stopClick;
      var _ref$ = track;
      typeof _ref$ == "function" ? use(_ref$, _el$) : track = _el$;
      var _ref$2 = thumb;
      return typeof _ref$2 == "function" ? use(_ref$2, _el$3) : thumb = _el$3, createRenderEffect((_p$) => {
        var _v$ = `${props.position === "fixed" ? "fixed" : "absolute"} inset-x-0 bottom-0 z-2 ui-h-xl touch-none select-none`, _v$2 = props.ariaLabel, _v$3 = !draggable(), _v$4 = props.maxValue, _v$5 = minValue(), _v$6 = props.currentValue, _v$7 = `absolute inset-x-0 bottom-4px h-6px ${props.trackVisible === !1 ? "bg-transparent" : POSITION_BAR_TRACK}`, _v$8 = `absolute bottom-0 flex ui-h-xl items-end ${draggable() ? "cursor-grab active:cursor-grabbing" : "cursor-default"}`, _v$9 = `${visualPosition()}%`, _v$0 = `translateX(-${visualPosition()}%)`, _v$1 = `clamp(var(--ui-control-size-md), ${thumbRatio() * 100}%, 100%)`, _v$10 = `block w-full ${HORIZONTAL_FILL[thickness]} rounded-t-md ${POSITION_BAR_FILL} shadow-[0_2px_10px_var(--color-shadow-control)]`, _v$11 = `scaleY(${props.pixelScale ?? 1})`;
        return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "aria-label", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "aria-disabled", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$, "aria-valuemax", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$, "aria-valuemin", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$, "aria-valuenow", _p$.n = _v$6), _v$7 !== _p$.s && className(_el$2, _p$.s = _v$7), _v$8 !== _p$.h && className(_el$3, _p$.h = _v$8), _v$9 !== _p$.r && setStyleProperty(_el$3, "left", _p$.r = _v$9), _v$0 !== _p$.d && setStyleProperty(_el$3, "transform", _p$.d = _v$0), _v$1 !== _p$.l && setStyleProperty(_el$3, "width", _p$.l = _v$1), _v$10 !== _p$.u && className(_el$4, _p$.u = _v$10), _v$11 !== _p$.c && setStyleProperty(_el$4, "transform", _p$.c = _v$11), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0,
        h: void 0,
        r: void 0,
        d: void 0,
        l: void 0,
        u: void 0,
        c: void 0
      }), _el$;
    })(), interactionSize = () => expanded() ? "ui-hit-w-sm" : "ui-w-xl", fillSize = () => expanded() ? VERTICAL_FILL[thickness].expanded : VERTICAL_FILL[thickness].collapsed, renderVertical = () => (() => {
      var _el$5 = _tmpl$24(), _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$7.firstChild;
      _el$5.addEventListener("wheel", stopWheel), _el$5.$$pointerup = onPointerUp, _el$5.$$pointermove = onPointerMove, _el$5.$$pointerdown = onPointerDown, _el$5.addEventListener("pointercancel", onPointerCancel), _el$5.$$contextmenu = stopContextMenu, _el$5.$$click = stopClick;
      var _ref$3 = track;
      typeof _ref$3 == "function" ? use(_ref$3, _el$5) : track = _el$5;
      var _ref$4 = thumb;
      return typeof _ref$4 == "function" ? use(_ref$4, _el$7) : thumb = _el$7, createRenderEffect((_p$) => {
        var _v$12 = `${props.position === "fixed" ? "fixed" : "absolute"} inset-y-0 right-0 z-2 ${interactionSize()} touch-none select-none transition-[width,opacity] duration-160 ease-in-out [--ehpeek-position-bar-thumb-min:calc(var(--ui-control-size-md)*1.5)] ${visible() ? "opacity-100" : "opacity-0 pointer-events-none"}`, _v$13 = props.ariaLabel, _v$14 = !draggable(), _v$15 = props.maxValue, _v$16 = minValue(), _v$17 = props.currentValue, _v$18 = `absolute inset-y-0 right-4px w-6px ${props.trackVisible === !1 ? "bg-transparent" : POSITION_BAR_TRACK}`, _v$19 = `absolute right-0 flex ${interactionSize()} items-center justify-end ${draggable() ? "cursor-grab active:cursor-grabbing" : "cursor-default"} transition-[width,height] duration-160`, _v$20 = `clamp(var(--ehpeek-position-bar-thumb-min), ${thumbRatio() * 100}%, 100%)`, _v$21 = `${visualPosition()}%`, _v$22 = `translateY(-${visualPosition()}%)`, _v$23 = `block h-full rounded-l-md ${POSITION_BAR_FILL} ${fillSize()} shadow-[0_2px_10px_var(--color-shadow-control)] transition-[width,opacity] duration-160`, _v$24 = `scaleX(${props.pixelScale ?? 1})`;
        return _v$12 !== _p$.e && className(_el$5, _p$.e = _v$12), _v$13 !== _p$.t && setAttribute(_el$5, "aria-label", _p$.t = _v$13), _v$14 !== _p$.a && setAttribute(_el$5, "aria-disabled", _p$.a = _v$14), _v$15 !== _p$.o && setAttribute(_el$5, "aria-valuemax", _p$.o = _v$15), _v$16 !== _p$.i && setAttribute(_el$5, "aria-valuemin", _p$.i = _v$16), _v$17 !== _p$.n && setAttribute(_el$5, "aria-valuenow", _p$.n = _v$17), _v$18 !== _p$.s && className(_el$6, _p$.s = _v$18), _v$19 !== _p$.h && className(_el$7, _p$.h = _v$19), _v$20 !== _p$.r && setStyleProperty(_el$7, "height", _p$.r = _v$20), _v$21 !== _p$.d && setStyleProperty(_el$7, "top", _p$.d = _v$21), _v$22 !== _p$.l && setStyleProperty(_el$7, "transform", _p$.l = _v$22), _v$23 !== _p$.u && className(_el$8, _p$.u = _v$23), _v$24 !== _p$.c && setStyleProperty(_el$8, "transform", _p$.c = _v$24), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0,
        h: void 0,
        r: void 0,
        d: void 0,
        l: void 0,
        u: void 0,
        c: void 0
      }), _el$5;
    })();
    return memo(() => horizontal ? renderHorizontal() : renderVertical());
  }
  delegateEvents(["click", "contextmenu", "pointerdown", "pointermove", "pointerup"]);

  // src/components/Widgets/PriorityLoadQueue.ts
  var PriorityLoadQueue = class {
    constructor(concurrentLoads = 6) {
      this.concurrentLoads = concurrentLoads;
      this.pending = /* @__PURE__ */ new Map();
      this.active = /* @__PURE__ */ new Set();
      this.timer = null;
      this.disposed = !1;
      this.callbacks = {};
    }
    updateCallbacks(callbacks) {
      this.callbacks = callbacks, this.schedule();
    }
    dispose() {
      this.disposed = !0, this.pending.clear(), this.timer !== null && (window.clearTimeout(this.timer), this.timer = null);
    }
    sync(targets) {
      this.pending = new Map(targets.filter(({ key }) => !this.active.has(key)).map((target) => [target.key, target])), this.schedule();
    }
    schedule() {
      this.timer !== null || this.disposed || !this.callbacks.loadTarget || (this.timer = window.setTimeout(() => {
        this.timer = null, this.process();
      }, 0));
    }
    process() {
      if (!this.disposed)
        for (; this.active.size < this.concurrentLoads; ) {
          let next = Array.from(this.pending.values()).sort((left, right) => left.priority - right.priority)[0];
          if (!next)
            return;
          this.pending.delete(next.key), this.start(next);
        }
    }
    start({ key, target }) {
      let { loadTarget, markLoading, onLoaded, onError } = this.callbacks;
      if (!loadTarget || !markLoading || !onLoaded || !onError)
        return;
      let token = markLoading(target);
      token !== null && (this.active.add(key), loadTarget(target).then(async (loaded) => {
        this.disposed || await onLoaded(target, loaded, token);
      }).catch((error) => {
        this.disposed || onError(target, error, token);
      }).finally(() => {
        this.active.delete(key), this.process();
      }));
    }
  };

  // src/components/Enhance/ScrollPreview.tsx
  var _tmpl$9 = /* @__PURE__ */ template('<span class="block w-[var(--ui-icon-size-sm)] h-[var(--ui-icon-size-sm)] box-border animate-spin rounded-full border-2px border-solid ehp-color-spinner">'), _tmpl$25 = /* @__PURE__ */ template('<div><span class="flex items-center ui-gap-sm opacity-75"></span><div><button type=button></button><button type=button></button><button type=button></button><button type=button></button><button type=button>'), _tmpl$33 = /* @__PURE__ */ template('<div class="grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] min-h-[var(--ui-control-size-xs)] flex-none items-center ui-gap-xs ui-px-xs ui-py-xs border-0 border-b ehp-color-site-border-subtle-b bg-[var(--color-site-elevated)] textsize-xs"><span class="col-start-2 inline-flex min-h-[var(--ui-control-size-xs)] items-center ui-gap-xs ui-px-sm ui-rounded-xs bg-[var(--color-site-surface)] opacity-75"></span><div><button type=button class="inline-flex w-[var(--ui-control-size-xs)] h-[var(--ui-control-size-xs)] items-center justify-center p-0 ui-rounded-xs border-0 bg-[var(--color-site-surface)] ehp-color-site-text cursor-pointer active:scale-96"></button><button type=button class="inline-flex w-[var(--ui-control-size-xs)] h-[var(--ui-control-size-xs)] items-center justify-center p-0 ui-rounded-xs border-0 bg-[var(--color-site-surface)] ehp-color-site-text cursor-pointer active:scale-96"></button><button type=button class="inline-flex w-[var(--ui-control-size-xs)] h-[var(--ui-control-size-xs)] items-center justify-center p-0 ui-rounded-xs border-0 bg-[var(--color-site-surface)] ehp-color-site-text cursor-pointer active:scale-96"></button><button type=button class="inline-flex w-[var(--ui-control-size-xs)] h-[var(--ui-control-size-xs)] items-center justify-center p-0 ui-rounded-xs border-0 bg-[var(--color-site-surface)] ehp-color-site-text cursor-pointer active:scale-96">'), _tmpl$43 = /* @__PURE__ */ template('<div class="relative min-h-0 w-full flex-1"><div class="absolute box-border bg-[var(--color-surface)] cursor-grab [&amp;[data-dragging=true]]:cursor-grabbing [&amp;[data-dragging=true]]:select-none [scrollbar-width:none] [&amp;::-webkit-scrollbar]:hidden [-webkit-overflow-scrolling:touch]"><div class=relative>'), _tmpl$53 = /* @__PURE__ */ template("<div class=absolute>"), _tmpl$63 = /* @__PURE__ */ template('<div class="flex w-full justify-center ui-my-sm"><button type=button class="inline-flex min-h-[var(--ui-control-size-xs)] items-center justify-center ui-gap-sm ui-px-md ui-rounded-xl border-0 bg-[var(--color-site-surface)] ehp-color-site-text font-sans textsize-sm font-700 cursor-pointer transition-[background-color,transform] duration-120 hover:bg-[var(--color-site-item-hover)] active:scale-98">'), _tmpl$72 = /* @__PURE__ */ template('<div><section class="box-border flex flex-col overflow-hidden text-[var(--color-text)] font-sans textsize-md leading-[1.4]">'), _tmpl$82 = /* @__PURE__ */ template('<div class="relative flex w-full min-w-0 items-start overflow-hidden rounded-sm bg-[var(--color-background)]">'), _tmpl$92 = /* @__PURE__ */ template('<button type=button class="flex w-full h-full flex-col items-center justify-center ui-gap-sm border-0 !bg-transparent text-[var(--color-text)] font-inherit textsize-sm cursor-default"><span>'), _tmpl$0 = /* @__PURE__ */ template('<span class="pointer-events-none block flex-none"role=img>'), _tmpl$1 = /* @__PURE__ */ template('<a class="absolute inset-0 text-[var(--color-text)] no-underline hover:no-underline active:no-underline">'), _tmpl$10 = /* @__PURE__ */ template('<span class="pointer-events-none absolute inset-0 z-1 box-border rounded-sm border-6 border-solid border-[var(--color-danger)]"aria-hidden=true>'), _tmpl$11 = /* @__PURE__ */ template('<img class="pointer-events-none block object-contain select-none [-webkit-user-drag:none]"alt decoding=async>'), GRID_GAP = 8, HORIZONTAL_FLING_VELOCITY_FACTOR = 1.6, MAX_TILE_WIDTH = 220, REFERENCE_PORTRAIT_ASPECT_RATIO = 7 / 5, MAX_CROSS_COUNT = 12, OVERSCAN_ROWS = 4, SCROLL_PIXEL_EPSILON = 1, PREVIEW_CONCURRENT_LOADS = 2, PREVIEW_LOAD_RADIUS = 2, OVERLAY_PREVIEW_ACTION_CLASS = ["inline-flex h-[var(--ui-control-size-md)] items-center justify-center py-0 ui-rounded-md border-0 bg-transparent text-[var(--color-site-text)] cursor-pointer font-sans textsize-sm font-700 leading-1", "opacity-90 hover:opacity-100 hover:bg-[var(--color-site-page)] focus-visible:opacity-100 disabled:opacity-40 disabled:cursor-default transition-[opacity,background-color] duration-160"].join(" "), OVERLAY_PREVIEW_ICON_ACTION_CLASS = `${OVERLAY_PREVIEW_ACTION_CLASS} w-[var(--ui-control-size-md)] px-0`, DECODE_CACHE_BYTES = 64 * 1024 * 1024, DECODE_CACHE_ITEMS = 160, NEXT_SCROLL_PREVIEW_DIRECTION = {
    ltr: "rtl",
    rtl: "ttb",
    ttb: "ltr"
  };
  function createPreviewLoading(options) {
    let queue = new PriorityLoadQueue(PREVIEW_CONCURRENT_LOADS), requestedIndexes = /* @__PURE__ */ new Set(), [failedIndexes, setFailedIndexes] = createSignal(/* @__PURE__ */ new Set()), [loadingCount, setLoadingCount] = createSignal(0), loadToken = 0, sync = (centerIndex, retryIndex) => {
      let firstIndex = Math.max(0, centerIndex - PREVIEW_LOAD_RADIUS), lastIndex = Math.min(options.maxPreviewIndex, centerIndex + PREVIEW_LOAD_RADIUS), targets = [];
      for (let previewIndex = firstIndex; previewIndex <= lastIndex; previewIndex += 1)
        targets.push({
          key: previewIndex,
          priority: previewIndex === retryIndex ? -1 : Math.abs(previewIndex - centerIndex),
          target: previewIndex
        });
      queue.sync(targets);
    };
    return queue.updateCallbacks({
      loadTarget: (previewIndex) => options.previewCache.load(previewIndex),
      markLoading: (previewIndex) => requestedIndexes.has(previewIndex) ? null : (requestedIndexes.add(previewIndex), setFailedIndexes((current) => {
        if (!current.has(previewIndex))
          return current;
        let next = new Set(current);
        return next.delete(previewIndex), next;
      }), setLoadingCount((count) => count + 1), ++loadToken),
      onLoaded: (previewIndex, loaded) => {
        previewIndex === options.aspectPreviewIndex && options.onAspectRatio(loaded.data.dominantAspectRatio), setLoadingCount((count) => Math.max(0, count - 1));
      },
      onError: (previewIndex, error) => {
        requestedIndexes.delete(previewIndex), setFailedIndexes((current) => new Set(current).add(previewIndex)), setLoadingCount((count) => Math.max(0, count - 1)), options.onLoadError(error);
      }
    }), createEffect(() => {
      options.ready() && sync(options.previewCache.previewIndexForPage(options.centeredPageNum()));
    }), onCleanup(() => queue.dispose()), {
      failedIndexes,
      loadingCount,
      retry(pageNum) {
        let retryIndex = options.previewCache.previewIndexForPage(pageNum);
        sync(options.previewCache.previewIndexForPage(options.centeredPageNum()), retryIndex);
      }
    };
  }
  function OverlayPreviewToolbar(props) {
    return (() => {
      var _el$ = _tmpl$25(), _el$2 = _el$.firstChild, _el$4 = _el$2.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling, _el$8 = _el$7.nextSibling, _el$9 = _el$8.nextSibling;
      return insert(_el$2, createComponent(Show, {
        get when() {
          return props.state.loading();
        },
        get children() {
          return _tmpl$9();
        }
      }), null), insert(_el$2, () => props.state.rangeText(), null), _el$5.$$click = () => props.state.onDirectionChange(), className(_el$5, OVERLAY_PREVIEW_ICON_ACTION_CLASS), insert(_el$5, createComponent(Icon2, {
        get name() {
          return props.state.directionIcon;
        },
        size: "var(--ui-icon-size-md)"
      })), _el$6.$$click = () => props.state.onZoomOut(), className(_el$6, OVERLAY_PREVIEW_ICON_ACTION_CLASS), insert(_el$6, createComponent(Icon2, {
        name: "zoom-out",
        size: "var(--ui-icon-size-md)"
      })), _el$7.$$click = () => props.state.onZoomIn(), className(_el$7, OVERLAY_PREVIEW_ICON_ACTION_CLASS), insert(_el$7, createComponent(Icon2, {
        name: "zoom-in",
        size: "var(--ui-icon-size-md)"
      })), _el$8.$$click = () => props.onCurrent(), className(_el$8, OVERLAY_PREVIEW_ICON_ACTION_CLASS), insert(_el$8, createComponent(Icon2, {
        name: "locate",
        size: "var(--ui-icon-size-md)"
      })), _el$9.$$click = () => props.onClose(), className(_el$9, OVERLAY_PREVIEW_ICON_ACTION_CLASS), insert(_el$9, createComponent(Icon2, {
        name: "close",
        size: "var(--ui-icon-size-md)"
      })), createRenderEffect((_p$) => {
        var _v$ = `flex min-h-[var(--ui-control-size-md)] flex-none items-center justify-between ui-gap-md bg-[var(--color-site-elevated)] safe-pt-sm safe-pr-sm ui-pb-sm safe-pl-sm border-0 border-b border-[var(--color-site-border)] text-[var(--color-site-text)] textsize-sm${props.state.leftHanded() ? " flex-row-reverse" : ""}`, _v$2 = `flex flex-none ui-gap-sm${props.state.leftHanded() ? " flex-row-reverse" : ""}`, _v$3 = props.state.directionLabel, _v$4 = props.state.directionLabel, _v$5 = i18n_default.common.actions.zoomOut, _v$6 = i18n_default.common.actions.zoomOut, _v$7 = props.state.zoomOutDisabled(), _v$8 = i18n_default.common.actions.zoomIn, _v$9 = i18n_default.common.actions.zoomIn, _v$0 = props.state.zoomInDisabled(), _v$1 = i18n_default.common.actions.current, _v$10 = i18n_default.common.actions.current, _v$11 = props.currentDisabled, _v$12 = i18n_default.common.actions.close, _v$13 = i18n_default.common.actions.close;
        return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && className(_el$4, _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$5, "aria-label", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$5, "title", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$6, "aria-label", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$6, "title", _p$.n = _v$6), _v$7 !== _p$.s && (_el$6.disabled = _p$.s = _v$7), _v$8 !== _p$.h && setAttribute(_el$7, "aria-label", _p$.h = _v$8), _v$9 !== _p$.r && setAttribute(_el$7, "title", _p$.r = _v$9), _v$0 !== _p$.d && (_el$7.disabled = _p$.d = _v$0), _v$1 !== _p$.l && setAttribute(_el$8, "aria-label", _p$.l = _v$1), _v$10 !== _p$.u && setAttribute(_el$8, "title", _p$.u = _v$10), _v$11 !== _p$.c && (_el$8.disabled = _p$.c = _v$11), _v$12 !== _p$.w && setAttribute(_el$9, "aria-label", _p$.w = _v$12), _v$13 !== _p$.m && setAttribute(_el$9, "title", _p$.m = _v$13), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0,
        h: void 0,
        r: void 0,
        d: void 0,
        l: void 0,
        u: void 0,
        c: void 0,
        w: void 0,
        m: void 0
      }), _el$;
    })();
  }
  function EmbeddedPreviewToolbar(props) {
    return (() => {
      var _el$0 = _tmpl$33(), _el$1 = _el$0.firstChild, _el$11 = _el$1.nextSibling, _el$12 = _el$11.firstChild, _el$13 = _el$12.nextSibling, _el$14 = _el$13.nextSibling, _el$15 = _el$14.nextSibling;
      return insert(_el$1, createComponent(Show, {
        get when() {
          return props.state.loading();
        },
        get children() {
          return _tmpl$9();
        }
      }), null), insert(_el$1, () => props.state.rangeText(), null), _el$12.$$click = () => props.state.onDirectionChange(), insert(_el$12, createComponent(Icon2, {
        get name() {
          return props.state.directionIcon;
        },
        size: "var(--ui-icon-size-sm)"
      })), _el$13.$$click = () => props.state.onZoomOut(), insert(_el$13, createComponent(Icon2, {
        name: "zoom-out",
        size: "var(--ui-icon-size-sm)"
      })), _el$14.$$click = () => props.state.onZoomIn(), insert(_el$14, createComponent(Icon2, {
        name: "zoom-in",
        size: "var(--ui-icon-size-sm)"
      })), _el$15.$$click = () => props.onOpenOverlay(), insert(_el$15, createComponent(Icon2, {
        name: "fullscreen",
        size: "var(--ui-icon-size-sm)"
      })), createRenderEffect((_p$) => {
        var _v$14 = `flex flex-none items-center ui-gap-xs ${props.state.leftHanded() ? "col-start-1 row-start-1 justify-self-start flex-row-reverse" : "col-start-3 justify-self-end"}`, _v$15 = props.state.directionLabel, _v$16 = props.state.directionLabel, _v$17 = i18n_default.common.actions.zoomOut, _v$18 = i18n_default.common.actions.zoomOut, _v$19 = props.state.zoomOutDisabled(), _v$20 = i18n_default.common.actions.zoomIn, _v$21 = i18n_default.common.actions.zoomIn, _v$22 = props.state.zoomInDisabled(), _v$23 = i18n_default.gallery.openScrollPreview, _v$24 = i18n_default.gallery.openScrollPreview;
        return _v$14 !== _p$.e && className(_el$11, _p$.e = _v$14), _v$15 !== _p$.t && setAttribute(_el$12, "aria-label", _p$.t = _v$15), _v$16 !== _p$.a && setAttribute(_el$12, "title", _p$.a = _v$16), _v$17 !== _p$.o && setAttribute(_el$13, "aria-label", _p$.o = _v$17), _v$18 !== _p$.i && setAttribute(_el$13, "title", _p$.i = _v$18), _v$19 !== _p$.n && (_el$13.disabled = _p$.n = _v$19), _v$20 !== _p$.s && setAttribute(_el$14, "aria-label", _p$.s = _v$20), _v$21 !== _p$.h && setAttribute(_el$14, "title", _p$.h = _v$21), _v$22 !== _p$.r && (_el$14.disabled = _p$.r = _v$22), _v$23 !== _p$.d && setAttribute(_el$15, "aria-label", _p$.d = _v$23), _v$24 !== _p$.l && setAttribute(_el$15, "title", _p$.l = _v$24), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0,
        h: void 0,
        r: void 0,
        d: void 0,
        l: void 0
      }), _el$0;
    })();
  }
  function PreviewViewport(props) {
    let state2 = untrack(() => props.state);
    return (() => {
      var _el$16 = _tmpl$43(), _el$17 = _el$16.firstChild, _el$18 = _el$17.firstChild;
      addEventListener(_el$17, "wheel", state2.onWheel), addEventListener(_el$17, "scroll", state2.onScroll);
      var _ref$ = state2.onScroller;
      return typeof _ref$ == "function" ? use(_ref$, _el$17) : state2.onScroller = _el$17, insert(_el$18, createComponent(For, {
        get each() {
          return state2.slots();
        },
        children: (slot) => {
          let itemIndex = () => slot.pageNum - 1, group = () => Math.floor(itemIndex() / state2.layout().crossCount), crossIndex = () => itemIndex() % state2.layout().crossCount, left = () => state2.horizontal ? state2.rightToLeft ? Number.parseFloat(state2.canvasWidth()) - state2.layout().tileWidth - group() * state2.layout().mainStride : group() * state2.layout().mainStride : crossIndex() * (state2.layout().tileWidth + state2.layout().gap), top = () => state2.horizontal ? crossIndex() * (state2.layout().tileHeight + state2.layout().gap) : group() * state2.layout().mainStride;
          return (() => {
            var _el$19 = _tmpl$53();
            return insert(_el$19, createComponent(PreviewTile, {
              get alignment() {
                return memo(() => !!state2.rightToLeft)() ? "right" : state2.horizontal ? "left" : "center";
              },
              get allowUpscale() {
                return state2.allowUpscale();
              },
              get decodeCache() {
                return state2.decodeCache;
              },
              get failed() {
                return state2.failedIndexes().has(state2.previewCache.previewIndexForPage(slot.pageNum));
              },
              get height() {
                return state2.layout().tileHeight;
              },
              get highlighted() {
                return slot.pageNum === state2.highlightedPageNum();
              },
              get item() {
                return slot.item;
              },
              get pageNum() {
                return slot.pageNum;
              },
              get onOpenPage() {
                return state2.onOpenPage;
              },
              onRetry: () => state2.onRetry(slot.pageNum),
              get width() {
                return state2.layout().tileWidth;
              }
            })), createRenderEffect((_p$) => {
              var _v$28 = `${state2.layout().tileHeight}px`, _v$29 = `${left()}px`, _v$30 = `${top()}px`, _v$31 = `${state2.layout().tileWidth}px`;
              return _v$28 !== _p$.e && setStyleProperty(_el$19, "height", _p$.e = _v$28), _v$29 !== _p$.t && setStyleProperty(_el$19, "left", _p$.t = _v$29), _v$30 !== _p$.a && setStyleProperty(_el$19, "top", _p$.a = _v$30), _v$31 !== _p$.o && setStyleProperty(_el$19, "width", _p$.o = _v$31), _p$;
            }, {
              e: void 0,
              t: void 0,
              a: void 0,
              o: void 0
            }), _el$19;
          })();
        }
      })), insert(_el$16, createComponent(Show, {
        get when() {
          return state2.positionBarVisible();
        },
        get children() {
          return createComponent(PositionBar, {
            get ariaLabel() {
              return i18n_default.gallery.scrollPreview;
            },
            get axis() {
              return state2.horizontal ? "horizontal" : "vertical";
            },
            get currentValue() {
              return state2.positionPage();
            },
            get expanded() {
              return !state2.horizontal;
            },
            get maxValue() {
              return state2.maxPageNum;
            },
            get onInput() {
              return state2.onPositionInput;
            },
            get pixelScale() {
              return state2.pixelScale();
            },
            get position() {
              return state2.horizontal ? void 0 : "absolute";
            },
            get reversed() {
              return memo(() => !!state2.horizontal)() && state2.rightToLeft;
            },
            get thickness() {
              return state2.thickness;
            },
            trackClickEnabled: !1,
            trackVisible: !1,
            get visibleRatio() {
              return state2.positionBarVisibleRatio();
            }
          });
        }
      }), null), createRenderEffect((_p$) => {
        var _v$25 = state2.scrollerClassList, _v$26 = state2.canvasHeight(), _v$27 = state2.canvasWidth();
        return _p$.e = classList(_el$17, _v$25, _p$.e), _v$26 !== _p$.t && setStyleProperty(_el$18, "height", _p$.t = _v$26), _v$27 !== _p$.a && setStyleProperty(_el$18, "width", _p$.a = _v$27), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$16;
    })();
  }
  function ScrollPreview(props) {
    let coordinator = untrack(() => props.coordinator), previewCache = untrack(() => props.previewCache), decodeCache = new PreviewDecodeCache(DECODE_CACHE_BYTES, DECODE_CACHE_ITEMS), [open, setOpen] = createSignal(!1), [readDirection, setReadDirection] = createSignal(untrack(() => props.readDirection)), [embeddedReadDirection, setEmbeddedReadDirection] = createSignal(untrack(() => props.embeddedDirection)), [crossCountOverride, setCrossCountOverride] = createSignal(null), [embeddedCrossCountOverride, setEmbeddedCrossCountOverride] = createSignal(null), [targetPreviewIndex, setTargetPreviewIndex] = createSignal(untrack(() => previewCache.current().data.currentIndex)), [highlightedPageNum, setHighlightedPageNum] = createSignal(null), continuePageNum = () => coordinator.progress().hasHistory ? coordinator.progress().currentPage : null, [targetPageNum, setTargetPageNum] = createSignal(null), openPreview = () => {
      open() || setOpen(!0);
    };
    createEffect(() => setEmbeddedReadDirection(props.embeddedDirection)), coordinator.attachPreview({
      close: () => setOpen(!1),
      gotoPreview: (previewIndex) => {
        setHighlightedPageNum(null), setTargetPageNum(null), setTargetPreviewIndex(previewIndex), openPreview();
      },
      gotoPage: (pageNum) => {
        setHighlightedPageNum(pageNum), setTargetPageNum(pageNum), setTargetPreviewIndex(previewCache.previewIndexForPage(pageNum)), openPreview();
      }
    }), onCleanup(() => {
      decodeCache.dispose();
    });
    let session = {
      continuePageNum,
      crossCountOverride,
      decodeCache,
      embeddedCrossCountOverride,
      embeddedReadDirection,
      highlightedPageNum,
      open,
      readDirection,
      setCrossCountOverride,
      setEmbeddedCrossCountOverride,
      setEmbeddedReadDirection,
      setReadDirection,
      setTargetPageNum,
      targetPageNum,
      targetPreviewIndex
    };
    return [createComponent(EmbeddedScrollPreview, {
      session,
      source: props
    }), createComponent(ScrollPreviewLauncher, {
      session,
      source: props
    }), createComponent(ScrollPreviewOverlay, {
      session,
      source: props
    })];
  }
  function EmbeddedScrollPreview(props) {
    let session = untrack(() => props.session), source = untrack(() => props.source);
    return createComponent(Show, {
      get when() {
        return source.replaceOriginalPreview;
      },
      get children() {
        return createComponent(Show, {
          get when() {
            return session.embeddedReadDirection();
          },
          keyed: !0,
          children: (direction) => createComponent(ScrollPreviewPanel, {
            get crossCountOverride() {
              return session.embeddedCrossCountOverride();
            },
            get decodeCache() {
              return session.decodeCache;
            },
            embedded: !0,
            get fillEmbeddedContainer() {
              return source.fillEmbeddedContainer;
            },
            get highlightedPageNum() {
              return session.continuePageNum;
            },
            get leftHandedControls() {
              return source.leftHandedControls;
            },
            onDirectionChange: (next, pageNum) => {
              session.setTargetPageNum(pageNum), session.setEmbeddedReadDirection(next), source.onEmbeddedDirectionChange(next);
            },
            get onLoadError() {
              return source.onLoadError;
            },
            get onCrossCountOverrideChange() {
              return session.setEmbeddedCrossCountOverride;
            },
            get onOpenOverlay() {
              return source.coordinator.openPreviewPage;
            },
            get onOpenPage() {
              return source.coordinator.openGalleryPage;
            },
            pixelScale: 1,
            get previewCache() {
              return source.previewCache;
            },
            readDirection: direction,
            get targetPageNum() {
              return session.targetPageNum() ?? session.continuePageNum() ?? 1;
            },
            get targetPreviewIndex() {
              return session.targetPreviewIndex();
            }
          })
        });
      }
    });
  }
  function ScrollPreviewLauncher(props) {
    let session = untrack(() => props.session), source = untrack(() => props.source);
    return createComponent(Show, {
      get when() {
        return !source.replaceOriginalPreview;
      },
      get children() {
        var _el$20 = _tmpl$63(), _el$21 = _el$20.firstChild;
        return _el$21.$$click = () => source.coordinator.openPreviewPage(session.continuePageNum() ?? 1), insert(_el$21, createComponent(Icon2, {
          name: "grid",
          size: "var(--ui-icon-size-sm)"
        }), null), insert(_el$21, () => i18n_default.gallery.scrollPreview, null), _el$20;
      }
    });
  }
  function ScrollPreviewOverlay(props) {
    let session = untrack(() => props.session), source = untrack(() => props.source), overlayHost2 = useOverlayHost();
    return createComponent(Show, {
      get when() {
        return session.open();
      },
      get children() {
        return createComponent(OverlayPortal, {
          get children() {
            return createComponent(Show, {
              get when() {
                return session.readDirection();
              },
              keyed: !0,
              children: (direction) => createComponent(ScrollPreviewPanel, {
                get crossCountOverride() {
                  return session.crossCountOverride();
                },
                get decodeCache() {
                  return session.decodeCache;
                },
                embedded: !1,
                fillEmbeddedContainer: () => !1,
                get highlightedPageNum() {
                  return session.highlightedPageNum;
                },
                get leftHandedControls() {
                  return source.leftHandedControls;
                },
                get onClose() {
                  return source.coordinator.requestClosePreview;
                },
                onDirectionChange: (next, pageNum) => {
                  session.setTargetPageNum(pageNum), session.setReadDirection(next), source.onReadDirectionChange(next);
                },
                get onLoadError() {
                  return source.onLoadError;
                },
                get onCrossCountOverrideChange() {
                  return session.setCrossCountOverride;
                },
                get onOpenPage() {
                  return source.coordinator.selectPreviewPage;
                },
                get pixelScale() {
                  return overlayHost2.fullscreenPixelScale();
                },
                get previewCache() {
                  return source.previewCache;
                },
                readDirection: direction,
                get targetPageNum() {
                  return session.targetPageNum();
                },
                get targetPreviewIndex() {
                  return session.targetPreviewIndex();
                }
              })
            });
          }
        });
      }
    });
  }
  function ScrollPreviewPanel(props) {
    let decodeCache = untrack(() => props.decodeCache), embedded = untrack(() => props.embedded), previewCache = untrack(() => props.previewCache), onClose = untrack(() => props.onClose), onLoadError = untrack(() => props.onLoadError), initialPreview = untrack(() => previewCache.current()), totalImages = initialPreview.data.totalImages, maxPreviewIndex = initialPreview.data.maxIndex, aspectPreviewIndex = previewCache.previewIndexForPage(untrack(() => props.targetPageNum ?? props.targetPreviewIndex * initialPreview.data.pageSize + 1)), [tileAspectRatio, setTileAspectRatio] = createSignal(initialPreview.data.dominantAspectRatio), initialTileAspectRatio = untrack(tileAspectRatio), pixelScale = () => props.pixelScale, initialPixelScale = untrack(pixelScale), readDirection = untrack(() => props.readDirection), horizontal = readDirection !== "ttb", rightToLeft = readDirection === "rtl", directionIcon = readDirection === "ttb" ? "arrow-down" : readDirection === "rtl" ? "arrow-left" : "arrow-right", directionLabel = readDirection === "ttb" ? i18n_default.gallery.scrollPreviewDirectionTtb : readDirection === "rtl" ? i18n_default.gallery.scrollPreviewDirectionRtl : i18n_default.gallery.scrollPreviewDirectionLtr, flingAnimator = new ScrollFlingAnimator(), crossCountOverride = () => props.crossCountOverride, [exitDragOffset, setExitDragOffset] = createSignal(0), [previewLoadReady, setPreviewLoadReady] = createSignal(!1), [positionBarReady, setPositionBarReady] = createSignal(!1), [scrollOffset, setScrollOffset] = createSignal(0), [layout, setLayout] = createSignal({
      crossCount: 1,
      gap: GRID_GAP * initialPixelScale,
      horizontal,
      mainStride: horizontal ? (MAX_TILE_WIDTH + GRID_GAP) * initialPixelScale : (MAX_TILE_WIDTH * initialTileAspectRatio + GRID_GAP) * initialPixelScale,
      tileHeight: MAX_TILE_WIDTH * initialTileAspectRatio * initialPixelScale,
      tileWidth: MAX_TILE_WIDTH * initialPixelScale,
      viewportHeight: 1,
      viewportWidth: 1
    }), scroller, overlay, dragDirection = null, dragStartPosition = null, resizeAnchorPageNum = null, pinchStartCrossCount = 1, pinchMinimumCrossCount = 1, layoutFrame = null, scrollFrame = null, layoutHeight = 0, layoutWidth = 0, initialized = !1, disposed = !1, totalGroups = createMemo(() => Math.ceil(totalImages / layout().crossCount)), totalMainSize = createMemo(() => Math.max(1, totalGroups() * layout().mainStride - layout().gap)), mainViewportSize = createMemo(() => horizontal ? layout().viewportWidth : layout().viewportHeight), mainCanvasSize = createMemo(() => Math.max(totalMainSize(), mainViewportSize())), visibleStartGroup = createMemo(() => clamp(Math.floor(scrollOffset() / layout().mainStride) - OVERSCAN_ROWS, 0, Math.max(0, totalGroups() - 1))), visibleEndGroup = createMemo(() => clamp(Math.ceil((scrollOffset() + mainViewportSize()) / layout().mainStride) + OVERSCAN_ROWS, visibleStartGroup(), Math.max(0, totalGroups() - 1))), visibleStartPageNum = createMemo(() => visibleStartGroup() * layout().crossCount + 1), visibleEndPageNum = createMemo(() => Math.min(totalImages, (visibleEndGroup() + 1) * layout().crossCount)), screenStartPageNum = createMemo(() => clamp(Math.floor(scrollOffset() / layout().mainStride) * layout().crossCount + 1, 1, totalImages)), screenEndPageNum = createMemo(() => {
      let end = Math.max(scrollOffset(), scrollOffset() + mainViewportSize() - 1), endGroup = Math.floor(end / layout().mainStride);
      return clamp((endGroup + 1) * layout().crossCount, screenStartPageNum(), totalImages);
    }), visibleSlots = createMemo(() => {
      previewCache.previewDataVersion();
      let slots = [];
      for (let pageNum = visibleStartPageNum(); pageNum <= visibleEndPageNum(); pageNum += 1)
        slots.push({
          item: previewCache.previewItem(pageNum),
          pageNum
        });
      return slots;
    }), centeredPageNum = () => {
      let currentLayout = layout(), centerGroup = Math.floor((scrollOffset() + mainViewportSize() / 2) / currentLayout.mainStride);
      return clamp(centerGroup * currentLayout.crossCount + Math.floor(currentLayout.crossCount / 2) + 1, 1, totalImages);
    }, centeredPreviewIndex = () => previewCache.previewIndexForPage(centeredPageNum()), loading = createPreviewLoading({
      aspectPreviewIndex,
      centeredPageNum,
      maxPreviewIndex,
      onAspectRatio: setTileAspectRatio,
      onLoadError,
      previewCache,
      ready: previewLoadReady
    }), preferredLayoutAnchorPageNum = () => {
      let targetPageNum = props.highlightedPageNum() ?? props.targetPageNum;
      return targetPageNum !== null && targetPageNum >= screenStartPageNum() && targetPageNum <= screenEndPageNum() ? targetPageNum : centeredPageNum();
    }, maximumCrossCount = () => horizontal ? Math.min(MAX_CROSS_COUNT, totalImages) : MAX_CROSS_COUNT, minimumCrossCount = (currentLayout) => {
      let aspectRatio = tileAspectRatio(), crossSize = currentLayout.horizontal ? currentLayout.viewportHeight : currentLayout.viewportWidth, maximumTileCrossSize = currentLayout.horizontal ? Math.min(currentLayout.viewportHeight / 2, currentLayout.viewportWidth / 2 * aspectRatio) : Math.min(currentLayout.viewportWidth / 2, currentLayout.viewportHeight / 2 / aspectRatio);
      return Math.max(1, Math.ceil((crossSize + currentLayout.gap) / (maximumTileCrossSize + currentLayout.gap)));
    }, resizeCrossCount = (delta) => {
      flingAnimator.cancel(), resizeAnchorPageNum = preferredLayoutAnchorPageNum();
      let currentLayout = layout();
      props.onCrossCountOverrideChange(clamp(currentLayout.crossCount + delta, minimumCrossCount(currentLayout), maximumCrossCount())), queueMicrotask(() => {
        resizeAnchorPageNum = null;
      });
    }, scrollPositionPage = () => {
      let maxOffset = Math.max(0, totalMainSize() - mainViewportSize());
      return maxOffset === 0 || totalImages <= 1 ? 1 : Math.round(1 + clamp(scrollOffset() / maxOffset, 0, 1) * (totalImages - 1));
    }, maxScrollOffset = () => Math.max(0, totalMainSize() - mainViewportSize()), readScrollOffset = () => {
      let value = horizontal ? rightToLeft ? maxScrollOffset() - scroller.scrollLeft : scroller.scrollLeft : scroller.scrollTop;
      return clamp(value, 0, maxScrollOffset());
    }, updateScrollOffset = (value) => {
      let next = clamp(value, 0, maxScrollOffset());
      horizontal ? scroller.scrollLeft = rightToLeft ? maxScrollOffset() - next : next : scroller.scrollTop = next, setScrollOffset(next);
    }, scrollToPositionPage = (pageNum) => {
      flingAnimator.cancel();
      let ratio = totalImages <= 1 ? 0 : (clamp(pageNum, 1, totalImages) - 1) / (totalImages - 1);
      updateScrollOffset(ratio * maxScrollOffset());
    }, requestDirectionChange = () => {
      window.confirm(i18n_default.gallery.confirmScrollPreviewDirection) && props.onDirectionChange?.(NEXT_SCROLL_PREVIEW_DIRECTION[readDirection], centeredPageNum());
    };
    createPointerGestureElement(() => scroller ?? null, () => ({
      dragAxis: embedded ? horizontal ? "x" : "y" : "any",
      onStart: () => {
        flingAnimator.cancel(), dragDirection = null, dragStartPosition = horizontal ? scroller.scrollLeft : scroller.scrollTop;
      },
      onMove: (info) => {
        if (dragDirection === null) {
          let mainDelta = Math.abs(horizontal ? info.dx : info.dy), exitDelta = Math.abs(horizontal ? info.dy : info.dx);
          dragDirection = embedded || mainDelta >= exitDelta ? "scroll" : "exit";
        }
        if (dragDirection === "exit") {
          setExitDragOffset(horizontal ? info.dy : info.dx);
          return;
        }
        dragStartPosition !== null && (horizontal ? scroller.scrollLeft = dragStartPosition - info.dx : scroller.scrollTop = dragStartPosition - info.dy);
      },
      onEnd: (info) => {
        if (dragStartPosition = null, dragDirection === "exit") {
          let offset = exitDragOffset(), exitSize = horizontal ? overlay.clientHeight : overlay.clientWidth, exitVelocity = horizontal ? info.velocityY : info.velocityX, exit = Math.abs(offset) >= exitSize * 0.2 || Math.abs(exitVelocity) >= 0.6;
          if (dragDirection = null, exit) {
            let direction = offset === 0 ? Math.sign(exitVelocity) || 1 : Math.sign(offset), previewIndex = centeredPreviewIndex(), translation = horizontal ? `0, ${direction * 100}vh` : `${direction * 100}vw, 0`;
            overlay.animate([{
              opacity: overlay.style.opacity,
              transform: overlay.style.transform
            }, {
              opacity: 0.7,
              transform: `translate3d(${translation}, 0) scale(0.97)`
            }], {
              duration: 180,
              easing: "cubic-bezier(0.2, 0.8, 0.2, 1)",
              fill: "forwards"
            }).finished.then(() => onClose?.(previewIndex));
            return;
          }
          overlay.animate([{
            opacity: overlay.style.opacity,
            transform: overlay.style.transform
          }, {
            opacity: 1,
            transform: "translate3d(0, 0, 0)"
          }], {
            duration: 180,
            easing: "cubic-bezier(0.2, 0.8, 0.2, 1)"
          }).finished.then(() => setExitDragOffset(0));
          return;
        }
        dragDirection = null, flingAnimator.start({
          axis: horizontal ? "x" : "y",
          scroller,
          initialVelocity: -(horizontal ? info.velocityX * HORIZONTAL_FLING_VELOCITY_FACTOR : info.velocityY),
          setScrollPosition: (position) => {
            horizontal ? scroller.scrollLeft = position : scroller.scrollTop = position;
          },
          canRun: () => !disposed && scroller.isConnected,
          onStop: () => setScrollOffset(readScrollOffset())
        });
      },
      onPinchStart: () => {
        if (embedded)
          return !1;
        flingAnimator.cancel(), resizeAnchorPageNum = preferredLayoutAnchorPageNum(), pinchStartCrossCount = layout().crossCount;
        let currentLayout = layout();
        return pinchMinimumCrossCount = Math.min(pinchStartCrossCount, minimumCrossCount(currentLayout)), !0;
      },
      onPinchMove: (info) => {
        embedded || props.onCrossCountOverrideChange(clamp(Math.round(pinchStartCrossCount / info.scale), pinchMinimumCrossCount, MAX_CROSS_COUNT));
      },
      onPinchEnd: () => {
        resizeAnchorPageNum = null;
      }
    }));
    let scrollToPage = (pageNum, currentLayout = untrack(layout)) => {
      let group = Math.floor((clamp(pageNum, 1, totalImages) - 1) / currentLayout.crossCount), tileMainSize = currentLayout.horizontal ? currentLayout.tileWidth : currentLayout.tileHeight;
      updateScrollOffset(group * currentLayout.mainStride - (mainViewportSize() - tileMainSize) / 2);
    }, scrollToPreview = (previewIndex, currentLayout) => {
      scrollToPage(previewIndex * initialPreview.data.pageSize + 1, currentLayout);
    };
    createEffect(() => {
      let previewIndex = props.targetPreviewIndex, pageNum = props.targetPageNum;
      initialized && scroller.isConnected && (pageNum === null ? scrollToPreview(previewIndex, untrack(layout)) : scrollToPage(pageNum, untrack(layout)));
    });
    let updateLayout = (resetEmbeddedHeight = !1) => {
      setPreviewLoadReady(!1), resetEmbeddedHeight && embedded && overlay.style.removeProperty("height");
      let width = Math.max(1, scroller.clientWidth), height = Math.max(1, scroller.clientHeight), scale = pixelScale(), gap = GRID_GAP * scale, aspectRatio = tileAspectRatio(), baseMaxTileWidth = MAX_TILE_WIDTH * scale, referenceItemsPerRow = Math.max(1, Math.ceil((width + gap) / (baseMaxTileWidth + gap))), referenceItemWidth = Math.max(1, (width - gap * (referenceItemsPerRow - 1)) / referenceItemsPerRow), maxTileWidth = embedded ? referenceItemWidth * Math.sqrt(REFERENCE_PORTRAIT_ASPECT_RATIO / aspectRatio) : baseMaxTileWidth, anchorPageNum = initialized ? resizeAnchorPageNum ?? preferredLayoutAnchorPageNum() : null, itemsPerRow = Math.max(1, Math.ceil((width + gap) / (maxTileWidth + gap))), itemWidth = Math.max(1, (width - gap * (itemsPerRow - 1)) / itemsPerRow), itemHeight = Math.max(1, Math.round(itemWidth * aspectRatio)), availableRows = embedded ? Math.max(1, Math.floor((height + gap) / (itemHeight + gap))) : Math.max(1, Math.ceil((height + gap) / (itemHeight + gap))), automaticCrossCount = horizontal ? Math.min(availableRows, Math.ceil(totalImages / itemsPerRow)) : Math.min(itemsPerRow, maximumCrossCount()), crossCount = clamp(crossCountOverride() ?? automaticCrossCount, 1, maximumCrossCount()), availableTileHeight = Math.max(1, (height - gap * (crossCount - 1)) / crossCount), crossCountOverridden = crossCountOverride() !== null, overriddenTileWidth = Math.min(Math.max(1, (width - gap * (crossCount - 1)) / crossCount), width / 2, height / 2 / aspectRatio), tileHeight = horizontal ? crossCountOverridden ? Math.min(availableTileHeight, height / 2, width / 2 * aspectRatio) : Math.min(itemHeight, availableTileHeight) : Math.max(1, Math.round((crossCountOverridden ? overriddenTileWidth : Math.max(1, (width - gap * (crossCount - 1)) / crossCount)) * aspectRatio)), tileWidth = horizontal ? crossCountOverridden ? tileHeight / aspectRatio : clamp(tileHeight / aspectRatio, 1, maxTileWidth) : crossCountOverridden ? overriddenTileWidth : Math.max(1, (width - gap * (crossCount - 1)) / crossCount), fitEmbeddedHeight = embedded && !props.fillEmbeddedContainer(), viewportHeight = height;
      if (fitEmbeddedHeight && horizontal)
        viewportHeight = crossCount * tileHeight + (crossCount - 1) * gap, overlay.style.height = `${Math.ceil(overlay.clientHeight - height + viewportHeight)}px`;
      else if (fitEmbeddedHeight) {
        let groupCount = Math.ceil(totalImages / crossCount), fittedScrollerHeight = groupCount * tileHeight + (groupCount - 1) * gap;
        viewportHeight = Math.min(height, fittedScrollerHeight), viewportHeight < height ? overlay.style.height = `${Math.ceil(overlay.clientHeight - height + viewportHeight)}px` : overlay.style.removeProperty("height");
      } else embedded && overlay.style.removeProperty("height");
      let next = {
        crossCount,
        gap,
        horizontal,
        mainStride: (horizontal ? tileWidth : tileHeight) + gap,
        tileHeight,
        tileWidth,
        viewportHeight,
        viewportWidth: width
      };
      setLayout(next), layoutFrame !== null && window.cancelAnimationFrame(layoutFrame), layoutFrame = window.requestAnimationFrame(() => untrack(() => {
        layoutFrame = null, scroller.isConnected && (initialized ? scrollToPage(anchorPageNum ?? centeredPageNum(), next) : (initialized = !0, props.targetPageNum === null ? scrollToPreview(props.targetPreviewIndex, next) : scrollToPage(props.targetPageNum, next)), setPreviewLoadReady(!0), setPositionBarReady(!0));
      }));
    };
    createEffect(() => {
      crossCountOverride(), props.fillEmbeddedContainer(), pixelScale(), tileAspectRatio(), initialized && untrack(() => updateLayout(!0));
    }), onMount(() => {
      let previousBodyOverflow = document.body.style.overflow, previousHtmlOverflow = document.documentElement.style.overflow;
      embedded || (document.body.style.overflow = "hidden", document.documentElement.style.overflow = "hidden", overlay.animate([{
        opacity: 0.72,
        transform: horizontal ? "translate3d(0, -32px, 0) scale(0.99)" : "translate3d(32px, 0, 0) scale(0.99)"
      }, {
        opacity: 1,
        transform: "translate3d(0, 0, 0) scale(1)"
      }], {
        duration: 120,
        easing: "cubic-bezier(0.2, 0.8, 0.2, 1)"
      }).finished.catch(() => {
      }));
      let resizeObserver = new ResizeObserver(() => untrack(() => {
        let width = scroller.clientWidth, height = scroller.clientHeight;
        Math.abs(width - layoutWidth) <= 1 && Math.abs(height - layoutHeight) <= 1 || (layoutHeight = height, layoutWidth = width, updateLayout(!0));
      }));
      resizeObserver.observe(scroller), layoutHeight = scroller.clientHeight, layoutWidth = scroller.clientWidth, updateLayout(!0), onCleanup(() => {
        disposed = !0, flingAnimator.cancel(), resizeObserver.disconnect(), embedded || (document.body.style.overflow = previousBodyOverflow, document.documentElement.style.overflow = previousHtmlOverflow), layoutFrame !== null && window.cancelAnimationFrame(layoutFrame), scrollFrame !== null && window.cancelAnimationFrame(scrollFrame);
      });
    });
    let toolbarState = {
      directionIcon,
      directionLabel,
      leftHanded: untrack(() => props.leftHandedControls),
      loading: () => loading.loadingCount() > 0,
      rangeText: () => `${screenStartPageNum()}–${screenEndPageNum()} / ${totalImages}`,
      zoomInDisabled: () => layout().crossCount <= minimumCrossCount(layout()),
      zoomOutDisabled: () => layout().crossCount >= maximumCrossCount(),
      onDirectionChange: requestDirectionChange,
      onZoomIn: () => resizeCrossCount(-1),
      onZoomOut: () => resizeCrossCount(1)
    }, positionBarVisibleRatio = () => clamp(mainViewportSize() / mainCanvasSize(), 0, 1), viewportState = {
      allowUpscale: () => embedded || crossCountOverride() !== null,
      canvasHeight: () => horizontal ? "100%" : `${totalMainSize()}px`,
      canvasWidth: () => horizontal ? `${mainCanvasSize()}px` : "100%",
      decodeCache,
      failedIndexes: loading.failedIndexes,
      highlightedPageNum: untrack(() => props.highlightedPageNum),
      horizontal,
      layout,
      maxPageNum: totalImages,
      onOpenPage: untrack(() => props.onOpenPage),
      onPositionInput: scrollToPositionPage,
      onRetry: loading.retry,
      onScroll: () => {
        scrollFrame === null && (scrollFrame = window.requestAnimationFrame(() => {
          scrollFrame = null, setScrollOffset(untrack(readScrollOffset));
        }));
      },
      onScroller: (element) => {
        scroller = element;
      },
      onWheel: () => flingAnimator.cancel(),
      pixelScale,
      positionBarVisible: () => positionBarReady() && maxScrollOffset() > SCROLL_PIXEL_EPSILON && positionBarVisibleRatio() < 1 && (screenStartPageNum() > 1 || screenEndPageNum() < totalImages),
      positionBarVisibleRatio,
      positionPage: scrollPositionPage,
      previewCache,
      rightToLeft,
      screenEndPageNum,
      screenStartPageNum,
      scrollerClassList: {
        "inset-0": !embedded,
        "top-0 right-xs left-xs": embedded,
        "bottom-[calc(var(--ui-control-size-xs)/2)]": embedded && horizontal,
        "bottom-xs": embedded && !horizontal,
        "overflow-x-auto overflow-y-hidden": horizontal,
        "overflow-y-auto overflow-x-hidden": !horizontal,
        "overscroll-auto": embedded,
        "[touch-action:pan-x]": embedded && !horizontal,
        "[touch-action:pan-y]": embedded && horizontal,
        "overscroll-contain [touch-action:none]": !embedded
      },
      slots: visibleSlots,
      thickness: embedded || !horizontal ? "narrow" : "normal"
    };
    return (() => {
      var _el$22 = _tmpl$72(), _el$23 = _el$22.firstChild, _ref$2 = overlay;
      return typeof _ref$2 == "function" ? use(_ref$2, _el$23) : overlay = _el$23, insert(_el$23, createComponent(Show, {
        when: embedded,
        get fallback() {
          return createComponent(OverlayPreviewToolbar, {
            get currentDisabled() {
              return props.highlightedPageNum() === null;
            },
            onClose: () => onClose?.(centeredPreviewIndex()),
            onCurrent: () => {
              let highlightedPageNum = props.highlightedPageNum();
              highlightedPageNum !== null && (flingAnimator.cancel(), scrollToPage(highlightedPageNum));
            },
            state: toolbarState
          });
        },
        get children() {
          return createComponent(EmbeddedPreviewToolbar, {
            onOpenOverlay: () => props.onOpenOverlay?.(centeredPageNum()),
            state: toolbarState
          });
        }
      }), null), insert(_el$23, createComponent(PreviewViewport, {
        state: viewportState
      }), null), createRenderEffect((_p$) => {
        var _v$32 = {
          contents: embedded,
          "fixed inset-0 z-[1300]": !embedded
        }, _v$33 = {
          "absolute inset-0 bg-[var(--color-site-surface)] text-[var(--color-site-text)]": !embedded,
          "border ehp-color-site-border ui-rounded-sm bg-[var(--color-site-elevated)]": embedded,
          "relative h-[var(--scroll-preview-height)]": embedded,
          "w-full": !0
        }, _v$34 = embedded ? "1" : `${1 - Math.min(0.15, Math.abs(exitDragOffset()) / Math.max(1, horizontal ? window.innerHeight : window.innerWidth) * 0.15)}`, _v$35 = embedded ? "none" : `translate3d(${horizontal ? 0 : exitDragOffset()}px, ${horizontal ? exitDragOffset() : 0}px, 0) scale(${1 - Math.min(0.03, Math.abs(exitDragOffset()) / Math.max(1, horizontal ? window.innerHeight : window.innerWidth) * 0.03)})`;
        return _p$.e = classList(_el$22, _v$32, _p$.e), _p$.t = classList(_el$23, _v$33, _p$.t), _v$34 !== _p$.a && setStyleProperty(_el$23, "opacity", _p$.a = _v$34), _v$35 !== _p$.o && setStyleProperty(_el$23, "transform", _p$.o = _v$35), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0
      }), _el$22;
    })();
  }
  function PreviewTile(props) {
    let releaseDecodedImage = null;
    return createEffect(() => {
      releaseDecodedImage?.(), releaseDecodedImage = props.item?.thumbnail.url ? props.decodeCache.retain(props.item.thumbnail.url) : null;
    }), onCleanup(() => releaseDecodedImage?.()), (() => {
      var _el$24 = _tmpl$82();
      return insert(_el$24, createComponent(Show, {
        get when() {
          return props.item;
        },
        keyed: !0,
        get fallback() {
          return (() => {
            var _el$25 = _tmpl$92(), _el$26 = _el$25.firstChild;
            return _el$25.$$click = () => props.onRetry(), insert(_el$25, createComponent(Show, {
              get when() {
                return props.failed;
              },
              get children() {
                return createComponent(Icon2, {
                  name: "refresh",
                  size: "var(--ui-icon-size-lg)"
                });
              }
            }), _el$26), insert(_el$26, () => props.pageNum), createRenderEffect((_p$) => {
              var _v$40 = !!props.failed, _v$41 = !props.failed;
              return _v$40 !== _p$.e && _el$25.classList.toggle("cursor-pointer", _p$.e = _v$40), _v$41 !== _p$.t && (_el$25.disabled = _p$.t = _v$41), _p$;
            }, {
              e: void 0,
              t: void 0
            }), _el$25;
          })();
        },
        children: (item) => [createComponent(Show, {
          get when() {
            return item.thumbnail.kind === "background";
          },
          get fallback() {
            return (() => {
              var _el$30 = _tmpl$11();
              return setAttribute(_el$30, "draggable", !1), createRenderEffect((_p$) => {
                var _v$54 = {
                  "h-full w-full": props.allowUpscale,
                  "max-h-full max-w-full": !props.allowUpscale
                }, _v$55 = item.thumbnail.url, _v$56 = item.thumbnail.width, _v$57 = item.thumbnail.height;
                return _p$.e = classList(_el$30, _v$54, _p$.e), _v$55 !== _p$.t && setAttribute(_el$30, "src", _p$.t = _v$55), _v$56 !== _p$.a && setAttribute(_el$30, "width", _p$.a = _v$56), _v$57 !== _p$.o && setAttribute(_el$30, "height", _p$.o = _v$57), _p$;
              }, {
                e: void 0,
                t: void 0,
                a: void 0,
                o: void 0
              }), _el$30;
            })();
          },
          get children() {
            var _el$27 = _tmpl$0();
            return createRenderEffect((_p$) => {
              var _v$42 = `url(${JSON.stringify(item.thumbnail.url)})`, _v$43 = item.thumbnail.backgroundPosition, _v$44 = item.thumbnail.backgroundRepeat, _v$45 = item.thumbnail.backgroundSize, _v$46 = `${item.thumbnail.height}px`, _v$47 = `scale(${Math.min(props.allowUpscale ? Number.POSITIVE_INFINITY : 1, props.width / item.thumbnail.width, props.height / item.thumbnail.height)})`, _v$48 = props.alignment === "right" ? "right top" : props.alignment === "left" ? "left top" : "center top", _v$49 = `${item.thumbnail.width}px`, _v$50 = `Page ${item.pageNum}`;
              return _v$42 !== _p$.e && setStyleProperty(_el$27, "background-image", _p$.e = _v$42), _v$43 !== _p$.t && setStyleProperty(_el$27, "background-position", _p$.t = _v$43), _v$44 !== _p$.a && setStyleProperty(_el$27, "background-repeat", _p$.a = _v$44), _v$45 !== _p$.o && setStyleProperty(_el$27, "background-size", _p$.o = _v$45), _v$46 !== _p$.i && setStyleProperty(_el$27, "height", _p$.i = _v$46), _v$47 !== _p$.n && setStyleProperty(_el$27, "transform", _p$.n = _v$47), _v$48 !== _p$.s && setStyleProperty(_el$27, "transform-origin", _p$.s = _v$48), _v$49 !== _p$.h && setStyleProperty(_el$27, "width", _p$.h = _v$49), _v$50 !== _p$.r && setAttribute(_el$27, "aria-label", _p$.r = _v$50), _p$;
            }, {
              e: void 0,
              t: void 0,
              a: void 0,
              o: void 0,
              i: void 0,
              n: void 0,
              s: void 0,
              h: void 0,
              r: void 0
            }), _el$27;
          }
        }), (() => {
          var _el$28 = _tmpl$1();
          return _el$28.$$click = (event) => {
            event.preventDefault(), event.stopPropagation(), props.onOpenPage(item.pageUrl, item.pageNum);
          }, setAttribute(_el$28, "draggable", !1), createRenderEffect((_p$) => {
            var _v$51 = item.pageUrl, _v$52 = `Page ${item.pageNum}`, _v$53 = props.highlighted ? "page" : void 0;
            return _v$51 !== _p$.e && setAttribute(_el$28, "href", _p$.e = _v$51), _v$52 !== _p$.t && setAttribute(_el$28, "aria-label", _p$.t = _v$52), _v$53 !== _p$.a && setAttribute(_el$28, "aria-current", _p$.a = _v$53), _p$;
          }, {
            e: void 0,
            t: void 0,
            a: void 0
          }), _el$28;
        })(), createComponent(Show, {
          get when() {
            return props.highlighted;
          },
          get children() {
            return _tmpl$10();
          }
        })]
      })), createRenderEffect((_p$) => {
        var _v$36 = props.alignment === "center", _v$37 = props.alignment === "left", _v$38 = props.alignment === "right", _v$39 = `${props.height}px`;
        return _v$36 !== _p$.e && _el$24.classList.toggle("justify-center", _p$.e = _v$36), _v$37 !== _p$.t && _el$24.classList.toggle("justify-start", _p$.t = _v$37), _v$38 !== _p$.a && _el$24.classList.toggle("justify-end", _p$.a = _v$38), _v$39 !== _p$.o && setStyleProperty(_el$24, "height", _p$.o = _v$39), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0
      }), _el$24;
    })();
  }
  var PreviewDecodeCache = class {
    constructor(byteLimit, itemLimit) {
      __publicField(this, "bytes", 0);
      __publicField(this, "entries", /* @__PURE__ */ new Map());
      this.byteLimit = byteLimit, this.itemLimit = itemLimit;
    }
    retain(url) {
      let entry = this.ensure(url);
      return entry.pins += 1, this.touch(url, entry), () => {
        let current = this.entries.get(url);
        current === entry && (current.pins = Math.max(0, current.pins - 1), this.prune());
      };
    }
    dispose() {
      for (let entry of this.entries.values())
        entry.image.removeAttribute("src");
      this.entries.clear(), this.bytes = 0;
    }
    ensure(url) {
      let cached = this.entries.get(url);
      if (cached)
        return cached;
      let image2 = new Image(), entry = {
        bytes: 0,
        image: image2,
        pins: 0
      };
      return image2.decoding = "async", image2.onload = () => {
        let bytes = Math.max(1, image2.naturalWidth) * Math.max(1, image2.naturalHeight) * 4;
        this.bytes += bytes - entry.bytes, entry.bytes = bytes, image2.decode().catch(() => {
        }).finally(() => this.prune());
      }, image2.onerror = () => {
        entry.pins === 0 && this.evict(url, entry);
      }, image2.src = url, this.entries.set(url, entry), this.prune(), entry;
    }
    touch(url, entry) {
      this.entries.delete(url), this.entries.set(url, entry);
    }
    prune() {
      for (; this.entries.size > this.itemLimit || this.bytes > this.byteLimit; ) {
        let removable = Array.from(this.entries).find(([, entry]) => entry.pins === 0);
        if (!removable)
          break;
        this.evict(removable[0], removable[1]);
      }
    }
    evict(url, entry) {
      this.entries.get(url) === entry && (this.entries.delete(url), this.bytes = Math.max(0, this.bytes - entry.bytes), entry.image.onload = null, entry.image.onerror = null, entry.image.removeAttribute("src"));
    }
  };
  delegateEvents(["click"]);

  // src/state/readHistory.ts
  var HISTORY_KEY_PREFIX = "ehpeek:history:", HISTORY_QUEUE_KEY_PREFIX = "ehpeek:hist_q:", READ_HISTORY_LIMIT = 3e3, HISTORY_COMPACT_THRESHOLD = 4e3, SAVE_DELAY_MS = 1e4, READ_HISTORY_ARCHIVE_TYPE = "ehpeek-read-history", READ_HISTORY_ARCHIVE_VERSION = 1, ReadingProgressSession = class {
    constructor(baseRecord, initial) {
      this.baseRecord = baseRecord;
      this.pending = null;
      this.lastSaved = null;
      this.timer = null;
      this.flush = () => {
        this.timer !== null && (window.clearTimeout(this.timer), this.timer = null), this.pending && (this.sameProgress(this.pending, this.lastSaved) || (saveReadHistory(this.pending), this.lastSaved = this.pending), this.pending = null);
      };
      this.onVisibilityChange = () => {
        document.visibilityState === "hidden" && this.flush();
      };
      let [progress, setProgress] = createSignal(initial);
      this.progress = progress, this.setProgress = setProgress, window.addEventListener("pagehide", this.flush), document.addEventListener("visibilitychange", this.onVisibilityChange);
    }
    update(pageNum, totalPages) {
      if (!pageNum || pageNum <= 0 || (this.setProgress({
        currentPage: pageNum,
        hasHistory: this.baseRecord !== null,
        totalPages: totalPages ?? this.progress().totalPages
      }), !this.baseRecord))
        return;
      let nextRecord = {
        ...this.baseRecord,
        pageNum,
        totalPages,
        updatedAt: Date.now()
      };
      this.sameProgress(nextRecord, this.lastSaved) || (this.pending = nextRecord, this.schedule());
    }
    dispose() {
      this.flush(), window.removeEventListener("pagehide", this.flush), document.removeEventListener("visibilitychange", this.onVisibilityChange);
    }
    schedule() {
      this.timer === null && (this.timer = window.setTimeout(this.flush, SAVE_DELAY_MS));
    }
    sameProgress(left, right) {
      return !!(left && right && left.galleryId === right.galleryId && left.token === right.token && left.pageNum === right.pageNum && left.totalPages === right.totalPages);
    }
  };
  function loadReadHistory(galleryId, token) {
    return GM_getValue(historyKey(galleryId, token), null);
  }
  function loadReadHistoryRecords() {
    return GM_listValues().filter((key) => key.startsWith(HISTORY_QUEUE_KEY_PREFIX)).sort((left, right) => right.localeCompare(left)).map((key) => {
      let reference = GM_getValue(key, null);
      if (!reference)
        return null;
      let record = GM_getValue(
        `${HISTORY_KEY_PREFIX}${reference}`,
        null
      );
      return record?.queueOrder === queueOrderFromKey(key) ? record : null;
    }).filter((record) => record !== null);
  }
  function loadDisplayReadHistoryRecords() {
    return loadReadHistoryRecords().filter(
      (record) => record.gallery !== void 0
    );
  }
  function exportReadHistory() {
    let archive = {
      type: READ_HISTORY_ARCHIVE_TYPE,
      version: READ_HISTORY_ARCHIVE_VERSION,
      records: loadReadHistoryRecords().map((record) => ({
        galleryId: record.galleryId,
        gallery: mergeGalleryInfo(void 0, record.gallery),
        pageNum: record.pageNum,
        token: record.token,
        totalPages: record.totalPages,
        updatedAt: record.updatedAt
      }))
    };
    return JSON.stringify(archive, null, 2);
  }
  function importReadHistory(source) {
    let archive = parseReadHistoryArchive(JSON.parse(source)), imported = /* @__PURE__ */ new Map();
    for (let archived of archive.records) {
      let record = archiveRecordToHistory(archived), reference = historyReference(record.galleryId, record.token), previous = imported.get(reference);
      if (!previous) {
        imported.set(reference, record);
        continue;
      }
      let newer = record.updatedAt >= previous.updatedAt ? record : previous, older = newer === record ? previous : record;
      imported.set(reference, {
        ...newer,
        gallery: mergeGalleryInfo(older.gallery, newer.gallery)
      });
    }
    for (let [reference, record] of imported) {
      let key = `${HISTORY_KEY_PREFIX}${reference}`, previous = GM_getValue(key, null), importedIsNewer = !previous || record.updatedAt >= previous.updatedAt, retained = importedIsNewer ? record : previous;
      GM_setValue(key, {
        ...retained,
        gallery: importedIsNewer ? mergeGalleryInfo(previous?.gallery, record.gallery) : mergeGalleryInfo(record.gallery, previous.gallery),
        queueOrder: previous?.queueOrder ?? ""
      });
    }
    return pruneReadHistory(), Math.min(imported.size, READ_HISTORY_LIMIT);
  }
  function clearReadHistory() {
    for (let key of GM_listValues())
      (key.startsWith(HISTORY_KEY_PREFIX) || key.startsWith(HISTORY_QUEUE_KEY_PREFIX)) && GM_deleteValue(key);
    state.gallery.readHistoryCount.set(0);
  }
  function removeReadHistory(galleryId, token) {
    let key = historyKey(galleryId, token), record = GM_getValue(key, null);
    record && (GM_deleteValue(key), GM_deleteValue(queueKey(record.queueOrder)), state.gallery.readHistoryCount.set(
      Math.max(0, state.gallery.readHistoryCount.reload() - 1)
    ));
  }
  function updateReadHistoryGalleryInfo(galleryId, token, gallery2) {
    let record = loadReadHistory(galleryId, token);
    if (!record)
      return null;
    let updated = {
      ...record,
      gallery: mergeGalleryInfo(record.gallery, gallery2)
    };
    return GM_setValue(historyKey(galleryId, token), updated), updated;
  }
  function recordGalleryVisit(galleryId, token, totalPages, gallery2) {
    let existing = loadReadHistory(galleryId, token), record = existing ? {
      ...existing,
      gallery: mergeGalleryInfo(existing.gallery, gallery2),
      totalPages,
      updatedAt: Date.now()
    } : {
      gallery: gallery2,
      galleryId,
      pageNum: -1,
      token,
      totalPages,
      updatedAt: Date.now()
    };
    return saveReadHistory(record), record;
  }
  function saveReadHistory(record) {
    let key = historyKey(record.galleryId, record.token), previous = GM_getValue(key, null), exists = previous !== null, queueOrder = createQueueOrder(record);
    if (GM_setValue(key, {
      ...record,
      gallery: mergeGalleryInfo(previous?.gallery, record.gallery),
      queueOrder
    }), GM_setValue(queueKey(queueOrder), historyReference(record.galleryId, record.token)), !exists) {
      let count = state.gallery.readHistoryCount.reload() + 1;
      state.gallery.readHistoryCount.set(count), count >= HISTORY_COMPACT_THRESHOLD && pruneReadHistory();
    }
  }
  function mergeGalleryInfo(previous, current) {
    let merged = {
      category: current?.category ?? previous?.category,
      categoryClass: current?.categoryClass ?? previous?.categoryClass,
      coverUrl: current?.coverUrl ?? previous?.coverUrl,
      language: current?.language ?? previous?.language,
      postedAt: current?.postedAt ?? (typeof previous?.postedAt == "number" ? previous.postedAt : void 0),
      rating: current?.rating ?? (typeof previous?.rating == "number" ? previous.rating : void 0),
      title: current?.title ?? previous?.title,
      titleSub: current?.titleSub ?? previous?.titleSub,
      uploader: current?.uploader ?? previous?.uploader
    }, entries = Object.entries(merged).filter((entry) => entry[1] !== void 0);
    return entries.length > 0 ? Object.fromEntries(entries) : void 0;
  }
  function parseReadHistoryArchive(source) {
    if (!isRecord(source) || source.type !== READ_HISTORY_ARCHIVE_TYPE || source.version !== READ_HISTORY_ARCHIVE_VERSION || !Array.isArray(source.records))
      throw new Error("Invalid EhPeek history archive.");
    return {
      type: READ_HISTORY_ARCHIVE_TYPE,
      version: READ_HISTORY_ARCHIVE_VERSION,
      records: source.records.map(parseReadHistoryRecord)
    };
  }
  function parseReadHistoryRecord(source) {
    if (!isRecord(source) || !Number.isSafeInteger(source.galleryId) || source.galleryId <= 0 || typeof source.token != "string" || source.token.length === 0 || !Number.isSafeInteger(source.pageNum) || source.pageNum < -1 || typeof source.updatedAt != "number" || !Number.isFinite(source.updatedAt) || source.updatedAt <= 0 || source.totalPages !== void 0 && (!Number.isSafeInteger(source.totalPages) || source.totalPages <= 0))
      throw new Error("Invalid EhPeek history record.");
    return {
      galleryId: source.galleryId,
      gallery: parseArchiveGallery(source.gallery),
      pageNum: source.pageNum,
      token: source.token,
      totalPages: source.totalPages,
      updatedAt: source.updatedAt
    };
  }
  function archiveRecordToHistory(source) {
    return {
      galleryId: source.galleryId,
      gallery: source.gallery,
      pageNum: source.pageNum,
      token: source.token,
      totalPages: source.totalPages,
      updatedAt: source.updatedAt
    };
  }
  function parseArchiveGallery(source) {
    if (source === void 0)
      return;
    if (!isRecord(source))
      throw new Error("Invalid gallery information in EhPeek history archive.");
    let gallery2 = {
      category: optionalString(source, "category"),
      categoryClass: optionalString(source, "categoryClass"),
      coverUrl: optionalString(source, "coverUrl"),
      language: optionalString(source, "language"),
      postedAt: optionalPositiveNumber(source, "postedAt"),
      rating: optionalNumber(source, "rating"),
      title: optionalString(source, "title"),
      titleSub: optionalString(source, "titleSub"),
      uploader: optionalString(source, "uploader")
    };
    return Object.values(gallery2).some((value) => value !== void 0) ? gallery2 : void 0;
  }
  function optionalString(source, key) {
    let value = source[key];
    if (value !== void 0 && typeof value != "string")
      throw new Error("Invalid EhPeek history record.");
    return value;
  }
  function optionalNumber(source, key) {
    let value = source[key];
    if (value !== void 0 && (typeof value != "number" || !Number.isFinite(value)))
      throw new Error("Invalid EhPeek history record.");
    return value;
  }
  function optionalPositiveNumber(source, key) {
    let value = optionalNumber(source, key);
    if (value !== void 0 && value <= 0)
      throw new Error("Invalid EhPeek history record.");
    return value;
  }
  function isRecord(source) {
    return typeof source == "object" && source !== null && !Array.isArray(source);
  }
  function historyKey(galleryId, token) {
    return `${HISTORY_KEY_PREFIX}${historyReference(galleryId, token)}`;
  }
  function pruneReadHistory() {
    let keys = GM_listValues(), queueKeys = keys.filter((key) => key.startsWith(HISTORY_QUEUE_KEY_PREFIX)), records = keys.filter((key) => key.startsWith(HISTORY_KEY_PREFIX)).map((key) => ({ key, record: GM_getValue(key, null) })).filter(
      (entry) => entry.record !== null
    ).sort((left, right) => right.record.updatedAt - left.record.updatedAt), retained = records.slice(0, READ_HISTORY_LIMIT);
    for (let entry of records.slice(retained.length))
      GM_deleteValue(entry.key);
    retained.forEach((entry) => {
      let queueOrder = createQueueOrder(entry.record), record = { ...entry.record, queueOrder };
      GM_setValue(entry.key, record), GM_setValue(
        queueKey(queueOrder),
        historyReference(record.galleryId, record.token)
      );
    });
    for (let key of queueKeys) {
      let reference = GM_getValue(key, null), record = reference ? GM_getValue(`${HISTORY_KEY_PREFIX}${reference}`, null) : null;
      (!record || queueKey(record.queueOrder) !== key) && GM_deleteValue(key);
    }
    state.gallery.readHistoryCount.set(retained.length);
  }
  function historyReference(galleryId, token) {
    return `${galleryId}:${token}`;
  }
  function queueKey(order) {
    return `${HISTORY_QUEUE_KEY_PREFIX}${order}`;
  }
  function queueOrderFromKey(key) {
    return key.slice(HISTORY_QUEUE_KEY_PREFIX.length);
  }
  function createQueueOrder(record) {
    return `${record.updatedAt}-${record.galleryId}`;
  }

  // src/components/Enhance/ReadHistory.tsx
  var _tmpl$12 = /* @__PURE__ */ template('<nav class="flex flex-col items-center ui-gap-sm border-0 border-y border-solid ehp-color-site-border-subtle-b ui-p-md">'), _tmpl$26 = /* @__PURE__ */ template('<span class="text-center textsize-md font-600 ehp-color-site-text"><span class=block>'), _tmpl$34 = /* @__PURE__ */ template('<div class="flex flex-wrap items-center justify-center ui-gap-sm"><input class=hidden type=file accept=application/json,.json><button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$44 = /* @__PURE__ */ template('<button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$54 = /* @__PURE__ */ template('<span class="textsize-sm ehp-color-site-text opacity-75">'), _tmpl$64 = /* @__PURE__ */ template("<div>"), _tmpl$73 = /* @__PURE__ */ template('<div class="ui-p-xl text-center textsize-md ehp-color-site-text opacity-72">');
  function ReadHistoryPage(props) {
    let [items, setItems] = createSignal(untrack(() => props.items)), pageCount = createMemo(() => Math.max(1, Math.ceil(items().length / props.pageSize))), [pageIndex, setPageIndex] = createSignal(Math.min(props.initialPageIndex, untrack(pageCount) - 1)), [transferStatus, setTransferStatus] = createSignal(""), historyFileInput, pageItems = createMemo(() => {
      let start = pageIndex() * props.pageSize;
      return items().slice(start, start + props.pageSize);
    }), visibleRange = createMemo(() => {
      if (items().length === 0)
        return "0 / 0";
      let start = pageIndex() * props.pageSize + 1, end = Math.min(start + props.pageSize - 1, items().length);
      return i18n_default.history.range.replace("{start}", String(start)).replace("{end}", String(end)).replace("{total}", String(items().length));
    }), navigate = (nextPageIndex, scrollToPageBar = "top", updateUrl = !0) => {
      let nextIndex = Math.max(0, Math.min(nextPageIndex, pageCount() - 1));
      nextIndex !== pageIndex() && (setPageIndex(nextIndex), updateUrl && window.history.pushState(window.history.state, "", readHistoryUrl(nextIndex)), props.source.handle.scrollReadHistoryPage(scrollToPageBar));
    }, clearHistory = () => {
      window.confirm(i18n_default.history.clearConfirm) && (clearReadHistory(), setItems([]), setPageIndex(0), setTransferStatus(""), window.history.replaceState(window.history.state, "", readHistoryUrl()));
    }, importHistoryFile = async (file) => {
      try {
        let count = importReadHistory(await file.text());
        setItems(loadDisplayReadHistoryRecords().map((record) => ({
          currentPage: record.pageNum,
          galleryId: record.galleryId,
          info: record.gallery,
          token: record.token,
          totalPages: record.totalPages,
          updatedAt: record.updatedAt
        }))), setPageIndex(0), setTransferStatus(i18n_default.history.imported.replace("{count}", String(count))), window.history.replaceState(window.history.state, "", readHistoryUrl());
      } catch {
        setTransferStatus(i18n_default.history.importFailed);
      }
    }, exportHistoryFile = () => {
      let url = URL.createObjectURL(new Blob([exportReadHistory()], {
        type: "application/json"
      })), link = document.createElement("a");
      link.href = url, link.download = `ehpeek-history-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`, link.click(), URL.revokeObjectURL(url), setTransferStatus(i18n_default.history.exported);
    }, removeHistoryItem = (item) => {
      if (!window.confirm(i18n_default.history.removeConfirm))
        return;
      removeReadHistory(item.galleryId, item.token);
      let nextItems = items().filter((candidate) => candidate.galleryId !== item.galleryId || candidate.token !== item.token), nextPageCount = Math.max(1, Math.ceil(nextItems.length / props.pageSize)), nextPageIndex = Math.min(pageIndex(), nextPageCount - 1);
      setItems(nextItems), setPageIndex(nextPageIndex), window.history.replaceState(window.history.state, "", readHistoryUrl(nextPageIndex));
    };
    createEffect(() => {
      props.source.handle.updateReadHistoryItems(pageItems());
    }), onMount(() => {
      let syncFromHistory = () => {
        let page2 = extractPageType();
        page2.type === "readHistory" && navigate(page2.pageIndex, "top", !1);
      };
      window.addEventListener("popstate", syncFromHistory);
      let stopRemoval = props.source.handle.listenForReadHistoryRemoval(removeHistoryItem);
      onCleanup(() => {
        stopRemoval(), window.removeEventListener("popstate", syncFromHistory);
      });
    });
    let navigation = (showHeader) => (() => {
      var _el$ = _tmpl$12();
      return insert(_el$, showHeader && [(() => {
        var _el$2 = _tmpl$26(), _el$3 = _el$2.firstChild;
        return insert(_el$2, visibleRange, _el$3), insert(_el$3, () => i18n_default.history.limit.replace("{limit}", String(READ_HISTORY_LIMIT))), _el$2;
      })(), (() => {
        var _el$4 = _tmpl$34(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling;
        _el$5.addEventListener("change", (event) => {
          let input2 = event.currentTarget, file = input2.files?.[0];
          input2.value = "", file && importHistoryFile(file);
        });
        var _ref$ = historyFileInput;
        return typeof _ref$ == "function" ? use(_ref$, _el$5) : historyFileInput = _el$5, _el$6.$$click = () => historyFileInput.click(), insert(_el$6, () => i18n_default.history.actions.import), _el$7.$$click = exportHistoryFile, insert(_el$7, () => i18n_default.history.actions.export), insert(_el$4, (() => {
          var _c$2 = memo(() => items().length > 0);
          return () => _c$2() && (() => {
            var _el$8 = _tmpl$44();
            return _el$8.$$click = clearHistory, insert(_el$8, () => i18n_default.history.actions.clear), _el$8;
          })();
        })(), null), _el$4;
      })(), memo(() => memo(() => !!transferStatus())() && (() => {
        var _el$9 = _tmpl$54();
        return insert(_el$9, transferStatus), _el$9;
      })())], null), insert(_el$, (() => {
        var _c$ = memo(() => pageCount() > 1);
        return () => _c$() && createComponent(ScrollPageBar, {
          get currentIndex() {
            return pageIndex();
          },
          get maxIndex() {
            return pageCount() - 1;
          },
          onNavigate: navigate,
          urlForIndex: readHistoryUrl
        });
      })(), null), _el$;
    })();
    return (() => {
      var _el$0 = _tmpl$64();
      return insert(_el$0, createComponent(PageSwipe, {
        canNavigate: (direction) => direction === "next" ? pageIndex() + 1 < pageCount() : pageIndex() > 0,
        onNavigate: (direction) => navigate(direction === "next" ? pageIndex() + 1 : pageIndex() - 1),
        target: () => props.source.elems.resultList.Component()
      }), null), insert(_el$0, () => navigation(!0), null), insert(_el$0, (() => {
        var _c$3 = memo(() => items().length === 0);
        return () => _c$3() && (() => {
          var _el$1 = _tmpl$73();
          return insert(_el$1, () => i18n_default.history.empty), _el$1;
        })();
      })(), null), insert(_el$0, (() => {
        var _c$4 = memo(() => pageCount() > 1);
        return () => _c$4() && createComponent(Portal, {
          get mount() {
            return props.source.elems.navigationBottomMount.Component();
          },
          get children() {
            return navigation(!1);
          }
        });
      })(), null), _el$0;
    })();
  }
  delegateEvents(["click"]);

  // src/components/Enhance/SearchHistory.tsx
  var _tmpl$13 = /* @__PURE__ */ template('<section class="fixed z-ui flex box-border max-h-[60dvh] flex-col overflow-x-hidden overflow-y-auto overscroll-contain ui-rounded-md border ehp-color-site-border ehp-color-site-elevated ehp-color-site-text font-sans"role=list>'), _tmpl$27 = /* @__PURE__ */ template('<div class="flex min-w-0 flex-none items-stretch border-0 border-b ehp-color-site-border-subtle-b last:border-b-0"role=listitem><button type=button></button><button type=button class="appearance-none inline-flex ui-hit-w-lg ui-hit-min-h-lg flex-none items-center justify-center border-0 border-l ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text textsize-xl font-inherit leading-1 cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-item-hover)]">×');
  function SearchHistory(props) {
    let dropdown, [searchValue, setSearchValue] = createSignal(untrack(() => props.source.data.value)), [history, setHistory] = createSignal(loadSearchHistory()), [open, setOpen] = createSignal(!1), [activeIndex, setActiveIndex] = createSignal(-1), [position, setPosition] = createSignal(null), itemButtons = [], visiblePosition = () => open() && !searchValue().trim() && history().length > 0 ? position() : null, selectHistory = (item) => {
      props.source.handle.applySearchSelection(item), setOpen(!1);
    };
    return onMount(() => {
      let updatePosition = () => {
        setPosition(props.source.handle.readSearchOverlayPosition());
      }, showHistory = () => {
        updatePosition(), setActiveIndex(-1), setOpen(!0);
      }, moveSelection = (offset) => {
        let items = history();
        if (items.length === 0)
          return;
        let current = activeIndex(), next = current < 0 ? offset > 0 ? 0 : items.length - 1 : (current + offset + items.length) % items.length;
        setActiveIndex(next), window.requestAnimationFrame(() => itemButtons[next]?.scrollIntoView({
          block: "nearest"
        }));
      }, onInputKeyDown = (event) => {
        if (visiblePosition())
          if (event.key === "ArrowDown" || event.key === "ArrowUp")
            event.preventDefault(), moveSelection(event.key === "ArrowDown" ? 1 : -1);
          else if (event.key === "Enter" && activeIndex() >= 0) {
            event.preventDefault();
            let item = history()[activeIndex()];
            item !== void 0 && selectHistory(item);
          } else event.key === "Escape" && (event.preventDefault(), setOpen(!1));
      }, updateSearchValue = (value, focused) => {
        setSearchValue(value), !value.trim() && focused && showHistory();
      }, recordSearch = (sourceValue) => {
        let value = sourceValue.trim();
        value && setHistory(addSearchHistory(value));
      }, disconnect = props.source.handle.listenSearchHistoryOverlay({
        onFocus: showHistory,
        onInput: updateSearchValue,
        onKeyDown: onInputKeyDown,
        onOutsidePointer: () => setOpen(!1),
        onPositionChange: updatePosition,
        onSubmit: recordSearch
      }, () => dropdown ?? null);
      updateSearchValue(props.source.data.value, !1), onCleanup(disconnect);
    }), createComponent(Show, {
      get when() {
        return visiblePosition();
      },
      children: (currentPosition) => (() => {
        var _el$ = _tmpl$13(), _ref$ = dropdown;
        return typeof _ref$ == "function" ? use(_ref$, _el$) : dropdown = _el$, insert(_el$, createComponent(For, {
          get each() {
            return history();
          },
          children: (item, index) => (() => {
            var _el$2 = _tmpl$27(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
            return _el$3.$$click = () => selectHistory(item), _el$3.addEventListener("pointerenter", () => setActiveIndex(index())), use((button2) => {
              itemButtons[index()] = button2;
            }, _el$3), setAttribute(_el$3, "title", item), insert(_el$3, item), _el$4.$$click = () => {
              setHistory(removeSearchHistory(item));
            }, createRenderEffect(() => className(_el$3, `appearance-none block min-w-0 ui-hit-min-h-lg flex-1 overflow-hidden text-ellipsis whitespace-nowrap ui-px-lg border-0 ehp-color-site-text text-left textsize-lg font-inherit cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-item-hover)] ${activeIndex() === index() ? "bg-[var(--color-site-item-hover)]" : "bg-transparent"}`)), _el$2;
          })()
        })), createRenderEffect((_p$) => {
          var _v$ = `${currentPosition().left}px`, _v$2 = `${currentPosition().top}px`, _v$3 = `${currentPosition().width}px`;
          return _v$ !== _p$.e && setStyleProperty(_el$, "left", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "top", _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$, "width", _p$.a = _v$3), _p$;
        }, {
          e: void 0,
          t: void 0,
          a: void 0
        }), _el$;
      })()
    });
  }
  delegateEvents(["click"]);

  // src/components/Enhance/MyTags.ts
  async function loadMyTagsPage(tagSet) {
    let url = new URL("/mytags", window.location.origin);
    tagSet && url.searchParams.set("tagset", tagSet);
    let response = await requestPage(url.href);
    return extractMyTagsPageData(response.document, tagSet);
  }
  function loadMyTagAppearances() {
    return state.gallery.myTags.value && state.gallery.myTagAppearances.stored() ? state.gallery.myTagAppearances.reload() : null;
  }
  async function refreshMyTags(initialPage) {
    if (!state.gallery.myTags.value)
      return null;
    try {
      let initialData = initialPage ?? await loadMyTagsPage(), options = initialData.options;
      state.gallery.myTagSets.set(options);
      let appearances = (options.length > 0 ? await Promise.all(options.map(async (option2) => option2.selected ? initialData : loadMyTagsPage(option2.value))) : [initialData]).flatMap((page2) => page2.enabled ? page2.appearances : []), unique = Array.from(new Map(appearances.map((appearance) => [appearance.name, appearance])).values());
      return state.gallery.myTagAppearances.set(unique), unique;
    } catch (error) {
      return console.error("[ehpeek] Could not load My Tags", error), null;
    }
  }

  // node_modules/.pnpm/[email protected]/node_modules/solid-js/store/dist/store.js
  var $RAW = /* @__PURE__ */ Symbol("store-raw"), $NODE = /* @__PURE__ */ Symbol("store-node"), $HAS = /* @__PURE__ */ Symbol("store-has"), $SELF = /* @__PURE__ */ Symbol("store-self");
  function wrap$1(value) {
    let p = value[$PROXY];
    if (!p && (Object.defineProperty(value, $PROXY, {
      value: p = new Proxy(value, proxyTraps$1)
    }), !Array.isArray(value))) {
      let keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value), proto = Object.getPrototypeOf(value), isClass = proto !== null && value !== null && typeof value == "object" && !Array.isArray(value) && proto !== Object.prototype;
      if (isClass) {
        let descriptors = Object.getOwnPropertyDescriptors(proto);
        keys.push(...Object.keys(descriptors)), Object.assign(desc, descriptors);
      }
      for (let i = 0, l = keys.length; i < l; i++) {
        let prop = keys[i];
        isClass && prop === "constructor" || desc[prop].get && Object.defineProperty(value, prop, {
          configurable: !0,
          enumerable: desc[prop].enumerable,
          get: desc[prop].get.bind(p)
        });
      }
    }
    return p;
  }
  function isWrappable(obj) {
    let proto;
    return obj != null && typeof obj == "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
  }
  function unwrap(item, set = /* @__PURE__ */ new Set()) {
    let result, unwrapped, v, prop;
    if (result = item != null && item[$RAW]) return result;
    if (!isWrappable(item) || set.has(item)) return item;
    if (Array.isArray(item)) {
      Object.isFrozen(item) ? item = item.slice(0) : set.add(item);
      for (let i = 0, l = item.length; i < l; i++)
        v = item[i], (unwrapped = unwrap(v, set)) !== v && (item[i] = unwrapped);
    } else {
      Object.isFrozen(item) ? item = Object.assign({}, item) : set.add(item);
      let keys = Object.keys(item), desc = Object.getOwnPropertyDescriptors(item);
      for (let i = 0, l = keys.length; i < l; i++)
        prop = keys[i], !desc[prop].get && (v = item[prop], (unwrapped = unwrap(v, set)) !== v && (item[prop] = unwrapped));
    }
    return item;
  }
  function getNodes(target, symbol) {
    let nodes = target[symbol];
    return nodes || Object.defineProperty(target, symbol, {
      value: nodes = /* @__PURE__ */ Object.create(null)
    }), nodes;
  }
  function getNode(nodes, property, value) {
    if (nodes[property]) return nodes[property];
    let [s, set] = createSignal(value, {
      equals: !1,
      internal: !0
    });
    return s.$ = set, nodes[property] = s;
  }
  function proxyDescriptor$1(target, property) {
    let desc = Reflect.getOwnPropertyDescriptor(target, property);
    return !desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE || (delete desc.value, delete desc.writable, desc.get = () => target[$PROXY][property]), desc;
  }
  function trackSelf(target) {
    getListener() && getNode(getNodes(target, $NODE), $SELF)();
  }
  function ownKeys(target) {
    return trackSelf(target), Reflect.ownKeys(target);
  }
  var proxyTraps$1 = {
    get(target, property, receiver) {
      if (property === $RAW) return target;
      if (property === $PROXY) return receiver;
      if (property === $TRACK)
        return trackSelf(target), receiver;
      let nodes = getNodes(target, $NODE), tracked = nodes[property], value = tracked ? tracked() : target[property];
      if (property === $NODE || property === $HAS || property === "__proto__") return value;
      if (!tracked) {
        let desc = Object.getOwnPropertyDescriptor(target, property);
        getListener() && (typeof value != "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get) && (value = getNode(nodes, property, value)());
      }
      return isWrappable(value) ? wrap$1(value) : value;
    },
    has(target, property) {
      return property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__" ? !0 : (getListener() && getNode(getNodes(target, $HAS), property)(), property in target);
    },
    set() {
      return !0;
    },
    deleteProperty() {
      return !0;
    },
    ownKeys,
    getOwnPropertyDescriptor: proxyDescriptor$1
  };
  function setProperty(state2, property, value, deleting = !1) {
    if (property === "__proto__" || !deleting && state2[property] === value) return;
    let prev = state2[property], len = state2.length;
    value === void 0 ? (delete state2[property], state2[$HAS] && state2[$HAS][property] && prev !== void 0 && state2[$HAS][property].$()) : (state2[property] = value, state2[$HAS] && state2[$HAS][property] && prev === void 0 && state2[$HAS][property].$());
    let nodes = getNodes(state2, $NODE), node;
    if ((node = getNode(nodes, property, prev)) && node.$(() => value), Array.isArray(state2) && state2.length !== len) {
      for (let i = state2.length; i < len; i++) (node = nodes[i]) && node.$();
      (node = getNode(nodes, "length", len)) && node.$(state2.length);
    }
    (node = nodes[$SELF]) && node.$();
  }
  function mergeStoreNode(state2, value) {
    let keys = Object.keys(value);
    for (let i = 0; i < keys.length; i += 1) {
      let key = keys[i];
      isUnsafeKey$1(key) || setProperty(state2, key, value[key]);
    }
  }
  function isUnsafeKey$1(property) {
    return property === "__proto__" || property === "constructor" || property === "prototype";
  }
  function updateArray(current, next) {
    if (typeof next == "function" && (next = next(current)), next = unwrap(next), Array.isArray(next)) {
      if (current === next) return;
      let i = 0, len = next.length;
      for (; i < len; i++) {
        let value = next[i];
        current[i] !== value && setProperty(current, i, value);
      }
      setProperty(current, "length", len);
    } else mergeStoreNode(current, next);
  }
  function updatePath(current, path, traversed = []) {
    let part, prev = current;
    if (path.length > 1) {
      part = path.shift();
      let partType = typeof part, isArray = Array.isArray(current);
      if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part)))
        return;
      if (Array.isArray(part)) {
        for (let i = 0; i < part.length; i++)
          updatePath(current, [part[i]].concat(path), traversed);
        return;
      } else if (isArray && partType === "function") {
        for (let i = 0; i < current.length; i++)
          part(current[i], i) && updatePath(current, [i].concat(path), traversed);
        return;
      } else if (isArray && partType === "object") {
        let {
          from = 0,
          to = current.length - 1,
          by = 1
        } = part;
        for (let i = from; i <= to; i += by)
          updatePath(current, [i].concat(path), traversed);
        return;
      } else if (path.length > 1) {
        updatePath(current[part], path, [part].concat(traversed));
        return;
      }
      prev = current[part], traversed = [part].concat(traversed);
    }
    let value = path[0];
    typeof value == "function" && (value = value(prev, traversed), value === prev) || part === void 0 && value == null || (value = unwrap(value), part === void 0 || isWrappable(prev) && isWrappable(value) && !Array.isArray(value) ? mergeStoreNode(prev, value) : setProperty(current, part, value));
  }
  function createStore(...[store, options]) {
    let unwrappedStore = unwrap(store || {}), isArray = Array.isArray(unwrappedStore), wrappedStore = wrap$1(unwrappedStore);
    function setStore(...args) {
      batch(() => {
        isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
      });
    }
    return [wrappedStore, setStore];
  }

  // src/components/Widgets/Dialog.tsx
  var _tmpl$14 = /* @__PURE__ */ template('<div class="fixed inset-0 z-dialog box-border flex items-center justify-center overflow-hidden ui-p-lg bg-black/65 pointer-events-auto font-sans"role=dialog aria-modal=true><div><div><h2 class="m-0 textsize-lg font-700"></h2><button type=button></button></div><div>'), DIALOG_WIDTHS = {
    md: "max-w-[calc(var(--ui-control-size-xl)*7.5)]",
    lg: "max-w-[calc(var(--ui-control-size-xl)*9.25)]"
  };
  function Dialog(props) {
    onMount(() => {
      let scrollRoots = [document.documentElement, document.body], overflowStyles = scrollRoots.map((root) => ({
        priority: root.style.getPropertyPriority("overflow"),
        value: root.style.getPropertyValue("overflow")
      })), closeOnEscape = (event) => {
        event.key === "Escape" && (event.preventDefault(), event.stopImmediatePropagation(), props.onClose());
      };
      for (let root of scrollRoots)
        root.style.setProperty("overflow", "hidden", "important");
      window.addEventListener("keydown", closeOnEscape, !0), onCleanup(() => {
        window.removeEventListener("keydown", closeOnEscape, !0), scrollRoots.forEach((root, index) => {
          let previous = overflowStyles[index];
          previous?.value ? root.style.setProperty("overflow", previous.value, previous.priority) : root.style.removeProperty("overflow");
        });
      });
    });
    let reader = () => props.variant === "reader";
    return createComponent(OverlayPortal, {
      get children() {
        var _el$ = _tmpl$14(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$3.nextSibling;
        return _el$.addEventListener("wheel", (event) => event.stopPropagation()), _el$.$$pointerdown = (event) => event.stopPropagation(), _el$.$$click = (event) => {
          event.stopPropagation(), event.target === event.currentTarget && props.onClose();
        }, insert(_el$4, () => props.title), _el$5.$$click = () => props.onClose(), insert(_el$5, createComponent(Icon2, {
          name: "close",
          size: "var(--ui-icon-size-md)"
        })), insert(_el$6, () => props.children), createRenderEffect((_p$) => {
          var _v$ = props.label, _v$2 = `box-border flex w-full ${DIALOG_WIDTHS[props.width]} max-h-[min(calc(var(--ui-control-size-xl)*12.75),calc(100dvh_-_var(--ui-space-lg)_-_var(--ui-space-lg)))] flex-col overflow-hidden ui-rounded-lg border shadow-xl ${reader() ? "border-[var(--color-border)] bg-[var(--color-background)] text-[var(--color-text)]" : "ehp-color-site-border ehp-color-site-elevated ehp-color-site-text"}`, _v$3 = `flex box-border min-h-[var(--ui-control-size-lg)] flex-none items-center justify-between ui-gap-md ui-py-sm ui-pl-lg ui-pr-sm border-0 border-b ${reader() ? "border-[var(--color-border)]" : "ehp-color-site-border-subtle-b"}`, _v$4 = `inline-flex w-[var(--ui-control-size-md)] h-[var(--ui-control-size-md)] flex-none items-center justify-center p-0 ui-rounded-md border-0 bg-transparent cursor-pointer ${reader() ? "text-[var(--color-text)] hover:bg-[var(--color-badge)]" : "ehp-color-site-text hover:bg-[var(--color-site-item-hover)]"}`, _v$5 = i18n_default.common.actions.close, _v$6 = i18n_default.common.actions.close, _v$7 = `min-h-0 overflow-y-auto overscroll-contain ui-pb-lg [&>:last-child]:!border-b-0 ${props.bodyClass ?? ""}`;
          return _v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && className(_el$2, _p$.t = _v$2), _v$3 !== _p$.a && className(_el$3, _p$.a = _v$3), _v$4 !== _p$.o && className(_el$5, _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$5, "aria-label", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$5, "title", _p$.n = _v$6), _v$7 !== _p$.s && className(_el$6, _p$.s = _v$7), _p$;
        }, {
          e: void 0,
          t: void 0,
          a: void 0,
          o: void 0,
          i: void 0,
          n: void 0,
          s: void 0
        }), _el$;
      }
    });
  }
  delegateEvents(["click", "pointerdown"]);

  // src/components/InteractionHelp.tsx
  var _tmpl$15 = /* @__PURE__ */ template('<div class="grid ui-gap-lg text-left textsize-md leading-[1.45]">'), _tmpl$28 = /* @__PURE__ */ template('<section><h3 class="m-0 ui-mb-sm textsize-md font-700"></h3><ul class="m-0 ui-pl-xl">'), _tmpl$35 = /* @__PURE__ */ template('<li class="ui-mb-xs last:mb-0">'), _tmpl$45 = /* @__PURE__ */ template("<strong>");
  function InteractionHelp(props) {
    return createComponent(Dialog, {
      bodyClass: "ui-p-xl",
      get label() {
        return i18n_default.help.title;
      },
      get onClose() {
        return props.onClose;
      },
      get title() {
        return i18n_default.help.title;
      },
      get variant() {
        return props.variant;
      },
      width: "lg",
      get children() {
        var _el$ = _tmpl$15();
        return insert(_el$, createComponent(For, {
          get each() {
            return i18n_default.help.sections;
          },
          children: (section) => (() => {
            var _el$2 = _tmpl$28(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
            return insert(_el$3, () => section.title), insert(_el$4, createComponent(For, {
              get each() {
                return section.items;
              },
              children: (item) => (() => {
                var _el$5 = _tmpl$35();
                return insert(_el$5, createComponent(HelpText, {
                  text: item
                })), _el$5;
              })()
            })), _el$2;
          })()
        })), _el$;
      }
    });
  }
  function HelpText(props) {
    return createComponent(For, {
      get each() {
        return props.text.split(/(\*\*[^*]+\*\*)/g);
      },
      children: (part) => part.startsWith("**") && part.endsWith("**") ? (() => {
        var _el$6 = _tmpl$45();
        return insert(_el$6, () => part.slice(2, -2)), _el$6;
      })() : part
    });
  }

  // src/components/SettingsMenu.tsx
  var _tmpl$16 = /* @__PURE__ */ template('<p class="box-border w-full m-0 ui-px-md ui-pb-md text-left whitespace-normal [overflow-wrap:anywhere] [contain:inline-size] [font-size:var(--ui-font-size-sm)] leading-[1.35] opacity-75">'), _tmpl$29 = /* @__PURE__ */ template('<div class="border-0 border-b ehp-color-site-border-subtle-b"><div class="flex items-stretch"><button type=button class="flex min-w-0 flex-1 min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-py-sm ui-pl-md ui-pr-sm ui-rounded-xs border-0 !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer [-webkit-tap-highlight-color:transparent]"><span></span><span class="flex flex-none items-center ui-gap-sm"><span class="[font-size:var(--ui-font-size-sm)] opacity-70"></span><span></span></span></button><button type=button class="flex flex-none w-[var(--ui-control-size-sm)] min-h-[var(--ui-control-size-lg)] items-center justify-center p-0 ui-rounded-xs border-0 !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text cursor-pointer font-inherit [font-size:var(--ui-font-size-md)] font-700 [-webkit-tap-highlight-color:transparent]"><span class="flex w-[var(--ui-icon-size-md)] h-[var(--ui-icon-size-md)] items-center justify-center rounded-full border border-[var(--color-site-border-subtle)] leading-none">?'), _tmpl$36 = /* @__PURE__ */ template('<label class="flex box-border w-full min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span><select class="box-border min-h-[var(--ui-control-size-sm)] min-w-[calc(var(--ui-control-size-xl)*2)] ui-px-sm ui-rounded-xs border ehp-color-site-border bg-[var(--color-site-surface)] ehp-color-site-text font-inherit [font-size:var(--ui-font-size-sm)] cursor-pointer">'), _tmpl$46 = /* @__PURE__ */ template("<option>"), _tmpl$55 = /* @__PURE__ */ template('<a class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text no-underline text-left [font-size:var(--ui-font-size-md)] cursor-pointer">'), _tmpl$65 = /* @__PURE__ */ template('<div class="pointer-events-auto fixed safe-top-sm safe-right-sm z-overlay box-border flex w-[calc(var(--ui-control-size-xl)*6)] max-w-[calc(100vw-16px)] max-h-[calc(100dvh-16px)] flex-col overflow-hidden ui-p-md border ehp-color-site-border ui-rounded-sm ehp-color-site-elevated ehp-color-site-text [font-size:var(--ui-font-size-md)] leading-[1.2]"><div class="grid grid-cols-4 flex-none ui-gap-xs ui-mb-sm ui-rounded-md border ehp-color-site-border overflow-hidden"role=tablist></div><div class="min-h-0 overflow-x-hidden overflow-y-auto overscroll-contain"><h2 class="m-0 ui-px-md ui-py-sm border-0 border-b ehp-color-site-border-subtle-b [font-size:var(--ui-font-size-md)] font-700"></h2><div id=ehpeek-settings-panel-general data-ehpeek-settings-tab=general role=tabpanel></div><div id=ehpeek-settings-panel-enhance data-ehpeek-settings-tab=enhance role=tabpanel></div><div id=ehpeek-settings-panel-options data-ehpeek-settings-tab=options role=tabpanel></div><div id=ehpeek-settings-panel-about data-ehpeek-settings-tab=about role=tabpanel><div class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text [font-size:var(--ui-font-size-md)] font-700"></div><a class="flex w-full min-h-[var(--ui-control-size-lg)] items-center overflow-hidden text-ellipsis whitespace-nowrap ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text no-underline [font-size:var(--ui-font-size-md)] font-700 hover:bg-[var(--color-site-item-hover)]"href=https://github.com/yamipot/ehpeek target=_blank rel="noopener noreferrer">v</a><button type=button class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span></button><button type=button class="flex w-full min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span><span class="flex flex-none"aria-hidden=true></span></button></div></div><div class="grid grid-cols-3 flex-none ui-gap-sm ui-mt-md ui-pt-md border-0 border-t border-t-[var(--color-site-border-subtle)]"><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"></button><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$74 = /* @__PURE__ */ template("<button type=button role=tab>"), _tmpl$83 = /* @__PURE__ */ template('<a class="flex min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md ui-py-sm border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text no-underline text-left"target=_blank rel="noopener noreferrer"><span class="min-w-0 [font-size:var(--ui-font-size-md)] font-700"></span><span class="flex flex-none items-center ui-gap-sm [font-size:var(--ui-font-size-sm)]">'), SETTINGS_SECTIONS = [["general", i18n_default.settings.general, "book-open"], ["enhance", i18n_default.settings.enhance, "sparkles"], ["options", i18n_default.settings.options, "settings"], ["about", i18n_default.settings.about, "info"]];
  var SETTINGS_DOT_CLASS = "block flex-none ui-w-md ui-h-md rounded-full", UI_SCALE_OPTIONS = UI_SCALE_NAMES.map((value) => ({
    label: String(uiScaleLevel(value)),
    value
  })), LICENSES = [{
    href: "https://github.com/yamipot/ehpeek/blob/master/LICENSE",
    license: "MIT",
    name: "EhPeek"
  }, {
    href: "https://github.com/solidjs/solid/blob/main/LICENSE",
    license: "MIT",
    name: "SolidJS"
  }, {
    href: "https://github.com/lucide-icons/lucide/blob/main/LICENSE",
    license: "ISC",
    name: "Lucide Icons"
  }, {
    href: "https://github.com/adobe/spectrum-design-data/blob/main/LICENSE",
    license: "Apache-2.0",
    name: "Adobe Spectrum Tokens"
  }];
  function SwitchButton(props) {
    let [helpOpen, setHelpOpen] = createSignal(!1);
    return (() => {
      var _el$ = _tmpl$29(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$3.nextSibling;
      return _el$3.$$click = (event) => {
        event.stopPropagation(), props.onChange(!props.checked);
      }, insert(_el$4, () => props.label), insert(_el$6, (() => {
        var _c$ = memo(() => !!props.checked);
        return () => _c$() ? i18n_default.settings.on : i18n_default.settings.off;
      })()), _el$8.$$click = (event) => {
        event.stopPropagation(), setHelpOpen((open) => !open);
      }, insert(_el$, createComponent(Show, {
        get when() {
          return helpOpen();
        },
        get children() {
          var _el$9 = _tmpl$16();
          return insert(_el$9, () => props.description), _el$9;
        }
      }), null), createRenderEffect(() => className(_el$7, `${SETTINGS_DOT_CLASS} ${props.checked ? "bg-[var(--color-state-on)]" : "bg-[var(--color-state-off)]"}`)), _el$;
    })();
  }
  function SelectSetting(props) {
    return (() => {
      var _el$0 = _tmpl$36(), _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling;
      return insert(_el$1, () => props.label), _el$10.addEventListener("change", (event) => {
        let value = props.options.find((option2) => option2.value === event.currentTarget.value)?.value;
        value && props.onChange(value);
      }), insert(_el$10, createComponent(For, {
        get each() {
          return props.options;
        },
        children: (option2) => (() => {
          var _el$11 = _tmpl$46();
          return insert(_el$11, () => option2.label), createRenderEffect(() => _el$11.value = option2.value), _el$11;
        })()
      })), createRenderEffect(() => setAttribute(_el$0, "translate", props.noTranslate ? "no" : void 0)), createRenderEffect(() => _el$10.value = props.value), _el$0;
    })();
  }
  function SettingsMenu(props) {
    let [draft, setDraft] = createStore(untrack(() => ({
      ...props.initState
    }))), [activeTab, setActiveTab] = createSignal("general"), [helpOpen, setHelpOpen] = createSignal(!1), [licensesOpen, setLicensesOpen] = createSignal(!1), [changed, setChanged] = createSignal(!1), menu, close = () => changed() && !window.confirm(i18n_default.settings.discardChanges) ? !1 : (props.onOpenChange(!1), !0), updateDraft = (key, value) => {
      setChanged(!0), setDraft(key, value);
    };
    return createEffect(() => {
      props.open && (setDraft(untrack(() => ({
        ...props.initState
      }))), setActiveTab("general"), setHelpOpen(!1), setLicensesOpen(!1), setChanged(!1));
    }), onMount(() => {
      let onPointerDown = (event) => {
        props.open && (event.target instanceof Element && menu.contains(event.target) || close() || (event.preventDefault(), event.stopImmediatePropagation()));
      }, onKeyDown = (event) => {
        props.open && event.key === "Escape" && (close() || (event.preventDefault(), event.stopImmediatePropagation()));
      };
      document.addEventListener("pointerdown", onPointerDown), document.addEventListener("keydown", onKeyDown), onCleanup(() => {
        document.removeEventListener("pointerdown", onPointerDown), document.removeEventListener("keydown", onKeyDown);
      });
    }), createComponent(Show, {
      get when() {
        return props.open;
      },
      get children() {
        return [(() => {
          var _el$12 = _tmpl$65(), _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, _el$15 = _el$14.firstChild, _el$16 = _el$15.nextSibling, _el$18 = _el$16.nextSibling, _el$19 = _el$18.nextSibling, _el$20 = _el$19.nextSibling, _el$21 = _el$20.firstChild, _el$22 = _el$21.nextSibling, _el$23 = _el$22.firstChild, _el$24 = _el$22.nextSibling, _el$25 = _el$24.firstChild, _el$26 = _el$24.nextSibling, _el$27 = _el$26.firstChild, _el$28 = _el$27.nextSibling, _el$29 = _el$14.nextSibling, _el$30 = _el$29.firstChild, _el$31 = _el$30.nextSibling, _el$32 = _el$31.nextSibling, _ref$ = menu;
          return typeof _ref$ == "function" ? use(_ref$, _el$12) : menu = _el$12, insert(_el$13, createComponent(For, {
            each: SETTINGS_SECTIONS,
            children: ([tab, label, icon]) => (() => {
              var _el$33 = _tmpl$74();
              return _el$33.$$click = () => setActiveTab(tab), setAttribute(_el$33, "aria-controls", `ehpeek-settings-panel-${tab}`), setAttribute(_el$33, "title", label), insert(_el$33, createComponent(Icon2, {
                name: icon,
                size: "var(--ui-icon-size-md)"
              })), createRenderEffect((_p$) => {
                var _v$7 = `flex min-w-0 min-h-[var(--ui-control-size-md)] items-center justify-center ui-gap-sm ui-px-sm border-0 ehp-color-site-text font-inherit [font-size:var(--ui-font-size-sm)] cursor-pointer ${activeTab() === tab ? "bg-[var(--color-site-item-hover)] font-700" : "bg-transparent hover:bg-[var(--color-site-item-hover)]"}`, _v$8 = activeTab() === tab;
                return _v$7 !== _p$.e && className(_el$33, _p$.e = _v$7), _v$8 !== _p$.t && setAttribute(_el$33, "aria-selected", _p$.t = _v$8), _p$;
              }, {
                e: void 0,
                t: void 0
              }), _el$33;
            })()
          })), insert(_el$15, () => SETTINGS_SECTIONS.find(([tab]) => tab === activeTab())?.[1]), insert(_el$16, createComponent(SwitchButton, {
            get checked() {
              return draft.readerEnabled;
            },
            get description() {
              return i18n_default.settings.readerHelp;
            },
            get label() {
              return i18n_default.settings.readerLabel;
            },
            onChange: (value) => updateDraft("readerEnabled", value)
          }), null), insert(_el$16, createComponent(SwitchButton, {
            get checked() {
              return draft.touchUiEnabled;
            },
            get description() {
              return i18n_default.settings.touchUiHelp;
            },
            get label() {
              return i18n_default.settings.touchUiLabel;
            },
            onChange: (value) => updateDraft("touchUiEnabled", value)
          }), null), insert(_el$16, createComponent(Show, {
            get when() {
              return draft.readHistoryEnabled;
            },
            get children() {
              var _el$17 = _tmpl$55();
              return insert(_el$17, () => i18n_default.settings.historyLabel), createRenderEffect(() => setAttribute(_el$17, "href", props.historyHref)), _el$17;
            }
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.enhanceSearchGridsEnabled;
            },
            get description() {
              return i18n_default.settings.enhanceSearchHelp;
            },
            get label() {
              return i18n_default.settings.enhanceSearchLabel;
            },
            onChange: (value) => updateDraft("enhanceSearchGridsEnabled", value)
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.enhanceThumbsGridsEnabled;
            },
            get description() {
              return i18n_default.settings.enhanceThumbsHelp;
            },
            get label() {
              return i18n_default.settings.enhanceThumbsLabel;
            },
            onChange: (value) => updateDraft("enhanceThumbsGridsEnabled", value)
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.replacePreviewWithScroll;
            },
            get description() {
              return i18n_default.settings.replacePreviewWithScrollHelp;
            },
            get label() {
              return i18n_default.settings.replacePreviewWithScrollLabel;
            },
            onChange: (value) => updateDraft("replacePreviewWithScroll", value)
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.myTagsEnabled;
            },
            get description() {
              return i18n_default.settings.myTagsHelp;
            },
            get label() {
              return i18n_default.settings.myTagsLabel;
            },
            onChange: (value) => updateDraft("myTagsEnabled", value)
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.readHistoryEnabled;
            },
            get description() {
              return i18n_default.settings.readHistoryHelp;
            },
            get label() {
              return i18n_default.settings.readHistoryLabel;
            },
            onChange: (value) => updateDraft("readHistoryEnabled", value)
          }), null), insert(_el$18, createComponent(SwitchButton, {
            get checked() {
              return draft.searchHistoryEnabled;
            },
            get description() {
              return i18n_default.settings.searchHistoryHelp;
            },
            get label() {
              return i18n_default.settings.searchHistoryLabel;
            },
            onChange: (value) => updateDraft("searchHistoryEnabled", value)
          }), null), insert(_el$19, createComponent(SwitchButton, {
            get checked() {
              return draft.readerFullscreenEnabled;
            },
            get description() {
              return i18n_default.settings.readerFullscreenHelp;
            },
            get label() {
              return i18n_default.settings.readerFullscreenLabel;
            },
            onChange: (value) => updateDraft("readerFullscreenEnabled", value)
          }), null), insert(_el$19, createComponent(SwitchButton, {
            get checked() {
              return draft.exitReaderOnFullscreenExit;
            },
            get description() {
              return i18n_default.settings.exitReaderOnFullscreenExitHelp;
            },
            get label() {
              return i18n_default.settings.exitReaderOnFullscreenExitLabel;
            },
            onChange: (value) => updateDraft("exitReaderOnFullscreenExit", value)
          }), null), insert(_el$19, createComponent(SwitchButton, {
            get checked() {
              return draft.openGalleryInNewTab;
            },
            get description() {
              return i18n_default.settings.openGalleryInNewTabHelp;
            },
            get label() {
              return i18n_default.settings.openGalleryInNewTabLabel;
            },
            onChange: (value) => updateDraft("openGalleryInNewTab", value)
          }), null), insert(_el$19, createComponent(SwitchButton, {
            get checked() {
              return draft.includeUnreadHistoryEnabled;
            },
            get description() {
              return i18n_default.settings.includeUnreadHistoryHelp;
            },
            get label() {
              return i18n_default.settings.includeUnreadHistoryLabel;
            },
            onChange: (value) => updateDraft("includeUnreadHistoryEnabled", value)
          }), null), insert(_el$19, createComponent(SelectSetting, {
            get label() {
              return i18n_default.settings.uiScaleLabel;
            },
            options: UI_SCALE_OPTIONS,
            get value() {
              return draft.uiScale;
            },
            onChange: (value) => {
              setChanged(!0), setDraft("uiScale", value);
            }
          }), null), insert(_el$19, createComponent(SelectSetting, {
            label: "Language",
            noTranslate: !0,
            options: APP_LOCALE_OPTIONS,
            get value() {
              return draft.locale;
            },
            onChange: (value) => {
              setChanged(!0), setDraft("locale", value);
            }
          }), null), insert(_el$21, "EhPeek"), insert(_el$22, "260807.1338", null), _el$24.$$click = () => setHelpOpen(!0), insert(_el$25, () => i18n_default.help.title), _el$26.$$click = () => setLicensesOpen(!0), insert(_el$27, () => i18n_default.settings.licenses), insert(_el$28, createComponent(Icon2, {
            name: "chevron-right",
            size: "var(--ui-icon-size-sm)"
          })), _el$30.$$click = (event) => {
            event.stopPropagation(), props.onApply({
              ...draft
            });
          }, insert(_el$30, () => i18n_default.common.actions.apply), _el$31.$$click = (event) => {
            event.stopPropagation(), setChanged(!0), setDraft({
              ...props.defaultState
            });
          }, insert(_el$31, () => i18n_default.common.actions.default), _el$32.$$click = (event) => {
            event.stopPropagation(), close();
          }, insert(_el$32, () => i18n_default.common.actions.close), insert(_el$12, createComponent(Show, {
            get when() {
              return helpOpen();
            },
            get children() {
              return createComponent(InteractionHelp, {
                variant: "site",
                onClose: () => setHelpOpen(!1)
              });
            }
          }), null), createRenderEffect((_p$) => {
            var _v$ = {
              "!right-auto safe-left-sm": props.leftHandedControls()
            }, _v$2 = i18n_default.settings.openSettings, _v$3 = activeTab() !== "general", _v$4 = activeTab() !== "enhance", _v$5 = activeTab() !== "options", _v$6 = activeTab() !== "about";
            return _p$.e = classList(_el$12, _v$, _p$.e), _v$2 !== _p$.t && setAttribute(_el$13, "aria-label", _p$.t = _v$2), _v$3 !== _p$.a && (_el$16.hidden = _p$.a = _v$3), _v$4 !== _p$.o && (_el$18.hidden = _p$.o = _v$4), _v$5 !== _p$.i && (_el$19.hidden = _p$.i = _v$5), _v$6 !== _p$.n && (_el$20.hidden = _p$.n = _v$6), _p$;
          }, {
            e: void 0,
            t: void 0,
            a: void 0,
            o: void 0,
            i: void 0,
            n: void 0
          }), _el$12;
        })(), createComponent(Show, {
          get when() {
            return licensesOpen();
          },
          get children() {
            return createComponent(Dialog, {
              get label() {
                return i18n_default.settings.licenses;
              },
              onClose: () => setLicensesOpen(!1),
              get title() {
                return i18n_default.settings.licenses;
              },
              variant: "site",
              width: "lg",
              get children() {
                return createComponent(For, {
                  each: LICENSES,
                  children: (license) => (() => {
                    var _el$34 = _tmpl$83(), _el$35 = _el$34.firstChild, _el$36 = _el$35.nextSibling;
                    return insert(_el$35, () => license.name), insert(_el$36, () => license.license, null), insert(_el$36, createComponent(Icon2, {
                      name: "external-link",
                      size: "var(--ui-icon-size-sm)"
                    }), null), createRenderEffect(() => setAttribute(_el$34, "href", license.href)), _el$34;
                  })()
                });
              }
            });
          }
        })];
      }
    });
  }
  delegateEvents(["click"]);

  // src/components/Widgets/BackToTop.tsx
  var _tmpl$17 = /* @__PURE__ */ template('<button type=button class="fixed safe-right-lg bottom-[calc(max(16px,env(safe-area-inset-bottom,0px))_+_var(--ui-hit-size-lg)_+_var(--ui-space-md))] z-ui inline-flex ui-hit-square-lg items-center justify-center rounded-full border-0 bg-[var(--color-site-elevated)] ehp-color-site-accent shadow-[0_4px_14px_var(--color-shadow-floating)] cursor-pointer [touch-action:none] active:scale-96">'), BACK_TO_TOP_POSITION_KEY = "ehpeek:back-to-top:position";
  function clearBackToTopPosition() {
    GM_deleteValue(BACK_TO_TOP_POSITION_KEY);
  }
  function BackToTop(props) {
    let button2, drag = null, dragged = !1, [visible, setVisible] = createSignal(!1), [position, setPosition] = createSignal(null), positionStyle = () => {
      let current = position();
      return current ? {
        bottom: `${current.bottom}px`,
        right: `${current.right}px`
      } : void 0;
    };
    return onMount(() => {
      let updateVisibility = () => {
        setVisible(window.scrollY > Math.max(320, window.innerHeight * 0.5));
      };
      updateVisibility();
      let savedPosition = GM_getValue(BACK_TO_TOP_POSITION_KEY, null);
      savedPosition && setPosition(savedPosition), window.addEventListener("scroll", updateVisibility, {
        passive: !0
      }), onCleanup(() => window.removeEventListener("scroll", updateVisibility));
    }), createComponent(Show, {
      get when() {
        return visible();
      },
      get children() {
        var _el$ = _tmpl$17();
        _el$.$$click = (event) => {
          if (dragged) {
            event.preventDefault(), dragged = !1;
            return;
          }
          window.scrollTo({
            top: 0,
            behavior: "smooth"
          });
        }, _el$.$$pointerup = (event) => {
          if (!drag || drag.pointerId !== event.pointerId)
            return;
          button2.releasePointerCapture(event.pointerId), drag = null;
          let current = position();
          dragged && current && GM_setValue(BACK_TO_TOP_POSITION_KEY, current);
        }, _el$.$$pointermove = (event) => {
          if (!drag || drag.pointerId !== event.pointerId)
            return;
          let dx = event.clientX - drag.x, dy = event.clientY - drag.y;
          dragged || (dragged = Math.hypot(dx, dy) > 4), setPosition(clampPosition({
            bottom: drag.bottom - dy,
            right: drag.right - dx
          }, button2));
        }, _el$.$$pointerdown = (event) => {
          let rect = button2.getBoundingClientRect();
          dragged = !1, drag = {
            bottom: window.innerHeight - rect.bottom,
            pointerId: event.pointerId,
            right: window.innerWidth - rect.right,
            x: event.clientX,
            y: event.clientY
          }, button2.setPointerCapture(event.pointerId);
        };
        var _ref$ = button2;
        return typeof _ref$ == "function" ? use(_ref$, _el$) : button2 = _el$, insert(_el$, createComponent(Icon2, {
          name: "arrow-up",
          size: "var(--ui-icon-size-lg)"
        })), createRenderEffect((_p$) => {
          var _v$ = {
            "!right-auto safe-left-lg": props.leftHanded() && position() === null
          }, _v$2 = positionStyle();
          return _p$.e = classList(_el$, _v$, _p$.e), _p$.t = style(_el$, _v$2, _p$.t), _p$;
        }, {
          e: void 0,
          t: void 0
        }), _el$;
      }
    });
  }
  function clampPosition(position, button2) {
    return {
      bottom: Math.min(Math.max(0, position.bottom), Math.max(0, window.innerHeight - button2.offsetHeight)),
      right: Math.min(Math.max(0, position.right), Math.max(0, window.innerWidth - button2.offsetWidth))
    };
  }
  delegateEvents(["pointerdown", "pointermove", "pointerup", "click"]);

  // src/components/Widgets/ExternalDom.tsx
  function DomNode2(props) {
    let Component = createMemo(() => props.node?.Component);
    return createComponent(Show, {
      get when() {
        return Component();
      },
      children: (Current) => createComponent(Dynamic, {
        get component() {
          return Current();
        }
      })
    });
  }
  function DomNodes(props) {
    return createComponent(For, {
      get each() {
        return props.nodes;
      },
      children: (node) => {
        let Component = node.Component;
        return createComponent(Component, {});
      }
    });
  }

  // src/components/TouchUI/GalleryInfoPanel.tsx
  var _tmpl$18 = /* @__PURE__ */ template("<div>"), _tmpl$210 = /* @__PURE__ */ template('<button type=button class="relative inline-flex self-center max-w-full overflow-hidden p-0 border-0 bg-transparent cursor-pointer select-none [touch-action:manipulation] [-webkit-tap-highlight-color:transparent] focus-visible:ui-rounded-xs focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--color-site-accent)] focus-visible:outline-offset-3px"><span class="flex gap-1px pointer-events-none text-[var(--color-muted)] opacity-40"aria-hidden=true></span><span aria-hidden=true>'), _tmpl$37 = /* @__PURE__ */ template('<div class="text-center textsize-md font-700"aria-live=polite>'), _tmpl$47 = /* @__PURE__ */ template('<div class="grid grid-cols-2 ui-gap-sm ui-pt-md border-0 border-t border-t-[var(--color-site-border-subtle)]"><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"></button><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$56 = /* @__PURE__ */ template('<section class="flex box-border w-full flex-col ui-mb-sm ehp-color-site-text font-sans"><div class="relative grid min-h-[clamp(130px,21vh,170px)] ui-pt-sm safe-pr-sm ui-pb-xl safe-pl-sm ehp-color-site-surface ehp-color-site-text"><div><div class="flex self-stretch min-w-0 flex-col items-start ui-gap-xs pt-1px"><div class="flex min-w-0 w-full flex-none flex-col ui-gap-xs items-start pb-2px"><div class="line-clamp-4 flex-none overflow-hidden [font-size:var(--ui-font-size-lg)] font-400 leading-[1.16] text-left break-anywhere"></div><div class="line-clamp-3 flex-none overflow-hidden opacity-82 textsize-md leading-[1.2] text-left break-anywhere"></div></div><div class="flex min-w-0 max-w-full flex-none items-center ui-gap-sm"><a class="box-border flex-none whitespace-nowrap ui-rounded-xs border border-solid ui-py-xs ui-px-xs text-center textsize-md font-700 leading-[1.1] uppercase no-underline hover:no-underline active:no-underline"></a></div></div></div></div><div class="relative z-1 grid grid-cols-[1fr_1fr] min-h-[var(--ui-control-size-xl)] mt--8px safe-mr-sm safe-ml-sm overflow-visible ui-rounded-xs bg-[var(--color-site-elevated)] shadow-[0_2px_10px_var(--color-shadow-panel)]"><div class="contents [direction:ltr]"></div><div class="flex min-w-0 border-0 border-solid border-[var(--color-site-page)] [direction:ltr]"></div></div><div class="flex flex-col ui-gap-sm ui-pt-md safe-pr-sm ui-pb-sm safe-pl-sm ehp-color-site-page ehp-color-site-text"><div class="grid grid-cols-[repeat(3,minmax(0,1fr))] ui-gap-y-sm ui-gap-x-sm items-center [font-size:var(--ui-font-size-lg)] leading-[1.2] text-center">'), _tmpl$66 = /* @__PURE__ */ template('<div class="flex self-center justify-self-stretch w-full max-h-full aspect-[2/3] items-center justify-center overflow-hidden rounded-3px">'), _tmpl$75 = /* @__PURE__ */ template('<a class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-82 textsize-md font-700 leading-[1.1] no-underline hover:underline active:underline">'), _tmpl$84 = /* @__PURE__ */ template('<button type=button class="flex w-[65%] max-w-full flex-none self-end flex-col items-end ui-gap-xs mt-auto p-0 border-0 bg-transparent ehp-color-site-text font-inherit text-right cursor-pointer select-none [touch-action:manipulation] [-webkit-tap-highlight-color:transparent] focus-visible:ui-rounded-xs focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--color-site-accent)] focus-visible:outline-offset-3px"><div class="relative inline-flex [&amp;_.ehpeek-icon]:w-[var(--ui-icon-size-lg)] [&amp;_.ehpeek-icon]:h-[var(--ui-icon-size-lg)]"><span class="flex gap-1px text-[var(--color-muted)] opacity-40"aria-hidden=true></span><span aria-hidden=true></span></div><div class="flex items-center justify-end ui-gap-xs text-[var(--color-muted)] [font-size:var(--ui-font-size-lg)] leading-[1.15] whitespace-nowrap"><span aria-live=polite>'), _tmpl$93 = /* @__PURE__ */ template('<span class="flex-none ui-pl-xs border-0 border-l border-[var(--color-site-border-subtle)] opacity-75">'), _tmpl$02 = /* @__PURE__ */ template('<div class="line-clamp-2 min-w-0 overflow-hidden whitespace-normal break-normal">'), _tmpl$19 = /* @__PURE__ */ template('<div class="flex flex-col pt-2px"><button type=button><span></span><span aria-hidden=true></span></button><div class="grid min-w-0 w-full grid-cols-[max-content_minmax(0,1fr)] items-start ui-gap-x-xs ui-gap-y-sm">'), _tmpl$102 = /* @__PURE__ */ template('<div class="absolute top-[calc(var(--ui-control-size-md)+var(--ui-space-sm))] right-0 z-overlay flex w-[min(78vw,calc(var(--ui-control-size-xl)*4))] flex-col overflow-hidden border ehp-color-site-border ui-rounded-sm ehp-color-site-elevated">'), _tmpl$112 = /* @__PURE__ */ template('<div class="relative flex min-w-0 items-center justify-center"><button type=button class="inline-flex w-[var(--ui-control-size-md)] h-[var(--ui-control-size-md)] items-center justify-center border-0 bg-transparent ehp-color-site-text"aria-haspopup=menu>'), _tmpl$122 = /* @__PURE__ */ template('<section class=contents><div class="box-border min-h-[var(--ui-control-size-sm)] whitespace-nowrap ui-rounded-xl bg-[var(--color-site-elevated)] ui-py-xs ui-px-md text-center lowercase ehp-color-site-accent textsize-md font-600"></div><div class="flex flex-wrap ui-gap-xs">'), _tmpl$132 = /* @__PURE__ */ template('<a class="ehpeek-touch-gallery-tag inline-flex flex-none box-border max-w-full min-h-[var(--ui-control-size-sm)] items-center overflow-hidden text-ellipsis whitespace-nowrap appearance-none m-0 py-0 ui-rounded-xl border border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] ui-px-lg ehp-color-site-text font-inherit font-700 textsize-md cursor-pointer select-text no-underline transition-[border-color,background-color,color] duration-120 hover:border-[var(--color-site-border)] hover:bg-[var(--color-site-accent-hover)] hover:ehp-color-site-accent">'), _tmpl$142 = /* @__PURE__ */ template('<div role=dialog aria-modal=true><div class="box-border flex w-full max-w-[calc(var(--ui-control-size-xl)*5.25)] max-h-[calc(100dvh-(var(--ui-space-lg)*2))] flex-col overflow-x-hidden overflow-y-auto overscroll-contain whitespace-nowrap border ehp-color-site-border ui-rounded-md ehp-color-site-elevated shadow-xl"role=menu>'), _tmpl$152 = /* @__PURE__ */ template('<div class="absolute top-full left-0 right-0 z-2 ui-mt-xs max-h-240px overflow-y-auto overscroll-contain ui-rounded-md border ehp-color-site-border ehp-color-site-elevated shadow-xl"role=listbox>'), _tmpl$162 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-sm ehp-color-site-text textsize-md font-600"><span></span><div class=relative><button type=button class="flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-rounded-md border ehp-color-site-border !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text ui-px-md font-inherit text-left textsize-md cursor-pointer"aria-haspopup=listbox><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"></span><span class=flex-none aria-hidden=true>'), _tmpl$172 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-sm ehp-color-site-text textsize-md font-600"><span></span><div class="overflow-hidden ui-rounded-md border ehp-color-site-border"role=radiogroup>'), _tmpl$182 = /* @__PURE__ */ template('<div class="grid grid-cols-2 ui-gap-md"><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default ui-gap-md border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"><span>'), _tmpl$192 = /* @__PURE__ */ template("<button type=button role=menuitem><span>"), _tmpl$20 = /* @__PURE__ */ template("<button type=button role=option><span>"), _tmpl$21 = /* @__PURE__ */ template("<button type=button role=radio><span>"), _tmpl$222 = /* @__PURE__ */ template('<span class="contents [&amp;_*]:!bg-transparent [&amp;_*]:!text-inherit"translate=no>'), _tmpl$232 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-md ui-pt-lg ui-px-lg"><textarea class="box-border min-h-[calc(var(--ui-control-size-xl)*3)] w-full resize-y ui-rounded-md border ehp-color-site-border bg-[var(--color-site-surface)] ui-p-md ehp-color-site-text font-inherit textsize-md leading-[1.4]"></textarea><div class="grid grid-cols-1 ui-gap-md"><button type=button class="min-h-[var(--ui-control-size-md)] ui-rounded-md border border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] font-inherit textsize-md font-700">'), _tmpl$242 = /* @__PURE__ */ template('<div class="relative z-2 min-w-0"><button type=button class="flex min-w-0 w-full h-full ui-hit-min-h-xl flex-col items-center justify-center ui-gap-xs ui-py-md ui-px-lg border-0 bg-transparent ehp-color-site-text text-center uppercase [touch-action:manipulation] [font-size:var(--ui-font-size-lg)] font-700 normal-case"aria-haspopup=menu><span class="block leading-[1.15]"></span><span class="block opacity-78 normal-case"aria-hidden=true>'), _tmpl$252 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left cursor-pointer"><span class="flex-none ehp-color-site-text"aria-hidden=true></span><span>'), _tmpl$262 = /* @__PURE__ */ template('<div class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left">'), _tmpl$272 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left cursor-pointer"><span class="flex-none ehp-color-site-text"aria-hidden=true></span><span></span><span aria-hidden=true>'), RATING_STAR_INDEXES = [0, 1, 2, 3, 4];
  var GALLERY_FAVORITE_ICON_SIZE = "var(--ui-icon-size-lg)";
  function GalleryInfoPanel(props) {
    let source = untrack(() => props.source), rating = source.data.rating, hasCover = source.elems.cover !== null, [ratingValue, setRatingValue] = createSignal(rating?.value ?? 0), [ratingPreview, setRatingPreview] = createSignal(null), [ratingPickerOpen, setRatingPickerOpen] = createSignal(!1), [ratingSubmitted, setRatingSubmitted] = createSignal(rating?.rated ?? !1), [ratingCount] = createSignal(rating?.count ?? ""), [ratingValueLabel] = createSignal(rating?.label ?? ""), initialTagGroups = source.data.tagGroups.map((group) => ({
      ...group,
      tags: group.tags.flatMap(({
        contentSourceIndex,
        ...tag2
      }) => {
        let contentSource = source.elems.tagContents[contentSourceIndex];
        return contentSource ? [{
          ...tag2,
          contentSource
        }] : [];
      })
    })), [tagGroups, setTagGroups] = createSignal(initialTagGroups), [selectedTag, setSelectedTag] = createSignal(null), [tagging, setTagging] = createSignal(!1), ratingPointerType = "", hasNewTag = () => source.elems.newTag !== null, displayedRating = createMemo(() => ratingPreview() ?? ratingValue()), closeRatingPicker = () => {
      setRatingPreview(null), setRatingPickerOpen(!1);
    }, ratingLabel = createMemo(() => {
      let preview = ratingPreview();
      return preview !== null ? `Rate as ${preview.toFixed(1)} stars` : ratingSubmitted() ? `Rated ${ratingValue().toFixed(1)} stars` : ratingValueLabel();
    }), previewRatingFromPointer = (event) => {
      event.pointerType === "mouse" && setRatingPreview(ratingFromPointer(event.clientX, event.currentTarget));
    };
    onMount(() => {
      let stopObservingTags = source.handle.observeGalleryTagGroups(setTagGroups);
      onCleanup(stopObservingTags);
    });
    let submitRating = (value) => {
      if (!rating)
        return !1;
      try {
        return source.handle.submitGalleryRating(value), setRatingValue(value), setRatingPreview(null), setRatingSubmitted(!0), !0;
      } catch (error) {
        return setRatingPreview(null), console.error("[ehpeek]", error), window.alert(error instanceof Error ? error.message : i18n_default.errors.loadFailed), !1;
      }
    }, openTagMenu = (tag2) => {
      try {
        source.handle.openGalleryTagMenu(tag2), setSelectedTag(tag2);
      } catch (error) {
        console.error("[ehpeek] Gallery tag actions failed", error), window.alert(error instanceof Error ? error.message : i18n_default.errors.loadFailed);
      }
    }, closeTagMenu = () => {
      selectedTag() && (source.handle.closeGalleryTagMenu(), setSelectedTag(null));
    }, updateTag = (updatedTag) => {
      setTagGroups((groups) => groups.map((group) => ({
        ...group,
        tags: group.tags.map((tag2) => tag2.url === updatedTag.url ? updatedTag : tag2)
      }))), setSelectedTag((tag2) => tag2?.url === updatedTag.url ? updatedTag : tag2);
    };
    return (() => {
      var _el$ = _tmpl$56(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$5.nextSibling, _el$9 = _el$8.firstChild, _el$0 = _el$2.nextSibling, _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling, _el$11 = _el$0.nextSibling, _el$12 = _el$11.firstChild;
      return className(_el$3, `grid ui-gap-sm items-stretch ${hasCover ? "ehpeek-touch-gallery-summary-has-cover" : "grid-cols-1"}`), insert(_el$3, hasCover && (() => {
        var _el$21 = _tmpl$66();
        return insert(_el$21, createComponent(DomNode2, {
          get node() {
            return source.elems.cover;
          }
        })), _el$21;
      })(), _el$4), insert(_el$6, () => source.data.titleMain), insert(_el$7, () => source.data.titleSub), insert(_el$9, () => source.data.category), insert(_el$8, (() => {
        var _c$ = memo(() => !!source.data.uploader);
        return () => _c$() && (() => {
          var _el$22 = _tmpl$75();
          return insert(_el$22, () => source.data.uploader), createRenderEffect(() => setAttribute(_el$22, "href", source.data.uploaderUrl)), _el$22;
        })();
      })(), null), insert(_el$4, rating && (() => {
        var _el$23 = _tmpl$84(), _el$24 = _el$23.firstChild, _el$25 = _el$24.firstChild, _el$26 = _el$25.nextSibling, _el$27 = _el$24.nextSibling, _el$28 = _el$27.firstChild;
        return _el$23.$$pointerdown = (event) => {
          ratingPointerType = event.pointerType, event.pointerType !== "mouse" && setRatingPreview(null);
        }, _el$23.addEventListener("pointercancel", () => {
          ratingPointerType = "", setRatingPreview(null);
        }), _el$23.addEventListener("blur", () => {
          setRatingPreview(null);
        }), _el$23.$$click = () => {
          let preview = ratingPointerType === "mouse" ? ratingPreview() : null;
          if (ratingPointerType = "", preview !== null) {
            submitRating(preview);
            return;
          }
          setRatingPreview(null), setRatingPickerOpen(!0);
        }, _el$24.addEventListener("pointerleave", () => setRatingPreview(null)), _el$24.$$pointermove = previewRatingFromPointer, _el$24.$$pointerdown = previewRatingFromPointer, insert(_el$25, createComponent(For, {
          each: RATING_STAR_INDEXES,
          children: () => createComponent(Icon2, {
            name: "star"
          })
        })), insert(_el$26, createComponent(For, {
          each: RATING_STAR_INDEXES,
          children: () => createComponent(Icon2, {
            name: "star",
            filled: !0
          })
        })), insert(_el$28, ratingLabel), insert(_el$27, (() => {
          var _c$3 = memo(() => !!ratingCount());
          return () => _c$3() && (() => {
            var _el$29 = _tmpl$93();
            return insert(_el$29, ratingCount), _el$29;
          })();
        })(), null), createRenderEffect((_p$) => {
          var _v$9 = i18n_default.gallery.rate, _v$0 = `absolute top-0 left-0 flex gap-1px overflow-hidden ${ratingSubmitted() ? "text-[var(--color-rating-submitted)]" : "ehp-color-site-accent"}`, _v$1 = `${displayedRating() / 5 * 100}%`;
          return _v$9 !== _p$.e && setAttribute(_el$23, "aria-label", _p$.e = _v$9), _v$0 !== _p$.t && className(_el$26, _p$.t = _v$0), _v$1 !== _p$.a && setStyleProperty(_el$26, "width", _p$.a = _v$1), _p$;
        }, {
          e: void 0,
          t: void 0,
          a: void 0
        }), _el$23;
      })(), null), _el$0.addEventListener("dragstart", (event) => event.preventDefault()), insert(_el$1, createComponent(TouchGalleryFavoriteButton, {
        source
      })), insert(_el$10, () => props.primaryAction), insert(_el$12, createComponent(For, {
        get each() {
          return source.data.summary;
        },
        children: (item) => (() => {
          var _el$30 = _tmpl$02();
          return insert(_el$30, () => item.value), _el$30;
        })()
      }), null), insert(_el$12, createComponent(TouchGalleryActionsMenu, {
        get items() {
          return source.elems.actionItems;
        }
      }), null), insert(_el$11, (() => {
        var _c$2 = memo(() => tagGroups().length > 0);
        return () => _c$2() && (() => {
          var _el$31 = _tmpl$19(), _el$32 = _el$31.firstChild, _el$33 = _el$32.firstChild, _el$34 = _el$33.nextSibling, _el$35 = _el$32.nextSibling;
          return _el$31.addEventListener("dragstart", (event) => event.preventDefault()), _el$32.$$click = () => {
            setTagging((enabled) => !enabled);
          }, insert(_el$33, () => i18n_default.gallery.tagging), insert(_el$35, createComponent(For, {
            get each() {
              return tagGroups();
            },
            children: (group) => createComponent(TouchGalleryTagGroup, {
              group,
              get tagging() {
                return tagging();
              },
              onTagOpen: openTagMenu
            })
          })), createRenderEffect((_p$) => {
            var _v$10 = `inline-flex self-end ui-hit-min-h-xs items-center justify-center ui-gap-sm ui-mb-xs ui-rounded-xl border-0 ui-px-md font-inherit font-700 textsize-sm cursor-pointer transition-[background-color,color] duration-120 ${tagging() ? "bg-[var(--color-site-accent-hover)] ehp-color-site-accent" : "bg-[var(--color-site-surface)] ehp-color-site-text"}`, _v$11 = tagging(), _v$12 = `block flex-none ui-w-md ui-h-md rounded-full ${tagging() ? "bg-[var(--color-state-on)]" : "bg-[var(--color-state-off)]"}`;
            return _v$10 !== _p$.e && className(_el$32, _p$.e = _v$10), _v$11 !== _p$.t && setAttribute(_el$32, "aria-pressed", _p$.t = _v$11), _v$12 !== _p$.a && className(_el$34, _p$.a = _v$12), _p$;
          }, {
            e: void 0,
            t: void 0,
            a: void 0
          }), _el$31;
        })();
      })(), null), insert(_el$11, createComponent(Show, {
        get when() {
          return hasNewTag();
        },
        get children() {
          var _el$13 = _tmpl$18();
          return insert(_el$13, createComponent(TouchGalleryNewTag, {
            source
          })), createRenderEffect(() => className(_el$13, tagging() ? "block" : "hidden")), _el$13;
        }
      }), null), insert(_el$, createComponent(TouchGalleryTagMenu, {
        source,
        get tag() {
          return selectedTag();
        },
        onClose: closeTagMenu,
        onTagUpdated: updateTag
      }), null), insert(_el$, createComponent(Show, {
        get when() {
          return ratingPickerOpen();
        },
        get children() {
          return createComponent(Dialog, {
            bodyClass: "flex flex-col ui-gap-lg ui-pt-lg ui-px-lg",
            get label() {
              return i18n_default.gallery.rate;
            },
            onClose: closeRatingPicker,
            get title() {
              return i18n_default.gallery.rate;
            },
            variant: "site",
            width: "md",
            get children() {
              return [(() => {
                var _el$14 = _tmpl$210(), _el$15 = _el$14.firstChild, _el$16 = _el$15.nextSibling;
                return _el$14.$$click = (event) => {
                  setRatingPreview(ratingFromPointer(event.clientX, event.currentTarget));
                }, insert(_el$15, createComponent(For, {
                  each: RATING_STAR_INDEXES,
                  children: () => createComponent(Icon2, {
                    name: "star",
                    size: "var(--ui-control-size-lg)"
                  })
                })), insert(_el$16, createComponent(For, {
                  each: RATING_STAR_INDEXES,
                  children: () => createComponent(Icon2, {
                    name: "star",
                    size: "var(--ui-control-size-lg)",
                    filled: !0
                  })
                })), createRenderEffect((_p$) => {
                  var _v$ = i18n_default.gallery.rateWithStars.replace("{rating}", displayedRating().toFixed(1)), _v$2 = `absolute top-0 left-0 flex gap-1px overflow-hidden pointer-events-none ${ratingSubmitted() || ratingPreview() !== null ? "text-[var(--color-rating-submitted)]" : "ehp-color-site-accent"}`, _v$3 = `${displayedRating() / 5 * 100}%`;
                  return _v$ !== _p$.e && setAttribute(_el$14, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && className(_el$16, _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$16, "width", _p$.a = _v$3), _p$;
                }, {
                  e: void 0,
                  t: void 0,
                  a: void 0
                }), _el$14;
              })(), (() => {
                var _el$17 = _tmpl$37();
                return insert(_el$17, ratingLabel), _el$17;
              })(), (() => {
                var _el$18 = _tmpl$47(), _el$19 = _el$18.firstChild, _el$20 = _el$19.nextSibling;
                return _el$19.$$click = () => {
                  let value = ratingPreview();
                  value !== null && submitRating(value) && setRatingPickerOpen(!1);
                }, insert(_el$19, () => i18n_default.common.actions.submit), _el$20.$$click = closeRatingPicker, insert(_el$20, () => i18n_default.common.actions.close), createRenderEffect(() => _el$19.disabled = ratingPreview() === null), _el$18;
              })()];
            }
          });
        }
      }), null), createRenderEffect((_p$) => {
        var _v$4 = source.data.categoryUrl ?? void 0, _v$5 = source.data.categoryAppearance, _v$6 = {
          "[direction:rtl]": props.leftHandedControls()
        }, _v$7 = !!props.leftHandedControls(), _v$8 = !props.leftHandedControls();
        return _v$4 !== _p$.e && setAttribute(_el$9, "href", _p$.e = _v$4), _p$.t = style(_el$9, _v$5, _p$.t), _p$.a = classList(_el$0, _v$6, _p$.a), _v$7 !== _p$.o && _el$10.classList.toggle("border-r-6", _p$.o = _v$7), _v$8 !== _p$.i && _el$10.classList.toggle("border-l-6", _p$.i = _v$8), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0
      }), _el$;
    })();
  }
  function TouchGalleryActionsMenu(props) {
    let [open, setOpen] = createSignal(!1), root;
    return onMount(() => {
      let onClick = (event) => {
        event.target instanceof Element && root.contains(event.target) || setOpen(!1);
      };
      document.addEventListener("click", onClick), onCleanup(() => {
        document.removeEventListener("click", onClick);
      });
    }), (() => {
      var _el$36 = _tmpl$112(), _el$37 = _el$36.firstChild, _ref$ = root;
      return typeof _ref$ == "function" ? use(_ref$, _el$36) : root = _el$36, _el$37.$$click = (event) => {
        event.stopPropagation(), setOpen((value) => !value);
      }, insert(_el$37, createComponent(Icon2, {
        name: "menu"
      })), insert(_el$36, createComponent(Show, {
        get when() {
          return open();
        },
        get children() {
          var _el$38 = _tmpl$102();
          return insert(_el$38, createComponent(DomNodes, {
            get nodes() {
              return props.items;
            }
          })), _el$38;
        }
      }), null), createRenderEffect(() => setAttribute(_el$37, "aria-expanded", open())), _el$36;
    })();
  }
  function TouchGalleryTagGroup(props) {
    return (() => {
      var _el$39 = _tmpl$122(), _el$40 = _el$39.firstChild, _el$41 = _el$40.nextSibling;
      return insert(_el$40, () => props.group.namespace), _el$41.$$click = (event) => {
        if (!props.tagging || event.defaultPrevented || event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
          return;
        let href = (event.target instanceof Element ? event.target.closest("a.ehpeek-touch-gallery-tag") : null)?.getAttribute("href"), tag2 = props.group.tags.find((candidate) => candidate.url === href);
        tag2 && (event.preventDefault(), props.onTagOpen(tag2));
      }, insert(_el$41, createComponent(For, {
        get each() {
          return props.group.tags;
        },
        children: (tag2) => createComponent(TouchGalleryTag, {
          tag: tag2
        })
      })), _el$39;
    })();
  }
  function TouchGalleryTag(props) {
    return (() => {
      var _el$42 = _tmpl$132();
      return setAttribute(_el$42, "draggable", !1), insert(_el$42, createComponent(TouchGalleryTagContent, {
        get tag() {
          return props.tag;
        }
      })), createRenderEffect((_p$) => {
        var _v$13 = props.tag.url, _v$14 = props.tag.appearance.backgroundColor, _v$15 = props.tag.appearance.borderColor, _v$16 = props.tag.appearance.color, _v$17 = props.tag.label;
        return _v$13 !== _p$.e && setAttribute(_el$42, "href", _p$.e = _v$13), _v$14 !== _p$.t && setStyleProperty(_el$42, "background-color", _p$.t = _v$14), _v$15 !== _p$.a && setStyleProperty(_el$42, "border-color", _p$.a = _v$15), _v$16 !== _p$.o && setStyleProperty(_el$42, "color", _p$.o = _v$16), _v$17 !== _p$.i && setAttribute(_el$42, "aria-label", _p$.i = _v$17), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0
      }), _el$42;
    })();
  }
  function TouchGalleryTagMenu(props) {
    let onClose = untrack(() => props.onClose), onTagUpdated = untrack(() => props.onTagUpdated), [favoriteDialogOpen, setFavoriteDialogOpen] = createSignal(!1), tagSets = state.gallery.myTagSets.reload(), [selectedTagSet, setSelectedTagSet] = createSignal(tagSets.find((option2) => option2.selected)?.value ?? tagSets[0]?.value ?? "1"), [collectionOpen, setCollectionOpen] = createSignal(!1), [tagMode, setTagMode] = createSignal("marked"), [updating, setUpdating] = createSignal(!1), [favoriteTag, setFavoriteTag] = createSignal(null), closeFavoriteTagDialog = () => {
      setCollectionOpen(!1), setFavoriteDialogOpen(!1);
    };
    onMount(() => {
      let onKeyDown = (event) => {
        event.key === "Escape" && props.tag && props.onClose();
      };
      document.addEventListener("keydown", onKeyDown), onCleanup(() => {
        document.removeEventListener("keydown", onKeyDown);
      });
    });
    let updateFavoriteTag = async (tag2) => {
      if (!updating()) {
        setUpdating(!0);
        try {
          let myTagsPage = tag2.myTag ? await props.source.handle.removeFavoriteTag(tag2) : await props.source.handle.submitFavoriteTag(tag2, selectedTagSet(), tagMode()), updateAppearance = (appearance) => onTagUpdated({
            ...tag2,
            appearance: appearance ? {
              ...tag2.appearance,
              backgroundColor: appearance.backgroundColor,
              color: appearance.color
            } : {
              backgroundColor: "",
              borderColor: "",
              color: ""
            },
            myTag: appearance ? {
              id: appearance.id,
              tagSet: appearance.tagSet
            } : null
          });
          updateAppearance(myTagsPage.appearances.find((item) => item.name === tag2.name)), setFavoriteDialogOpen(!1), onClose(), refreshMyTags(myTagsPage).then((appearances) => {
            appearances && updateAppearance(appearances.find((item) => item.name === tag2.name));
          });
        } catch (error) {
          console.error("[ehpeek]", error), window.alert(error instanceof Error ? error.message : i18n_default.errors.loadFailed);
        } finally {
          setUpdating(!1);
        }
      }
    };
    return [(() => {
      var _el$43 = _tmpl$142(), _el$44 = _el$43.firstChild;
      return _el$43.$$click = (event) => {
        event.target === event.currentTarget && props.onClose();
      }, _el$44.$$click = () => {
        updating() || props.onClose();
      }, insert(_el$44, createComponent(Show, {
        get when() {
          return !updating();
        },
        get fallback() {
          return createComponent(WelcomeIcon, {
            embedded: !0,
            get label() {
              return i18n_default.common.status.loading;
            },
            showIcon: !1
          });
        },
        get children() {
          return [createComponent(DomNode2, {
            get node() {
              return props.source.elems.tagMenuAction;
            }
          }), createComponent(Show, {
            get when() {
              return state.gallery.myTags.value;
            },
            get children() {
              return createComponent(Show, {
                get when() {
                  return props.tag;
                },
                children: (tag2) => createComponent(Show, {
                  get when() {
                    return !tag2().myTag;
                  },
                  get fallback() {
                    return (() => {
                      var _el$61 = _tmpl$192(), _el$62 = _el$61.firstChild;
                      return _el$61.$$click = (event) => {
                        event.stopPropagation(), updateFavoriteTag(tag2());
                      }, insert(_el$61, createComponent(Icon2, {
                        name: "heart",
                        filled: !0
                      }), _el$62), insert(_el$62, () => i18n_default.gallery.removeFavoriteTag), createRenderEffect(() => className(_el$61, sharedApply.galleryTagMenuItem)), _el$61;
                    })();
                  },
                  get children() {
                    var _el$59 = _tmpl$192(), _el$60 = _el$59.firstChild;
                    return _el$59.$$click = () => {
                      setFavoriteTag(tag2()), setCollectionOpen(!1), setFavoriteDialogOpen(!0);
                    }, insert(_el$59, createComponent(Icon2, {
                      name: "heart"
                    }), _el$60), insert(_el$60, () => i18n_default.gallery.favoriteTag), createRenderEffect(() => className(_el$59, sharedApply.galleryTagMenuItem)), _el$59;
                  }
                })
              });
            }
          })];
        }
      })), createRenderEffect((_p$) => {
        var _v$18 = `fixed inset-0 z-overlay flex items-center justify-center ui-p-lg bg-black/65 transition-opacity duration-120 ${props.tag ? "visible opacity-100" : "invisible opacity-0 pointer-events-none"}`, _v$19 = !props.tag, _v$20 = props.tag?.label ?? "";
        return _v$18 !== _p$.e && className(_el$43, _p$.e = _v$18), _v$19 !== _p$.t && setAttribute(_el$43, "aria-hidden", _p$.t = _v$19), _v$20 !== _p$.a && setAttribute(_el$43, "aria-label", _p$.a = _v$20), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$43;
    })(), createComponent(Show, {
      get when() {
        return favoriteDialogOpen();
      },
      get children() {
        return createComponent(Dialog, {
          bodyClass: "flex flex-col ui-gap-lg ui-pt-lg ui-px-lg",
          get label() {
            return i18n_default.gallery.favoriteTag;
          },
          onClose: closeFavoriteTagDialog,
          get title() {
            return i18n_default.gallery.favoriteTag;
          },
          variant: "site",
          width: "md",
          get children() {
            return createComponent(Show, {
              get when() {
                return !updating();
              },
              get fallback() {
                return createComponent(WelcomeIcon, {
                  embedded: !0,
                  get label() {
                    return i18n_default.common.status.loading;
                  },
                  showIcon: !1
                });
              },
              get children() {
                return [(() => {
                  var _el$45 = _tmpl$162(), _el$46 = _el$45.firstChild, _el$47 = _el$46.nextSibling, _el$48 = _el$47.firstChild, _el$49 = _el$48.firstChild, _el$50 = _el$49.nextSibling;
                  return insert(_el$46, () => i18n_default.gallery.tagCollection), _el$48.$$click = () => setCollectionOpen((open) => !open), insert(_el$49, () => tagSets.find((option2) => option2.value === selectedTagSet())?.label ?? selectedTagSet()), insert(_el$50, () => collectionOpen() ? "▴" : "▾"), insert(_el$47, createComponent(Show, {
                    get when() {
                      return collectionOpen();
                    },
                    get children() {
                      var _el$51 = _tmpl$152();
                      return insert(_el$51, createComponent(For, {
                        each: tagSets,
                        children: (option2) => (() => {
                          var _el$63 = _tmpl$20(), _el$64 = _el$63.firstChild;
                          return _el$63.$$click = () => {
                            setSelectedTagSet(option2.value), setCollectionOpen(!1);
                          }, insert(_el$64, () => option2.label), insert(_el$63, createComponent(Show, {
                            get when() {
                              return selectedTagSet() === option2.value;
                            },
                            get children() {
                              return createComponent(Icon2, {
                                name: "check"
                              });
                            }
                          }), null), createRenderEffect((_p$) => {
                            var _v$21 = `flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-px-md border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b ehp-color-site-text font-inherit text-left textsize-md cursor-pointer ${selectedTagSet() === option2.value ? "bg-[var(--color-site-item-hover)] font-700" : "!bg-transparent hover:!bg-[var(--color-site-item-hover)]"}`, _v$22 = selectedTagSet() === option2.value;
                            return _v$21 !== _p$.e && className(_el$63, _p$.e = _v$21), _v$22 !== _p$.t && setAttribute(_el$63, "aria-selected", _p$.t = _v$22), _p$;
                          }, {
                            e: void 0,
                            t: void 0
                          }), _el$63;
                        })()
                      })), createRenderEffect(() => setAttribute(_el$51, "aria-label", i18n_default.gallery.tagCollection)), _el$51;
                    }
                  }), null), createRenderEffect(() => setAttribute(_el$48, "aria-expanded", collectionOpen())), _el$45;
                })(), (() => {
                  var _el$52 = _tmpl$172(), _el$53 = _el$52.firstChild, _el$54 = _el$53.nextSibling;
                  return insert(_el$53, () => i18n_default.gallery.tagBehavior), insert(_el$54, createComponent(For, {
                    get each() {
                      return [["marked", i18n_default.gallery.markTag], ["watched", i18n_default.gallery.watchTag], ["hidden", i18n_default.gallery.hideTag]];
                    },
                    children: ([value, label]) => (() => {
                      var _el$65 = _tmpl$21(), _el$66 = _el$65.firstChild;
                      return _el$65.$$click = () => setTagMode(value), insert(_el$66, label), insert(_el$65, createComponent(Show, {
                        get when() {
                          return tagMode() === value;
                        },
                        get children() {
                          return createComponent(Icon2, {
                            name: "check"
                          });
                        }
                      }), null), createRenderEffect((_p$) => {
                        var _v$23 = `flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-px-md border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b ehp-color-site-text font-inherit text-left textsize-md cursor-pointer ${tagMode() === value ? "bg-[var(--color-site-item-hover)] font-700" : "!bg-transparent hover:!bg-[var(--color-site-item-hover)]"}`, _v$24 = tagMode() === value;
                        return _v$23 !== _p$.e && className(_el$65, _p$.e = _v$23), _v$24 !== _p$.t && setAttribute(_el$65, "aria-checked", _p$.t = _v$24), _p$;
                      }, {
                        e: void 0,
                        t: void 0
                      }), _el$65;
                    })()
                  })), createRenderEffect(() => setAttribute(_el$54, "aria-label", i18n_default.gallery.tagBehavior)), _el$52;
                })(), (() => {
                  var _el$55 = _tmpl$182(), _el$56 = _el$55.firstChild, _el$57 = _el$56.nextSibling, _el$58 = _el$57.firstChild;
                  return _el$56.$$click = closeFavoriteTagDialog, insert(_el$56, () => i18n_default.common.actions.close), _el$57.$$click = () => {
                    let tag2 = favoriteTag();
                    tag2 && updateFavoriteTag(tag2);
                  }, insert(_el$57, createComponent(Icon2, {
                    name: "heart"
                  }), _el$58), insert(_el$58, () => i18n_default.common.actions.confirm), _el$55;
                })()];
              }
            });
          }
        });
      }
    })];
  }
  function TouchGalleryNewTag(props) {
    return createComponent(DomNode2, {
      get node() {
        return props.source.elems.newTag;
      }
    });
  }
  function TouchGalleryTagContent(props) {
    let host;
    return onMount(() => {
      onCleanup(props.tag.contentSource.mirrorContentTo(host));
    }), (() => {
      var _el$67 = _tmpl$222(), _ref$2 = host;
      return typeof _ref$2 == "function" ? use(_ref$2, _el$67) : host = _el$67, _el$67;
    })();
  }
  function TouchGalleryFavoriteButton(props) {
    let [favorite, setFavorite] = createSignal(untrack(() => ({
      ...props.source.data.favorite
    }))), [open, setOpen] = createSignal(!1), [loadingState, setLoadingState] = createSignal("idle"), [options, setOptions] = createSignal([]), [note, setNote] = createSignal(""), [noteDraft, setNoteDraft] = createSignal(""), [editingNote, setEditingNote] = createSignal(!1), favorited = () => favorite().favorited, closeMenu = () => {
      noteDraft() !== note() && !window.confirm(i18n_default.gallery.discardFavoriteNote) || (setNoteDraft(note()), setEditingNote(!1), setOpen(!1));
    }, openMenu = async () => {
      let currentFavorite = favorite();
      if (currentFavorite.actionUrl) {
        setOpen(!0), setEditingNote(!1), setNote(""), setNoteDraft(""), setLoadingState("loading");
        try {
          let dialog = await props.source.handle.loadGalleryFavoriteDialog(currentFavorite.actionUrl, currentFavorite.favorited);
          setOptions(dialog.options), setNote(dialog.note), setNoteDraft(dialog.note), setLoadingState("idle");
        } catch (error) {
          console.error("[ehpeek]", error), setLoadingState("failed");
        }
      }
    }, updateFavorite = async (option2) => {
      let actionUrl = favorite().actionUrl;
      if (!(!actionUrl || loadingState() === "loading")) {
        setLoadingState("loading");
        try {
          await props.source.handle.updateGalleryFavorite(actionUrl, option2.value, noteDraft()), setFavorite({
            ...favorite(),
            color: option2.color,
            favorited: option2.value !== "favdel",
            label: option2.value === "favdel" ? i18n_default.gallery.notFavorited : option2.label
          }), setNote(noteDraft()), setLoadingState("idle"), setOpen(!1);
        } catch (error) {
          console.error("[ehpeek]", error), setLoadingState("failed");
        }
      }
    };
    return (() => {
      var _el$68 = _tmpl$242(), _el$69 = _el$68.firstChild, _el$70 = _el$69.firstChild, _el$71 = _el$70.nextSibling;
      return _el$69.$$click = (event) => {
        event.stopPropagation(), open() ? closeMenu() : openMenu();
      }, insert(_el$70, () => favorite().label), insert(_el$71, createComponent(Icon2, {
        name: "heart",
        size: "var(--ui-icon-size-lg)",
        get filled() {
          return favorited();
        }
      })), insert(_el$68, createComponent(Show, {
        get when() {
          return open();
        },
        get children() {
          return createComponent(Dialog, {
            get label() {
              return favorite().label;
            },
            onClose: closeMenu,
            get title() {
              return memo(() => !!editingNote())() ? i18n_default.gallery.editFavoriteNote : favorite().label;
            },
            variant: "site",
            width: "md",
            get children() {
              return [createComponent(Show, {
                get when() {
                  return loadingState() === "loading";
                },
                get children() {
                  return createComponent(WelcomeIcon, {
                    embedded: !0,
                    get label() {
                      return i18n_default.common.status.loading;
                    },
                    showIcon: !1
                  });
                }
              }), createComponent(Show, {
                get when() {
                  return loadingState() === "failed";
                },
                get children() {
                  return createComponent(TouchGalleryFavoriteStatus, {
                    get text() {
                      return i18n_default.common.status.failed;
                    }
                  });
                }
              }), createComponent(Show, {
                get when() {
                  return loadingState() === "idle";
                },
                get children() {
                  return createComponent(Show, {
                    get when() {
                      return editingNote();
                    },
                    get fallback() {
                      return [createComponent(For, {
                        get each() {
                          return options().filter((option2) => option2.value !== "favdel");
                        },
                        children: (option2) => createComponent(TouchGalleryFavoriteOption, {
                          option: option2,
                          onSelect: () => {
                            updateFavorite(option2);
                          }
                        })
                      }), (() => {
                        var _el$76 = _tmpl$252(), _el$77 = _el$76.firstChild, _el$78 = _el$77.nextSibling;
                        return _el$76.$$click = () => setEditingNote(!0), insert(_el$77, createComponent(Icon2, {
                          name: "edit",
                          size: GALLERY_FAVORITE_ICON_SIZE
                        })), insert(_el$78, () => i18n_default.gallery.editFavoriteNote), _el$76;
                      })(), createComponent(For, {
                        get each() {
                          return options().filter((option2) => option2.value === "favdel");
                        },
                        children: (option2) => createComponent(TouchGalleryFavoriteOption, {
                          option: option2,
                          onSelect: () => {
                            updateFavorite(option2);
                          }
                        })
                      })];
                    },
                    get children() {
                      var _el$72 = _tmpl$232(), _el$73 = _el$72.firstChild, _el$74 = _el$73.nextSibling, _el$75 = _el$74.firstChild;
                      return _el$73.$$input = (event) => setNoteDraft(event.currentTarget.value), _el$75.$$click = () => setEditingNote(!1), insert(_el$75, () => i18n_default.common.actions.confirm), createRenderEffect(() => _el$73.value = noteDraft()), _el$72;
                    }
                  });
                }
              })];
            }
          });
        }
      }), null), createRenderEffect((_p$) => {
        var _v$25 = favorite().color ?? void 0, _v$26 = open();
        return _v$25 !== _p$.e && setStyleProperty(_el$69, "color", _p$.e = _v$25), _v$26 !== _p$.t && setAttribute(_el$69, "aria-expanded", _p$.t = _v$26), _p$;
      }, {
        e: void 0,
        t: void 0
      }), _el$68;
    })();
  }
  function TouchGalleryFavoriteStatus(props) {
    return (() => {
      var _el$79 = _tmpl$262();
      return insert(_el$79, () => props.text), _el$79;
    })();
  }
  function TouchGalleryFavoriteOption(props) {
    return (() => {
      var _el$80 = _tmpl$272(), _el$81 = _el$80.firstChild, _el$82 = _el$81.nextSibling, _el$83 = _el$82.nextSibling;
      return _el$80.$$click = (event) => {
        event.stopPropagation(), props.onSelect();
      }, insert(_el$81, createComponent(Icon2, {
        name: "heart",
        size: GALLERY_FAVORITE_ICON_SIZE,
        get filled() {
          return props.option.value !== "favdel";
        }
      })), insert(_el$82, () => props.option.label), insert(_el$83, createComponent(Icon2, {
        name: "check",
        size: "var(--ui-icon-size-sm)"
      })), createRenderEffect((_p$) => {
        var _v$27 = props.option.selected, _v$28 = props.option.color ?? void 0, _v$29 = `ml-auto flex-none ehp-color-site-text ${props.option.selected ? "visible" : "invisible"}`, _v$30 = props.option.color ?? void 0;
        return _v$27 !== _p$.e && setAttribute(_el$80, "aria-pressed", _p$.e = _v$27), _v$28 !== _p$.t && setStyleProperty(_el$81, "color", _p$.t = _v$28), _v$29 !== _p$.a && className(_el$83, _p$.a = _v$29), _v$30 !== _p$.o && setStyleProperty(_el$83, "color", _p$.o = _v$30), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0
      }), _el$80;
    })();
  }
  function ratingFromPointer(clientX, element) {
    let rect = element.getBoundingClientRect(), progress = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    return Math.max(0.5, Math.ceil(progress * 10) / 2);
  }
  delegateEvents(["click", "pointerdown", "pointermove", "input"]);

  // src/components/TouchUI/FavoritesPanel.tsx
  var _tmpl$30 = /* @__PURE__ */ template('<div class="border-0 border-t border-t-[var(--color-site-border-subtle)]">'), _tmpl$211 = /* @__PURE__ */ template('<div class="box-border w-full min-w-0 overflow-hidden ui-rounded-xs border ehp-color-site-border bg-[var(--color-site-elevated)]"><button type=button class="flex box-border w-full ui-hit-min-h-lg items-center justify-between ui-gap-sm ui-px-sm ui-py-xs ui-rounded-xs border-0 !bg-transparent ehp-color-site-text text-left textsize-sm font-700 font-inherit cursor-pointer hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)]"><span class="flex min-w-0 items-center ui-gap-sm overflow-hidden"><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"> [<!>]</span></span><span class="flex w-[var(--ui-icon-size-md)] h-[var(--ui-icon-size-md)] flex-none items-center justify-center leading-none"aria-hidden=true>'), _tmpl$38 = /* @__PURE__ */ template('<button type=button><span class="flex min-w-0 items-center ui-gap-sm"><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"> [<!>]'), _tmpl$48 = /* @__PURE__ */ template('<span class="block h-15px w-15px flex-none bg-no-repeat"aria-hidden=true>');
  function FavoritesCategorySelect(props) {
    let container, [open, setOpen] = createSignal(!1), selected = () => props.source.data.favoritesCategory?.categories.find((category) => category.selected) ?? props.source.data.favoritesCategory?.categories[0] ?? null;
    return onMount(() => {
      let closeOnOutsidePointer = (event) => {
        event.target instanceof Node && !container.contains(event.target) && setOpen(!1);
      };
      document.addEventListener("pointerdown", closeOnOutsidePointer, !0), onCleanup(() => document.removeEventListener("pointerdown", closeOnOutsidePointer, !0));
    }), (() => {
      var _el$ = _tmpl$211(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$7 = _el$5.nextSibling, _el$6 = _el$7.nextSibling, _el$8 = _el$3.nextSibling, _ref$ = container;
      return typeof _ref$ == "function" ? use(_ref$, _el$) : container = _el$, _el$2.$$click = () => setOpen((value) => !value), insert(_el$3, () => categoryIndicator(selected()?.appearance), _el$4), insert(_el$4, () => selected()?.label, _el$5), insert(_el$4, () => selected()?.count, _el$7), insert(_el$8, () => open() ? "−" : "+"), insert(_el$, createComponent(Show, {
        get when() {
          return open();
        },
        get children() {
          var _el$9 = _tmpl$30();
          return insert(_el$9, createComponent(For, {
            get each() {
              return props.source.data.favoritesCategory?.categories;
            },
            children: (category, index) => (() => {
              var _el$0 = _tmpl$38(), _el$1 = _el$0.firstChild, _el$10 = _el$1.firstChild, _el$11 = _el$10.firstChild, _el$13 = _el$11.nextSibling, _el$12 = _el$13.nextSibling;
              return _el$0.$$click = () => props.source.handle.activateFavoriteCategory(index()), insert(_el$1, () => categoryIndicator(category.appearance), _el$10), insert(_el$10, () => category.label, _el$11), insert(_el$10, () => category.count, _el$13), createRenderEffect(() => className(_el$0, `flex box-border w-full ui-hit-min-h-lg items-center ui-px-sm ui-py-xs border-0 border-b ehp-color-site-border-subtle-b last:border-b-0 text-left textsize-sm font-inherit no-underline cursor-pointer ${category.selected ? "bg-[var(--color-site-accent-hover)] ehp-color-site-accent font-700" : "!bg-transparent ehp-color-site-text hover:!bg-[var(--color-site-item-hover)]"}`)), _el$0;
            })()
          })), _el$9;
        }
      }), null), createRenderEffect(() => setAttribute(_el$2, "aria-expanded", open())), _el$;
    })();
  }
  function categoryIndicator(appearance) {
    return (() => {
      var _el$14 = _tmpl$48();
      return createRenderEffect((_$p) => style(_el$14, appearance ? {
        "background-image": appearance.backgroundImage,
        "background-position": appearance.backgroundPosition,
        "background-size": appearance.backgroundSize
      } : void 0, _$p)), _el$14;
    })();
  }
  delegateEvents(["click"]);

  // src/components/TouchUI/SearchPanel.tsx
  var _tmpl$31 = /* @__PURE__ */ template('<section class="ehpeek-touch-search-panel box-border flex w-[calc(100%_-_(var(--ui-space-sm)*2))] max-w-960px flex-col ui-gap-sm mx-auto ui-mb-sm ui-p-sm border ehp-color-site-border ui-rounded-sm ehp-color-site-surface ehp-color-site-text shadow-[0_8px_24px_var(--color-shadow-panel)] font-sans">'), _tmpl$212 = /* @__PURE__ */ template('<button type=button class="appearance-none inline-flex ui-hit-min-h-sm items-center ui-px-md border-0 ui-rounded-sm bg-transparent ehp-color-site-accent text-left textsize-md font-700 font-inherit leading-[1.2] no-underline cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-accent-hover)]">'), _tmpl$39 = /* @__PURE__ */ template("<button>");
  var TOUCH_SEARCH_ACTION_CLASS = "appearance-none inline-flex box-border w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center p-0 ui-rounded-sm border-0 bg-transparent cursor-pointer transition-[background-color,transform] duration-120 [touch-action:manipulation] active:scale-96 active:bg-[var(--color-site-item-hover)] [--ehpeek-touch-search-icon-size:var(--ui-icon-size-lg)]";
  function TouchSearchPanel(props) {
    return (() => {
      var _el$ = _tmpl$31();
      return insert(_el$, createComponent(DomNode2, {
        get node() {
          return props.source.elems.searchBox;
        }
      }), null), insert(_el$, createComponent(DomNode2, {
        get node() {
          return props.source.elems.fileSearch;
        }
      }), null), insert(_el$, () => props.after, null), _el$;
    })();
  }
  function TouchSearchCategoryToggle(props) {
    let [open, setOpen] = createSignal(!1);
    return createEffect(() => props.source.handle.updateCategoryVisibility(open())), createComponent(ToggleButton, {
      get expanded() {
        return open();
      },
      get label() {
        return i18n_default.search.categories;
      },
      onClick: () => setOpen((value) => !value)
    });
  }
  function TouchSearchOptionToggle(props) {
    let [open, setOpen] = createSignal(!1);
    return createComponent(ToggleButton, {
      get expanded() {
        return open();
      },
      get label() {
        return i18n_default.search[props.option];
      },
      onClick: () => {
        props.option === "advancedOptions" ? props.source.handle.toggleAdvancedOptions() : props.source.handle.toggleFileSearch(), setOpen((value) => !value);
      }
    });
  }
  function ToggleButton(props) {
    return (() => {
      var _el$2 = _tmpl$212();
      return _el$2.$$click = () => props.onClick(), insert(_el$2, () => props.label), createRenderEffect(() => setAttribute(_el$2, "aria-expanded", props.expanded)), _el$2;
    })();
  }
  function TouchSearchAction(props) {
    let source = untrack(() => props.source), search2 = untrack(() => props.action === "search"), label = search2 ? source.data.searchLabel : source.data.clearLabel ?? "";
    return (() => {
      var _el$3 = _tmpl$39();
      return _el$3.$$click = (event) => {
        event.preventDefault(), search2 ? source.handle.activateSearch() : source.handle.clearSearchText();
      }, setAttribute(_el$3, "type", search2 ? "submit" : "button"), setAttribute(_el$3, "aria-label", label), setAttribute(_el$3, "title", label), insert(_el$3, createComponent(Icon2, {
        name: search2 ? "search" : "close",
        size: "var(--ehpeek-touch-search-icon-size)"
      })), createRenderEffect(() => className(_el$3, search2 ? `${TOUCH_SEARCH_ACTION_CLASS} z-1 ${source.data.hasClear ? "col-start-3" : "col-start-2"} row-start-1 ehp-color-site-accent` : `${TOUCH_SEARCH_ACTION_CLASS} z-1 col-start-2 row-start-1 ehp-color-site-text`)), _el$3;
    })();
  }
  delegateEvents(["click"]);

  // src/components/TouchUI/TopBar.tsx
  var _tmpl$40 = /* @__PURE__ */ template('<div class="absolute top-[calc(100%+var(--ui-space-xs))] left-0 z-overlay flex ui-gap-xs ui-p-xs overflow-hidden border ehp-color-site-border ui-rounded-sm ehp-color-site-elevated"role=menu><button type=button class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]"></button><button type=button class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]"><span>'), _tmpl$213 = /* @__PURE__ */ template('<div class=relative><button type=button class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]"aria-haspopup=menu>'), _tmpl$310 = /* @__PURE__ */ template('<button type=button class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]">'), _tmpl$49 = /* @__PURE__ */ template('<div class="absolute top-[calc(100%+var(--ui-space-xs))] right-0 z-overlay flex w-max min-w-[calc(var(--ui-control-size-xl)*2.25)] max-w-[calc(100vw-var(--ui-space-md))] flex-col overflow-hidden border ehp-color-site-border ui-rounded-sm ehp-color-site-elevated">'), _tmpl$57 = /* @__PURE__ */ template('<nav class="relative z-ui flex box-border w-full h-[var(--ui-control-size-xl)] items-center justify-between safe-px-md ehp-color-site-surface ehp-color-site-text font-sans"><div class="flex items-center ui-gap-xs"><a class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)] [--ehpeek-touch-top-bar-project-icon-size:var(--ui-control-size-sm)]"></a></div><div class="flex items-center ui-gap-xs"><a class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]"></a><a class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]"></a><button type=button class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]">'), _tmpl$67 = /* @__PURE__ */ template('<a class="inline-flex w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center ui-rounded-md border-0 bg-transparent ehp-color-site-text no-underline cursor-pointer hover:bg-[var(--color-site-item-hover)] [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]">'), TOUCH_TOP_BAR_ICON_SIZE = "var(--ehpeek-touch-top-bar-icon-size)", TOUCH_TOP_BAR_PROJECT_ICON_SIZE = "var(--ehpeek-touch-top-bar-project-icon-size)", TOUCH_TOP_BAR_SINGLE_COLUMN_ICON_SIZE = "calc(var(--ehpeek-touch-top-bar-icon-size) * 1.1)";
  function TouchTopBarUiMenu(props) {
    let [open, setOpen] = createSignal(!1), root;
    return onMount(() => {
      let onClick = (event) => {
        event.target instanceof Element && root.contains(event.target) || setOpen(!1);
      };
      document.addEventListener("click", onClick), onCleanup(() => {
        document.removeEventListener("click", onClick);
      });
    }), (() => {
      var _el$ = _tmpl$213(), _el$2 = _el$.firstChild, _ref$ = root;
      return typeof _ref$ == "function" ? use(_ref$, _el$) : root = _el$, _el$2.$$click = (event) => {
        event.stopPropagation(), setOpen((value) => !value);
      }, insert(_el$2, createComponent(Icon2, {
        name: "palette",
        size: TOUCH_TOP_BAR_ICON_SIZE,
        strokeWidth: 1.75
      })), insert(_el$, createComponent(Show, {
        get when() {
          return open();
        },
        get children() {
          var _el$3 = _tmpl$40(), _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.firstChild;
          return _el$4.$$click = () => props.uiScale.onChange(nextUiScale(props.uiScale.value())), insert(_el$4, createComponent(Icon2, {
            name: "viewport",
            size: TOUCH_TOP_BAR_ICON_SIZE
          })), _el$5.$$click = () => props.leftHandedControls.onChange(!props.leftHandedControls.enabled()), insert(_el$6, createComponent(Icon2, {
            name: "hand",
            size: TOUCH_TOP_BAR_ICON_SIZE
          })), insert(_el$3, createComponent(Show, {
            get when() {
              return props.columns;
            },
            children: (columns) => (() => {
              var _el$7 = _tmpl$310();
              return _el$7.$$click = () => columns().onChange(!columns().enabled()), insert(_el$7, createComponent(Icon2, {
                name: "pages",
                get size() {
                  return columns().enabled() ? TOUCH_TOP_BAR_ICON_SIZE : TOUCH_TOP_BAR_SINGLE_COLUMN_ICON_SIZE;
                }
              })), createRenderEffect((_p$) => {
                var _v$1 = i18n_default.settings.columnsLabel, _v$10 = columns().enabled(), _v$11 = i18n_default.settings.columnsLabel;
                return _v$1 !== _p$.e && setAttribute(_el$7, "aria-label", _p$.e = _v$1), _v$10 !== _p$.t && setAttribute(_el$7, "aria-pressed", _p$.t = _v$10), _v$11 !== _p$.a && setAttribute(_el$7, "title", _p$.a = _v$11), _p$;
              }, {
                e: void 0,
                t: void 0,
                a: void 0
              }), _el$7;
            })()
          }), null), createRenderEffect((_p$) => {
            var _v$ = {
              "!left-auto right-0 flex-row-reverse": props.leftHandedControls.enabled()
            }, _v$2 = `${i18n_default.settings.uiScaleLabel}: ${uiScaleLevel(props.uiScale.value())}`, _v$3 = `${i18n_default.settings.uiScaleLabel}: ${uiScaleLevel(props.uiScale.value())}`, _v$4 = i18n_default.settings.leftHandedControlsLabel, _v$5 = props.leftHandedControls.enabled(), _v$6 = i18n_default.settings.leftHandedControlsLabel, _v$7 = !!props.leftHandedControls.enabled();
            return _p$.e = classList(_el$3, _v$, _p$.e), _v$2 !== _p$.t && setAttribute(_el$4, "aria-label", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$4, "title", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$5, "aria-label", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$5, "aria-pressed", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$5, "title", _p$.n = _v$6), _v$7 !== _p$.s && _el$6.classList.toggle("-scale-x-100", _p$.s = _v$7), _p$;
          }, {
            e: void 0,
            t: void 0,
            a: void 0,
            o: void 0,
            i: void 0,
            n: void 0,
            s: void 0
          }), _el$3;
        }
      }), null), createRenderEffect((_p$) => {
        var _v$8 = i18n_default.settings.uiControlsLabel, _v$9 = open(), _v$0 = i18n_default.settings.uiControlsLabel;
        return _v$8 !== _p$.e && setAttribute(_el$2, "aria-label", _p$.e = _v$8), _v$9 !== _p$.t && setAttribute(_el$2, "aria-expanded", _p$.t = _v$9), _v$0 !== _p$.a && setAttribute(_el$2, "title", _p$.a = _v$0), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$;
    })();
  }
  function TouchTopBarMenu(props) {
    let [open, setOpen] = createSignal(!1), root;
    return onMount(() => {
      let onClick = (event) => {
        event.target instanceof Element && root.contains(event.target) || setOpen(!1);
      };
      document.addEventListener("click", onClick), onCleanup(() => {
        document.removeEventListener("click", onClick);
      });
    }), (() => {
      var _el$8 = _tmpl$213(), _el$9 = _el$8.firstChild, _ref$2 = root;
      return typeof _ref$2 == "function" ? use(_ref$2, _el$8) : root = _el$8, _el$9.$$click = (event) => {
        event.stopPropagation(), setOpen((value) => !value);
      }, insert(_el$9, createComponent(Icon2, {
        name: "menu",
        size: TOUCH_TOP_BAR_ICON_SIZE
      })), insert(_el$8, createComponent(Show, {
        get when() {
          return open();
        },
        get children() {
          var _el$0 = _tmpl$49();
          return insert(_el$0, createComponent(For, {
            get each() {
              return props.navItems;
            },
            children: (item) => {
              let Component = item.Component;
              return createComponent(Component, {});
            }
          })), createRenderEffect((_$p) => classList(_el$0, {
            "!right-auto left-0": props.leftHanded()
          }, _$p)), _el$0;
        }
      }), null), createRenderEffect(() => setAttribute(_el$9, "aria-expanded", open())), _el$8;
    })();
  }
  function TouchTopBar(props) {
    return (() => {
      var _el$1 = _tmpl$57(), _el$10 = _el$1.firstChild, _el$11 = _el$10.firstChild, _el$12 = _el$10.nextSibling, _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, _el$15 = _el$14.nextSibling;
      return insert(_el$11, createComponent(Icon2, {
        name: "panda-peek",
        size: TOUCH_TOP_BAR_PROJECT_ICON_SIZE,
        strokeWidth: 1.8
      })), insert(_el$10, createComponent(TouchTopBarUiMenu, {
        get leftHandedControls() {
          return props.leftHandedControls;
        },
        get uiScale() {
          return props.uiScale;
        },
        get columns() {
          return props.columns;
        }
      }), null), insert(_el$13, createComponent(Icon2, {
        name: "search",
        size: TOUCH_TOP_BAR_ICON_SIZE
      })), insert(_el$14, createComponent(Icon2, {
        name: "heart",
        size: TOUCH_TOP_BAR_ICON_SIZE
      })), insert(_el$12, createComponent(Show, {
        get when() {
          return props.historyHref;
        },
        children: (historyHref) => (() => {
          var _el$16 = _tmpl$67();
          return insert(_el$16, createComponent(Icon2, {
            name: "history",
            size: TOUCH_TOP_BAR_ICON_SIZE
          })), createRenderEffect(() => setAttribute(_el$16, "href", historyHref())), _el$16;
        })()
      }), _el$15), _el$15.$$click = (event) => {
        event.stopPropagation(), props.onSettingsMenuOpen();
      }, insert(_el$15, createComponent(Icon2, {
        name: "settings",
        size: TOUCH_TOP_BAR_ICON_SIZE
      })), insert(_el$12, createComponent(TouchTopBarMenu, {
        get leftHanded() {
          return props.leftHandedControls.enabled;
        },
        get navItems() {
          return props.source.elems.navItems;
        }
      }), null), createRenderEffect((_p$) => {
        var _v$12 = !!props.leftHandedControls.enabled(), _v$13 = !!props.leftHandedControls.enabled(), _v$14 = props.source.data.homeHref, _v$15 = !!props.leftHandedControls.enabled(), _v$16 = props.source.data.homeHref, _v$17 = props.source.data.favoritesHref;
        return _v$12 !== _p$.e && _el$1.classList.toggle("flex-row-reverse", _p$.e = _v$12), _v$13 !== _p$.t && _el$10.classList.toggle("flex-row-reverse", _p$.t = _v$13), _v$14 !== _p$.a && setAttribute(_el$11, "href", _p$.a = _v$14), _v$15 !== _p$.o && _el$12.classList.toggle("flex-row-reverse", _p$.o = _v$15), _v$16 !== _p$.i && setAttribute(_el$13, "href", _p$.i = _v$16), _v$17 !== _p$.n && setAttribute(_el$14, "href", _p$.n = _v$17), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0
      }), _el$1;
    })();
  }
  delegateEvents(["click"]);

  // src/state/events/index.ts
  var READY_EVENT = "ehpeek:ready";
  function dispatchReady() {
    document.dispatchEvent(new Event(READY_EVENT));
  }

  // src/eh/dom/styles.css
  var styles_default = `/* Style dynamic EhSyringe suggestions without observing its injected nodes. */
.ehs-injected .eh-syringe-lite-auto-complete-list {
  max-height: 60dvh !important;
  padding-block: var(--ui-space-sm) !important;
}

.ehs-injected .eh-syringe-lite-auto-complete-list .auto-complete-item {
  box-sizing: border-box;
  min-height: var(--ui-hit-size-xl);
  padding: var(--ui-space-sm) var(--ui-space-lg) !important;
  font-size: var(--ui-font-size-lg) !important;
  line-height: 1.25 !important;
}

.ehs-injected .eh-syringe-lite-auto-complete-list .auto-complete-text {
  font-size: inherit !important;
  line-height: inherit !important;
}

/* Keep TouchUI result tables inside the viewport without adding layout wrappers. */
html.ehpeek-constrain-results-to-viewport,
body.ehpeek-constrain-results-to-viewport {
  min-width: 0 !important;
  max-width: 100% !important;
  overflow-x: hidden !important;
}

.ehpeek-constrain-results-to-viewport .ido,
.ehpeek-constrain-results-to-viewport .itg {
  box-sizing: border-box;
  min-width: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
}

.ehpeek-expand-favorites-search {
  box-sizing: border-box;
  min-width: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
}

.ehpeek-constrain-favorites-navigation .searchnav {
  box-sizing: border-box;
  max-width: 100% !important;
  overflow-x: auto;
}

.ehpeek-hide-original-favorites-categories {
  display: none !important;
}

.ehpeek-contain-search-results,
.ehpeek-contain-favorites-results {
  box-sizing: border-box;
  min-width: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.ehpeek-contain-search-results.gld {
  overflow-x: clip;
  overflow-y: visible;
}

.ehpeek-enable-search-swipe-input {
  overscroll-behavior-x: contain;
  touch-action: pan-y;
}

.ehpeek-enable-search-swipe-input,
.ehpeek-enable-search-swipe-input * {
  user-select: none !important;
  -webkit-user-select: none !important;
}

/* Compact wide Favorites columns while preserving the original table structure. */
.ehpeek-compact-all-favorites-results {
  table-layout: auto !important;
  width: 100% !important;
  overflow-x: hidden !important;
}

.ehpeek-compact-all-favorites-results > tbody > tr > .gl2e {
  width: auto !important;
  overflow-wrap: anywhere !important;
}

.ehpeek-compact-all-favorites-results .glink {
  white-space: normal !important;
  overflow-wrap: anywhere !important;
}

.ehpeek-compact-all-favorites-results .gl4e table {
  table-layout: fixed !important;
  width: 100% !important;
  max-width: 100% !important;
}

.ehpeek-compact-all-favorites-results .gl4e td {
  min-width: 0 !important;
  overflow-wrap: anywhere !important;
}

.ehpeek-compact-all-favorites-results .gl4e td.tc {
  width: 4em !important;
  white-space: nowrap !important;
}

.ehpeek-compact-all-favorites-results > tbody > tr > .glfe {
  width: 1% !important;
  white-space: nowrap !important;
}

@media (max-width: 849px) {
  .ehpeek-contain-favorites-results {
    table-layout: auto !important;
    width: 100% !important;
  }

  .ehpeek-contain-favorites-results > tbody > tr > .gl2e {
    width: auto !important;
    overflow-wrap: anywhere !important;
  }

  .ehpeek-contain-favorites-results .glink {
    white-space: normal !important;
    overflow-wrap: anywhere !important;
  }

  .ehpeek-contain-favorites-results .gl4e table {
    table-layout: fixed !important;
    width: 100% !important;
    max-width: 100% !important;
  }

  .ehpeek-contain-favorites-results .gl4e td {
    min-width: 0 !important;
    overflow-wrap: anywhere !important;
  }

  .ehpeek-contain-favorites-results .gl4e td.tc {
    width: 4em !important;
    white-space: nowrap !important;
  }

  .ehpeek-contain-favorites-results > tbody > tr > .glfe {
    width: 1% !important;
    white-space: nowrap !important;
  }
}

/* Present original Search rows through one shared EhPeek layout state. */
.ehpeek-layout-search-grid {
  display: block !important;
  width: 100% !important;
  table-layout: auto !important;
}

.ehpeek-layout-search-grid > tbody {
  display: block !important;
}

.ehpeek-layout-search-grid.ehpeek-search-result-columns > tbody {
  display: grid !important;
  box-sizing: border-box !important;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  min-width: 0 !important;
  width: 100% !important;
  gap: 8px;
}

.ehpeek-layout-search-grid.ehpeek-search-result-columns > tbody > tr {
  box-sizing: border-box !important;
  height: 100%;
  min-width: 0 !important;
  max-width: 100% !important;
}

.ehpeek-layout-search-grid > tbody > tr {
  position: relative !important;
  display: grid !important;
  grid-template-columns: clamp(112px, 34%, 250px) minmax(0, 1fr) !important;
  align-items: center !important;
  column-gap: 0 !important;
  width: 100% !important;
  cursor: pointer !important;
}

.ehpeek-layout-search-grid > tbody > tr:has(> .glfe) {
  grid-template-columns: clamp(112px, 34%, 250px) minmax(0, 1fr) auto !important;
}

.ehpeek-layout-search-grid > tbody > tr.ehpeek-expand-coverless-search-grid {
  grid-template-columns: minmax(0, 1fr) !important;
}

.ehpeek-layout-search-grid > tbody > tr > .gl1e {
  width: auto !important;
}

.ehpeek-layout-search-grid > tbody > tr > .gl2e {
  box-sizing: border-box !important;
  grid-column: auto;
  align-self: stretch !important;
  min-width: 0 !important;
  width: auto !important;
  height: 100% !important;
  padding-left: 0 !important;
}

.ehpeek-layout-search-grid > tbody > tr.ehpeek-expand-coverless-search-grid > .gl2e {
  grid-column: 1 !important;
}

.ehpeek-layout-search-grid > tbody > tr > .glfe {
  width: auto !important;
  margin-left: 6px !important;
}

.ehpeek-layout-search-grid > tbody > tr > .gl1e > div,
.ehpeek-layout-search-grid > tbody > tr > .gl1e img {
  width: 100% !important;
  height: auto !important;
}

.ehpeek-layout-search-grid > tbody > tr.ehpeek-contain-tall-search-grid-cover > .gl1e > div {
  display: flex !important;
  align-items: flex-start !important;
  justify-content: center !important;
  height: min(375px, 55dvh) !important;
}

.ehpeek-layout-search-grid > tbody > tr.ehpeek-contain-tall-search-grid-cover > .gl1e img {
  width: auto !important;
  max-width: 100% !important;
  height: 100% !important;
  object-fit: contain !important;
}

.ehpeek-layout-search-grid .gl4e {
  box-sizing: border-box !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  justify-content: flex-start !important;
  gap: var(--ui-space-md) !important;
  min-height: 0 !important;
  width: 100% !important;
  padding-left: 6px !important;
}

.ehpeek-layout-search-grid .gl4e:has(> .ehpeek-read-history-actions) {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr);
}

.ehpeek-layout-search-grid .gl4e > .ehpeek-read-history-actions {
  position: static !important;
  align-self: end;
  justify-self: stretch;
  width: 100% !important;
}

.ehpeek-layout-search-grid .glink {
  min-height: 0 !important;
  height: auto !important;
  overflow: visible !important;
  overflow-wrap: anywhere !important;
  white-space: normal !important;
  word-break: normal !important;
  text-align: left !important;
  font-size: var(--ui-font-size-md) !important;
  font-weight: 700 !important;
  line-height: 1.35 !important;
}

.ehpeek-layout-search-grid .gl3e {
  position: static !important;
  display: grid !important;
  grid-template-columns: max-content max-content minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: center !important;
  gap: var(--ui-space-xs) var(--ui-space-sm) !important;
  float: none !important;
  min-height: 0 !important;
  width: 100% !important;
  height: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  font-weight: 600 !important;
}

.ehpeek-layout-search-grid .gl3e > * {
  position: static !important;
  min-width: 0 !important;
  width: auto !important;
  height: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  font-size: var(--ui-font-size-sm) !important;
  font-weight: 600 !important;
  line-height: 1.3 !important;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-category {
  grid-column: 1;
  grid-row: 1;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-pages {
  grid-column: 1;
  grid-row: 2;
  justify-self: center;
  font-variant-numeric: tabular-nums;
  font-weight: 700 !important;
  white-space: nowrap;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-posted {
  grid-column: 2;
  grid-row: 1;
  text-align: center !important;
  white-space: nowrap;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-rating {
  grid-column: 2;
  grid-row: 2;
  justify-self: center;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-uploader {
  grid-column: 3;
  grid-row: 1;
  width: 100% !important;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left !important;
  white-space: nowrap;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-download {
  display: flex !important;
  grid-column: 3;
  grid-row: 2;
  align-items: center !important;
  align-self: center;
  justify-self: start;
  height: 16px !important;
  line-height: 0 !important;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-extra {
  grid-column: 1 / -1;
  justify-self: start;
  text-align: left !important;
}

.ehpeek-layout-search-grid .ehpeek-search-meta-extra:has(> p) {
  display: flex !important;
  align-items: center;
  gap: var(--ui-space-xs);
}

.ehpeek-layout-search-grid .ehpeek-search-meta-extra > p {
  margin: 0 !important;
}

.ehpeek-layout-search-grid .gl3e > .ir {
  width: 80px !important;
  height: 16px !important;
  background-repeat: no-repeat !important;
}

.ehpeek-layout-search-grid .gl3e > .gldown {
  width: auto !important;
  height: auto !important;
}

.ehpeek-layout-search-grid .gl3e > :is(.cn, .cs, [class*="ct"]) {
  box-sizing: border-box !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: max(72px, 6em) !important;
  height: max(32px, 2.2em) !important;
  padding: 0 0.6em !important;
}

.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags {
  position: static !important;
  flex: 0 0 auto !important;
  min-height: 0 !important;
  width: 100% !important;
  height: auto !important;
  margin: 0 !important;
  padding: 0 !important;
}

.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags :is(table, tbody, tr) {
  min-height: 0 !important;
  height: auto !important;
  margin: 0 !important;
}

.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags td {
  min-height: 0 !important;
  height: auto !important;
  vertical-align: top !important;
}

.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags :is(.gt, .gtl, .gtw, td.tc) {
  font-size: var(--ui-font-size-sm) !important;
  line-height: 1.2 !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite {
  --ehpeek-lite-cover-width: 23.8095%;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite > tbody > tr {
  aspect-ratio: 3 / 1;
  height: auto !important;
  min-height: 0 !important;
  max-height: none !important;
  overflow: hidden !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr:not(.ehpeek-expand-coverless-search-grid) {
  grid-template-columns:
    var(--ehpeek-lite-cover-width)
    minmax(0, 1fr) !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr:has(> .glfe) {
  grid-template-columns:
    var(--ehpeek-lite-cover-width)
    minmax(0, 1fr)
    auto !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr
  > .gl1e {
  box-sizing: border-box !important;
  height: 100% !important;
  overflow: hidden !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr
  > .gl1e
  > div,
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr
  > .gl1e
  a {
  box-sizing: border-box !important;
  display: flex !important;
  align-items: flex-start !important;
  justify-content: center !important;
  width: 100% !important;
  height: 100% !important;
  overflow: hidden !important;
}

.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
  > tbody
  > tr
  > .gl1e
  img {
  top: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
  height: 100% !important;
  object-fit: contain !important;
  object-position: top center !important;
}

.ehpeek-layout-search-grid-lite > tbody > tr > .gl2e,
.ehpeek-layout-search-grid-lite .gl4e {
  overflow: hidden !important;
}

.ehpeek-layout-search-grid-lite .gl4e {
  gap: var(--ui-space-xs) !important;
  height: 100% !important;
  padding-block: var(--ui-space-xs) !important;
}

.ehpeek-layout-search-grid-lite .glink {
  display: -webkit-box !important;
  overflow: hidden !important;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.ehpeek-layout-search-grid-lite .ehpeek-stack-search-grid-tags {
  display: flex !important;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--ui-space-xs) var(--ui-space-sm) !important;
}

.ehpeek-layout-search-grid-lite
  .ehpeek-stack-search-grid-tags:not(
    :has(:is(.gt, .gtl, .gtw)[style*="background"])
  ) {
  display: none !important;
}

.ehpeek-layout-search-grid-lite
  .ehpeek-stack-search-grid-tags
  :is(table, tbody, tr, td) {
  display: contents !important;
}

.ehpeek-layout-search-grid-lite .ehpeek-stack-search-grid-tags .tc,
.ehpeek-layout-search-grid-lite
  .ehpeek-stack-search-grid-tags
  :is(.gt, .gtl, .gtw) {
  display: none !important;
}

.ehpeek-layout-search-grid-lite
  .ehpeek-stack-search-grid-tags
  :is(.gt, .gtl, .gtw)[style*="background"] {
  display: inline-flex !important;
  align-items: center;
}

.ehpeek-layout-search-grid-lite [data-ehpeek-lite-prefix]::before {
  content: attr(data-ehpeek-lite-prefix) ":";
}

.ehpeek-cover-search-grid-row {
  grid-column: 1 / 3;
  grid-row: 1;
}

/* Reading state remains visual and never changes the original title text. */
.ehpeek-prefix-read-history-label::before {
  box-sizing: border-box;
  content: attr(data-ehpeek-history-label);
  display: inline-flex;
  align-items: center;
  margin-right: var(--ui-space-xs);
  padding: 0;
  border: 0;
  border-radius: 0;
  outline: 0;
  background: transparent;
  box-shadow: none;
  color: var(--color-site-accent);
  vertical-align: middle;
  font-size: var(--ui-font-size-sm);
  font-weight: 700;
  line-height: 1.3;
}

[data-ehpeek-read-history="visited"] {
  --ehpeek-read-history-tint: color-mix(in srgb, var(--color-site-accent) 6%, transparent);
}

[data-ehpeek-read-history="reading"] {
  --ehpeek-read-history-tint: color-mix(in srgb, var(--color-site-accent) 12%, transparent);
}

tr[data-ehpeek-read-history] > td:not(.glfe),
[data-ehpeek-read-history]:not(tr) {
  box-shadow: inset 0 0 0 9999px var(--ehpeek-read-history-tint) !important;
}

/* Style retained Search controls without replacing their original classes. */
.ehpeek-reset-search-box-layout {
  box-sizing: border-box !important;
  min-width: 0 !important;
  width: 100% !important;
  height: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  text-align: left !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-stack-search-form {
  display: flex !important;
  flex-direction: column !important;
  gap: var(--ui-space-sm) !important;
  width: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
}

.ehpeek-overlay-search-actions {
  box-sizing: border-box !important;
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) var(--ui-control-size-xl) !important;
  align-items: start !important;
  gap: 0 !important;
  min-width: 0 !important;
  width: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
}

.ehpeek-overlay-search-actions[data-ehpeek-has-clear="true"] {
  grid-template-columns:
    minmax(0, 1fr)
    repeat(2, var(--ui-control-size-xl)) !important;
}

.ehpeek-expand-search-input {
  appearance: none !important;
  box-sizing: border-box !important;
  grid-column: 1 / -1 !important;
  grid-row: 1 !important;
  min-width: 0 !important;
  width: 100% !important;
  height: var(--ui-control-size-xl) !important;
  margin: 0 !important;
  padding:
    0
    calc(var(--ui-control-size-xl) + var(--ui-space-lg))
    0
    var(--ui-space-md) !important;
  border: 1px solid var(--color-site-border) !important;
  border-radius: var(--ui-radius-sm) !important;
  outline: none !important;
  background: var(--color-site-elevated) !important;
  color: var(--color-site-text) !important;
  font-size: var(--ui-font-size-lg) !important;
  line-height: 1.2 !important;
}

.ehpeek-overlay-search-actions[data-ehpeek-has-clear="true"] .ehpeek-expand-search-input {
  padding-right:
    calc((var(--ui-control-size-xl) * 2) + var(--ui-space-lg)) !important;
}

.ehpeek-expand-search-input:focus {
  border-color: var(--color-site-accent) !important;
  background: var(--color-site-elevated) !important;
  box-shadow: 0 0 0 3px var(--color-site-accent-hover) !important;
}

.ehpeek-hide-original-search-action {
  display: none !important;
}

.ehpeek-layout-search-categories {
  width: 100% !important;
  margin: 0 !important;
  border-collapse: collapse !important;
}

.ehpeek-layout-search-categories[aria-hidden="true"] {
  display: none !important;
}

.ehpeek-layout-search-categories > tbody {
  display: grid !important;
  grid-template-columns:
    repeat(
      auto-fit,
      minmax(min(100%, calc(var(--ui-control-size-xl) * 2)), 1fr)
    ) !important;
  gap: var(--ui-space-xs) !important;
}

.ehpeek-layout-search-categories tr {
  display: contents !important;
}

.ehpeek-layout-search-categories td {
  padding: 0 !important;
}

.ehpeek-layout-search-categories [id^="cat_"] {
  box-sizing: border-box !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  min-width: 0 !important;
  width: 100% !important;
  height: var(--ui-hit-size-sm) !important;
  padding-inline: var(--ui-space-sm) !important;
  border: 1px solid var(--color-site-border) !important;
  border-radius: var(--ui-radius-sm) !important;
  color: #ffffff !important;
  text-align: center !important;
  white-space: nowrap !important;
  font-size: var(--ui-font-size-md) !important;
  font-weight: 700 !important;
  line-height: 1.15 !important;
  box-shadow: 0 2px 6px var(--color-shadow-control) !important;
  cursor: pointer !important;
  user-select: none !important;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 120ms;
}

.ehpeek-layout-search-categories [id^="cat_"]:active {
  opacity: 0.7;
}

.ehpeek-layout-search-categories [id^="cat_"][data-disabled] {
  opacity: 0.4;
}

.ehpeek-wrap-search-options {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  justify-content: flex-start !important;
  gap:
    var(--ui-space-xs)
    var(--ui-space-sm) !important;
  width: 100% !important;
  padding: 0 !important;
  font-size: 0 !important;
}

.ehpeek-wrap-search-options > a {
  appearance: none !important;
  display: inline-flex !important;
  align-items: center !important;
  min-height: var(--ui-hit-size-sm) !important;
  padding-inline: var(--ui-space-md) !important;
  border: 0 !important;
  border-radius: var(--ui-radius-sm) !important;
  background: transparent !important;
  color: var(--color-site-accent) !important;
  text-align: left !important;
  text-decoration: none !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
  font-weight: 700 !important;
  line-height: 1.2 !important;
  cursor: pointer !important;
  touch-action: manipulation;
}

.ehpeek-wrap-search-options > a:active {
  background: var(--color-site-accent-hover) !important;
}

.ehpeek-expand-search-advanced-options {
  box-sizing: border-box !important;
  width: 100% !important;
  padding: 0 !important;
  color: var(--color-site-text) !important;
}

.ehpeek-reset-search-box-layout .searchadv {
  box-sizing: border-box !important;
  width: 100% !important;
  padding-top: var(--ui-space-sm) !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-reset-search-box-layout .searchadv > div,
.ehpeek-expand-file-search .searchadv > div {
  flex-wrap: wrap !important;
  justify-content: flex-start !important;
  gap: var(--ui-space-xs) !important;
}

.ehpeek-reset-search-box-layout .searchadv > div > div,
.ehpeek-expand-file-search .searchadv > div > div {
  padding: var(--ui-space-xs) !important;
}

.ehpeek-expand-file-search {
  box-sizing: border-box !important;
  width: 100% !important;
  margin: 0 !important;
  padding: var(--ui-space-sm) !important;
  border: 1px solid var(--color-site-border) !important;
  border-radius: var(--ui-radius-xs) !important;
  background: var(--color-site-elevated) !important;
  color: var(--color-site-text) !important;
  text-align: left !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-expand-file-search form {
  display: flex !important;
  flex-direction: column !important;
  gap: var(--ui-space-xs) !important;
}

.ehpeek-expand-file-search form > div {
  padding: 0 !important;
}

/* Apply dynamic My Tag colors through variables instead of direct presentation writes. */
.ehpeek-color-my-tag {
  background-color: var(--ehpeek-my-tag-background) !important;
}

.ehpeek-color-my-tag > a {
  color: var(--ehpeek-my-tag-color) !important;
}

.ehpeek-expand-gallery-actions {
  height: auto !important;
  max-height: none !important;
  overflow: visible !important;
}

.ehpeek-fit-gallery-cover {
  display: block;
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin-inline: auto;
  object-fit: contain;
  object-position: center;
}

/* Hide original GalleryInfo content only while the TouchUI panel owns its host. */
.ehpeek-hide-original-gallery-info > :not([data-ehpeek-anchor="gallery-info"]) {
  display: none !important;
}

.ehpeek-layout-gallery-action,
.ehpeek-layout-top-bar-menu-item {
  box-sizing: border-box !important;
  display: block !important;
  position: static !important;
  float: none !important;
  min-height: var(--ui-hit-size-xl) !important;
  width: 100% !important;
  height: auto !important;
  margin: 0 !important;
  padding: var(--ui-space-md) var(--ui-space-lg) !important;
  border: 0 !important;
  border-bottom: 1px solid var(--color-site-border-subtle) !important;
  background: transparent !important;
  color: var(--color-site-text) !important;
  text-align: left !important;
  text-decoration: none !important;
  white-space: normal !important;
  font-size: var(--ui-font-size-md) !important;
  line-height: 1.2 !important;
}

.ehpeek-layout-top-bar-menu-item {
  min-height: var(--ui-control-size-lg) !important;
  padding: var(--ui-space-md) !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-layout-new-tag-form {
  box-sizing: border-box !important;
  display: block !important;
  width: 100% !important;
  padding-top: var(--ui-space-md) !important;
}

.ehpeek-layout-new-tag-form form {
  display: flex !important;
  align-items: center !important;
  gap: var(--ui-space-sm) !important;
  min-width: 0 !important;
  width: 100% !important;
}

.ehpeek-layout-new-tag-form #newtagfield {
  box-sizing: border-box !important;
  flex: 1 1 auto !important;
  min-width: 0 !important;
  height: var(--ui-hit-size-md) !important;
  padding-inline: var(--ui-space-md) !important;
  border: 1px solid var(--color-site-border) !important;
  border-radius: var(--ui-radius-xs) !important;
  outline: none !important;
  background: var(--color-site-surface) !important;
  color: var(--color-site-text) !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-layout-new-tag-form #newtagfield:focus {
  border-color: var(--color-site-accent) !important;
}

.ehpeek-layout-new-tag-form #newtagbutton {
  box-sizing: border-box !important;
  flex: 0 0 auto !important;
  height: var(--ui-hit-size-md) !important;
  padding-inline: var(--ui-space-lg) !important;
  border: 1px solid var(--color-site-accent) !important;
  border-radius: var(--ui-radius-xs) !important;
  background: var(--color-site-accent) !important;
  color: var(--color-background) !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
  font-weight: 700 !important;
  cursor: pointer !important;
}

.ehpeek-layout-gallery-tag-menu {
  box-sizing: border-box !important;
  display: flex !important;
  flex-direction: column !important;
  float: none !important;
  width: 100% !important;
  height: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  font-size: var(--ui-font-size-md) !important;
}

.ehpeek-layout-gallery-tag-menu img {
  display: none !important;
}

.ehpeek-layout-gallery-tag-menu a,
.ehpeek-layout-gallery-tag-menu-item {
  box-sizing: border-box !important;
  display: flex !important;
  align-items: center !important;
  gap: var(--ui-space-md) !important;
  min-height: var(--ui-hit-size-xl) !important;
  width: 100% !important;
  padding: var(--ui-space-md) var(--ui-space-lg) !important;
  border: 0 !important;
  border-bottom: 1px solid var(--color-site-border-subtle) !important;
  background: transparent !important;
  color: var(--color-site-text) !important;
  text-align: left !important;
  text-decoration: none !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
  cursor: pointer !important;
}

.ehpeek-enable-touch-comment-score .c5 {
  white-space: nowrap !important;
}

.ehpeek-enable-touch-comment-score .c7[aria-hidden="true"] {
  display: none !important;
}

.ehpeek-enable-touch-comment-score .c7[aria-hidden="false"] {
  display: block !important;
}

.ehpeek-enable-preview-swipe-input {
  touch-action: pan-y;
  user-select: none;
}

.ehpeek-enable-preview-swipe-input img {
  -webkit-user-drag: none;
}

.ehpeek-hide-original-preview-page-bars :is(.ptt, .ptb, .gpc) {
  display: none !important;
}

.ehpeek-touch-gallery-summary-has-cover {
  grid-template-columns:
    minmax(60px, 38%)
    minmax(0, 1fr);
}

.ehpeek-touch-search-panel {
  container-type: inline-size;
}

/* The root state scopes original Gallery layout overrides to TouchUI pages. */
.ehpeek-touch-gallery-page {
  --touch-gallery-gutter: clamp(16px, 2.5vw, 36px);
}

html.ehpeek-touch-gallery-page,
body.ehpeek-touch-gallery-page {
  min-width: 0 !important;
  overflow-x: hidden !important;
  text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}

html.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root,
body.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root {
  height: 100dvh !important;
  overflow-y: hidden !important;
}

body.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

body.ehpeek-touch-gallery-page {
  box-sizing: border-box;
  padding-left: 0 !important;
  padding-right: 0 !important;
  background: var(--color-site-page) !important;
  font-size: var(--ui-font-size-sm) !important;
  line-height: 1.35 !important;
}

body.ehpeek-touch-gallery-page :is(
  .ehpeek-hide-original-gallery-info,
  .gpc,
  #gdt[class],
  #cdiv,
  .ptt,
  .ptb
) {
  box-sizing: border-box !important;
  width: calc(100% - (var(--touch-gallery-gutter) * 2)) !important;
  max-width: none !important;
  margin-left: auto !important;
  margin-right: auto !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
}

body.ehpeek-touch-gallery-page :is(#gdt[class], .ptt, .ptb) {
  overflow-x: auto !important;
  -webkit-overflow-scrolling: touch;
}

body.ehpeek-touch-gallery-page #gdt[class] {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  align-items: start;
}

body.ehpeek-touch-gallery-page #gdt :is(.gdtm, .gdtl),
body.ehpeek-touch-gallery-page #gdt > div {
  display: flex !important;
  box-sizing: border-box !important;
  min-width: 0 !important;
  align-items: center !important;
  justify-content: center !important;
  justify-self: center;
}

body.ehpeek-touch-gallery-page #gdt a {
  display: flex !important;
  align-items: center;
  justify-content: center;
}

body.ehpeek-touch-gallery-page #cdiv {
  font-size: var(--ui-font-size-md) !important;
  line-height: 1.5 !important;
}

body.ehpeek-touch-gallery-page #cdiv .c6 {
  font-size: var(--ui-font-size-lg) !important;
  line-height: 1.5 !important;
  overflow-wrap: anywhere;
}

body.ehpeek-touch-gallery-page :is(
  #cdiv .c3,
  #cdiv .c4,
  #cdiv .c5,
  #cdiv .c7,
  #formdiv
) {
  font-size: var(--ui-font-size-sm) !important;
  line-height: 1.4 !important;
}

body.ehpeek-touch-gallery-page #postnewcomment {
  display: flex !important;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--ui-space-md);
  margin: var(--ui-space-lg) 0 !important;
  font-size: 0 !important;
}

body.ehpeek-touch-gallery-page #postnewcomment a {
  display: inline-flex !important;
  min-height: var(--ui-hit-size-sm);
  align-items: center;
  padding: var(--ui-space-md) var(--ui-space-lg);
  border: 1px solid var(--color-site-border);
  border-radius: var(--ui-radius-md);
  background: var(--color-site-elevated);
  color: var(--color-site-accent);
  font-size: var(--ui-font-size-md);
  text-decoration: none;
}

body.ehpeek-touch-gallery-page #cdiv form {
  display: flex !important;
  flex-wrap: wrap;
  gap: var(--ui-space-md);
  align-items: center;
}

body.ehpeek-touch-gallery-page :is(#cdiv textarea, #commenttext) {
  display: block !important;
  box-sizing: border-box !important;
  width: 100% !important;
  min-height: calc(var(--ui-control-size-xl) * 2) !important;
  flex: 1 0 100%;
  padding: var(--ui-space-lg) !important;
  border-radius: var(--ui-radius-md) !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
  line-height: 1.5 !important;
}

body.ehpeek-touch-gallery-page #cdiv :is(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="text"],
  select
) {
  box-sizing: border-box !important;
  min-height: var(--ui-hit-size-sm) !important;
  padding: var(--ui-space-md) var(--ui-space-lg) !important;
  border-radius: var(--ui-radius-md) !important;
  font: inherit !important;
  font-size: var(--ui-font-size-md) !important;
}

body.ehpeek-touch-gallery-page #cdiv :is(
  button,
  input[type="button"],
  input[type="submit"]
) {
  flex: 1 1 12em;
  cursor: pointer;
}

body.ehpeek-touch-gallery-page #cdiv input[type="text"] {
  min-width: min(100%, 15em);
}

body.ehpeek-touch-gallery-page :is(
  .ehpeek-hide-original-gallery-info,
  .gpc,
  #gdt[class],
  #cdiv,
  .ptt,
  .ptb
) {
  width: min(
    calc(100% - (var(--touch-gallery-gutter) * 2)),
    90dvh
  ) !important;
}

body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout {
  box-sizing: border-box;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr) auto;
  column-gap: var(--touch-gallery-gutter);
  width: calc(100% - (var(--touch-gallery-gutter) * 2));
  height: calc(100dvh - var(--ui-control-size-xl));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  margin-inline: auto;
  align-items: start;
  overflow: hidden;
}

body.ehpeek-touch-gallery-page :is(
  .ehpeek-touch-gallery-layout-left,
  .ehpeek-touch-gallery-layout-right
) {
  grid-row: 1;
  display: block;
  min-width: 0;
  min-height: 0;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

body.ehpeek-touch-gallery-page :is(
  .ehpeek-touch-gallery-layout-left,
  .ehpeek-touch-gallery-layout-right
)::-webkit-scrollbar {
  display: none;
}

body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout :is(
  .ehpeek-hide-original-gallery-info,
  .gtb,
  .contents,
  .gpc,
  #cdiv,
  .ptt,
  .ptb
) {
  min-width: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
}

body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout #gdt[class] {
  min-width: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
}

body.ehpeek-touch-gallery-page
  .ehpeek-touch-gallery-layout-left
  > .ehpeek-hide-original-gallery-info {
  padding-bottom: 0 !important;
}

body.ehpeek-touch-gallery-page
  .ehpeek-touch-gallery-layout-left
  .ehpeek-touch-gallery {
  margin-bottom: 0;
}

body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout > .dp {
  box-sizing: border-box;
  grid-row: 2;
  grid-column: 1 / -1;
  min-width: 0;
  width: 100%;
}
`;

  // ehpeek-uno-css:ehpeek:uno.css
  var ehpeek_uno_default = `/* layer: preflights */
*,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}
/* layer: shortcuts */
.scrollbar-hidden{scrollbar-width:none;-ms-overflow-style:none;}
.container{width:100%;}
.container\\!{width:100% !important;}
.safe-left-lg{left:max(16px,env(safe-area-inset-left,0px));}
.safe-left-md{left:max(12px,env(safe-area-inset-left,0px));}
.safe-left-sm{left:max(8px,env(safe-area-inset-left,0px));}
.safe-right-lg{right:max(16px,env(safe-area-inset-right,0px));}
.safe-right-md{right:max(12px,env(safe-area-inset-right,0px));}
.safe-right-sm{right:max(8px,env(safe-area-inset-right,0px));}
.safe-top-sm{top:max(8px,env(safe-area-inset-top,0px));}
.z-dialog{z-index:1400;}
.z-overlay{z-index:1100;}
.z-reader{z-index:1200;}
.z-ui{z-index:1000;}
.ui-my-sm{margin-top:var(--ui-space-sm);margin-bottom:var(--ui-space-sm);}
.safe-ml-sm{margin-left:max(8px,env(safe-area-inset-left,0px));}
.safe-mr-sm{margin-right:max(8px,env(safe-area-inset-right,0px));}
.ui-mb-sm{margin-bottom:var(--ui-space-sm);}
.ui-mb-xs{margin-bottom:var(--ui-space-xs);}
.ui-mt-md{margin-top:var(--ui-space-md);}
.ui-mt-sm{margin-top:var(--ui-space-sm);}
.ui-mt-xs{margin-top:var(--ui-space-xs);}
.scrollbar-hidden::-webkit-scrollbar{display:none;}
.min-h-sm{min-height:32px;}
.ui-h-md{height:var(--ui-space-md);}
.ui-h-xl{height:var(--ui-space-xl);}
.ui-hit-h-md{height:var(--ui-hit-size-md);}
.\\!ui-hit-h-sm{height:var(--ui-hit-size-sm) !important;}
.ui-hit-min-h-lg{min-height:var(--ui-hit-size-lg);}
.ui-hit-min-h-md{min-height:var(--ui-hit-size-md);}
.ui-hit-min-h-sm{min-height:var(--ui-hit-size-sm);}
.ui-hit-min-h-xl{min-height:var(--ui-hit-size-xl);}
.ui-hit-min-h-xs{min-height:var(--ui-hit-size-xs);}
.ui-hit-min-w-md{min-width:var(--ui-hit-size-md);}
.ui-hit-square-lg{width:var(--ui-hit-size-lg);height:var(--ui-hit-size-lg);}
.ui-hit-square-xl{width:var(--ui-hit-size-xl);height:var(--ui-hit-size-xl);}
.ui-hit-w-lg{width:var(--ui-hit-size-lg);}
.\\!ui-hit-w-sm{width:var(--ui-hit-size-sm) !important;}
.ui-hit-w-sm{width:var(--ui-hit-size-sm);}
.ui-w-md{width:var(--ui-space-md);}
.ui-w-xl{width:var(--ui-space-xl);}
.gap-sm{gap:8px;}
.ui-gap-lg{gap:var(--ui-space-lg);}
.ui-gap-md{gap:var(--ui-space-md);}
.ui-gap-sm{gap:var(--ui-space-sm);}
.ui-gap-xl{gap:var(--ui-space-xl);}
.ui-gap-xs{gap:var(--ui-space-xs);}
.ui-gap-x-md{column-gap:var(--ui-space-md);}
.ui-gap-x-sm{column-gap:var(--ui-space-sm);}
.ui-gap-x-xs{column-gap:var(--ui-space-xs);}
.ui-gap-y-sm{row-gap:var(--ui-space-sm);}
.ehp-color-site-border{border-color:var(--color-site-border);}
.ehp-color-spinner{border-color:var(--color-border);border-top-color:var(--color-accent);}
.ehp-color-site-border-subtle-b{border-bottom-color:var(--color-site-border-subtle);}
.rounded-sm{border-radius:4px;}
.ui-rounded-lg{border-radius:var(--ui-radius-lg);}
.ui-rounded-md{border-radius:var(--ui-radius-md);}
.ui-rounded-sm{border-radius:var(--ui-radius-sm);}
.ui-rounded-xl{border-radius:var(--ui-radius-xl);}
.ui-rounded-xs{border-radius:var(--ui-radius-xs);}
.focus-visible\\:ui-rounded-xs:focus-visible{border-radius:var(--ui-radius-xs);}
.ehp-color-reader{background-color:var(--color-reader-background);color:var(--color-reader-text);}
.ehp-color-site-elevated{background-color:var(--color-site-elevated);--un-shadow:0 8px 24px var(--un-shadow-color, var(--color-shadow-elevated));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.ehp-color-site-page{background-color:var(--color-site-page);}
.ehp-color-site-surface{background-color:var(--color-site-surface);}
.ui-p-lg{padding:var(--ui-space-lg);}
.ui-p-md{padding:var(--ui-space-md);}
.ui-p-sm{padding:var(--ui-space-sm);}
.ui-p-xl{padding:var(--ui-space-xl);}
.ui-p-xs{padding:var(--ui-space-xs);}
.px-sm{padding-left:8px;padding-right:8px;}
.px-xs{padding-left:4px;padding-right:4px;}
.py-sm{padding-top:8px;padding-bottom:8px;}
.ui-px-lg{padding-left:var(--ui-space-lg);padding-right:var(--ui-space-lg);}
.ui-px-md{padding-left:var(--ui-space-md);padding-right:var(--ui-space-md);}
.\\!ui-px-sm{padding-left:var(--ui-space-sm) !important;padding-right:var(--ui-space-sm) !important;}
.ui-px-sm{padding-left:var(--ui-space-sm);padding-right:var(--ui-space-sm);}
.ui-px-xl{padding-left:var(--ui-space-xl);padding-right:var(--ui-space-xl);}
.ui-px-xs{padding-left:var(--ui-space-xs);padding-right:var(--ui-space-xs);}
.ui-py-lg{padding-top:var(--ui-space-lg);padding-bottom:var(--ui-space-lg);}
.ui-py-md{padding-top:var(--ui-space-md);padding-bottom:var(--ui-space-md);}
.ui-py-sm{padding-top:var(--ui-space-sm);padding-bottom:var(--ui-space-sm);}
.ui-py-xs{padding-top:var(--ui-space-xs);padding-bottom:var(--ui-space-xs);}
.pb-sm{padding-bottom:8px;}
.pr-sm{padding-right:8px;}
.pt-sm{padding-top:8px;}
.safe-pl-sm{padding-left:max(8px,env(safe-area-inset-left,0px));}
.safe-pr-sm{padding-right:max(8px,env(safe-area-inset-right,0px));}
.safe-pt-sm{padding-top:max(8px,env(safe-area-inset-top,0px));}
.safe-px-md{padding-left:max(12px,env(safe-area-inset-left,0px));padding-right:max(12px,env(safe-area-inset-right,0px));}
.ui-pb-lg{padding-bottom:var(--ui-space-lg);}
.ui-pb-md{padding-bottom:var(--ui-space-md);}
.ui-pb-sm{padding-bottom:var(--ui-space-sm);}
.ui-pb-xl{padding-bottom:var(--ui-space-xl);}
.ui-pb-xs{padding-bottom:var(--ui-space-xs);}
.ui-pl-lg{padding-left:var(--ui-space-lg);}
.ui-pl-md{padding-left:var(--ui-space-md);}
.ui-pl-xl{padding-left:var(--ui-space-xl);}
.ui-pl-xs{padding-left:var(--ui-space-xs);}
.ui-pr-sm{padding-right:var(--ui-space-sm);}
.ui-pt-lg{padding-top:var(--ui-space-lg);}
.ui-pt-md{padding-top:var(--ui-space-md);}
.ui-pt-sm{padding-top:var(--ui-space-sm);}
.textsize-lg{font-size:var(--ui-font-size-lg);}
.textsize-md{font-size:var(--ui-font-size-md);}
.textsize-sm{font-size:var(--ui-font-size-sm);}
.textsize-xl{font-size:var(--ui-font-size-xl);}
.textsize-xs{font-size:var(--ui-font-size-xs);}
.ehp-color-site-accent{color:var(--color-site-accent);}
.ehp-color-site-text{color:var(--color-site-text);}
.ehp-color-text{color:var(--color-text);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:ehp-color-site-accent:hover{color:var(--color-site-accent);}
@media (min-width: 640px){
.container{max-width:640px;}
.container\\!{max-width:640px !important;}
}
@media (min-width: 768px){
.container{max-width:768px;}
.container\\!{max-width:768px !important;}
}
@media (min-width: 1024px){
.container{max-width:1024px;}
.container\\!{max-width:1024px !important;}
}
@media (min-width: 1280px){
.container{max-width:1280px;}
.container\\!{max-width:1280px !important;}
}
@media (min-width: 1536px){
.container{max-width:1536px;}
.container\\!{max-width:1536px !important;}
}
/* layer: default */
.\\[--ehpeek-position-bar-thumb-min\\:calc\\(var\\(--ui-control-size-md\\)\\*1\\.5\\)\\]{--ehpeek-position-bar-thumb-min:calc(var(--ui-control-size-md) * 1.5);}
.\\[--ehpeek-touch-search-icon-size\\:var\\(--ui-icon-size-lg\\)\\]{--ehpeek-touch-search-icon-size:var(--ui-icon-size-lg);}
.\\[--ehpeek-touch-top-bar-icon-size\\:var\\(--ui-control-size-xs\\)\\]{--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs);}
.\\[--ehpeek-touch-top-bar-project-icon-size\\:var\\(--ui-control-size-sm\\)\\]{--ehpeek-touch-top-bar-project-icon-size:var(--ui-control-size-sm);}
.\\[--progress-bar-fill\\:0\\%\\]{--progress-bar-fill:0%;}
.\\[--progress-bar-track-direction\\:to_right\\]{--progress-bar-track-direction:to right;}
.\\[--scroll-preview-height\\:100\\%\\]{--scroll-preview-height:100%;}
.\\[--scroll-preview-height\\:55lvh\\]{--scroll-preview-height:55lvh;}
.\\[--scroll-preview-height\\:70svh\\]{--scroll-preview-height:70svh;}
.\\[-webkit-appearance\\:none\\]{-webkit-appearance:none;}
.\\[-webkit-overflow-scrolling\\:touch\\]{-webkit-overflow-scrolling:touch;}
.\\[-webkit-tap-highlight-color\\:transparent\\]{-webkit-tap-highlight-color:transparent;}
.\\[-webkit-user-drag\\:none\\]{-webkit-user-drag:none;}
.\\[accent-color\\:var\\(--color-text\\)\\]{accent-color:var(--color-text);}
.\\[appearance\\:none\\]{appearance:none;}
.\\[bottom\\:var\\(--ui-space-sm\\)\\]{bottom:var(--ui-space-sm);}
.\\[contain\\:inline-size\\]{contain:inline-size;}
.\\[container-type\\:inline-size\\]{container-type:inline-size;}
.\\[container-type\\:size\\]{container-type:size;}
.\\[direction\\:ltr\\]{direction:ltr;}
.\\[direction\\:rtl\\]{direction:rtl;}
.\\[font-size\\:0\\.9em\\]{font-size:0.9em;}
.\\[font-size\\:1\\.05em\\]{font-size:1.05em;}
.\\[font-size\\:min\\(25vw\\,35cqi\\,35cqb\\,180px\\)\\]{font-size:min(25vw,35cqi,35cqb,180px);}
.\\[font-size\\:min\\(var\\(--ui-font-size-xl\\)\\,var\\(--reader-end-font-size\\)\\)\\]{font-size:min(var(--ui-font-size-xl),var(--reader-end-font-size));}
.\\[font-size\\:var\\(--ui-font-size-lg\\)\\]{font-size:var(--ui-font-size-lg);}
.\\[font-size\\:var\\(--ui-font-size-md\\)\\]{font-size:var(--ui-font-size-md);}
.\\[font-size\\:var\\(--ui-font-size-sm\\)\\]{font-size:var(--ui-font-size-sm);}
.\\[font-variant-numeric\\:tabular-nums\\]{font-variant-numeric:tabular-nums;}
.\\[overflow-wrap\\:anywhere\\],
.break-anywhere{overflow-wrap:anywhere;}
.\\[right\\:var\\(--ui-space-sm\\)\\]{right:var(--ui-space-sm);}
.\\[scrollbar-width\\:none\\]{scrollbar-width:none;}
.\\[touch-action\\:manipulation\\]{touch-action:manipulation;}
.\\[touch-action\\:none\\],
.touch-none,
#ehpeek-reader[data-navigation-mode=paged] .\\[\\#ehpeek-reader\\[data-navigation-mode\\=paged\\]_\\&\\]\\:touch-none{touch-action:none;}
.\\[touch-action\\:pan-x_pan-y\\]{touch-action:pan-x pan-y;}
.\\[touch-action\\:pan-x\\]{touch-action:pan-x;}
.\\[touch-action\\:pan-y\\]{touch-action:pan-y;}
.\\[unicode-bidi\\:plaintext\\]{unicode-bidi:plaintext;}
.\\[width\\:min\\(calc\\(100\\%-\\(var\\(--touch-gallery-gutter\\)\\*2\\)\\)\\,90lvh\\)\\]{width:min(calc(100% - (var(--touch-gallery-gutter) * 2)),90lvh);}
.pointer-events-auto{pointer-events:auto;}
.\\[\\&\\[data-open\\=false\\]\\]\\:pointer-events-none[data-open=false],
.pointer-events-none{pointer-events:none;}
.visible{visibility:visible;}
.invisible{visibility:hidden;}
.absolute{position:absolute;}
.fixed{position:fixed;}
.relative{position:relative;}
.static{position:static;}
.inset-0{inset:0;}
.inset-x-0{left:0;right:0;}
.inset-y-0{top:0;bottom:0;}
.\\!left-auto{left:auto !important;}
.\\!right-auto{right:auto !important;}
.bottom-\\[calc\\(12px\\+env\\(safe-area-inset-bottom\\,0px\\)\\)\\]{bottom:calc(12px + env(safe-area-inset-bottom,0px));}
.bottom-\\[calc\\(max\\(16px\\,env\\(safe-area-inset-bottom\\,0px\\)\\)_\\+_var\\(--ui-hit-size-lg\\)_\\+_var\\(--ui-space-md\\)\\)\\]{bottom:calc(max(16px,env(safe-area-inset-bottom,0px)) + var(--ui-hit-size-lg) + var(--ui-space-md));}
.bottom-\\[calc\\(var\\(--ui-control-size-lg\\)\\*2\\+var\\(--ui-font-size-lg\\)\\*2\\.4\\+env\\(safe-area-inset-bottom\\,0px\\)\\)\\]{bottom:calc(var(--ui-control-size-lg) * 2 + var(--ui-font-size-lg) * 2.4 + env(safe-area-inset-bottom,0px));}
.bottom-\\[calc\\(var\\(--ui-control-size-xs\\)\\/2\\)\\]{bottom:calc(var(--ui-control-size-xs) / 2);}
.bottom-0{bottom:0;}
.bottom-4px{bottom:4px;}
.bottom-xs{bottom:0.75rem;}
.left-0{left:0;}
.left-1\\/2{left:50%;}
.left-auto{left:auto;}
.left-xs{left:0.75rem;}
.right-0{right:0;}
.right-4px{right:4px;}
.right-auto{right:auto;}
.right-xs{right:0.75rem;}
.top-\\[calc\\(100\\%\\+var\\(--ui-space-xs\\)\\)\\]{top:calc(100% + var(--ui-space-xs));}
.top-\\[calc\\(10px\\+env\\(safe-area-inset-top\\,0px\\)\\)\\]{top:calc(10px + env(safe-area-inset-top,0px));}
.top-\\[calc\\(var\\(--ui-control-size-md\\)\\+var\\(--ui-space-sm\\)\\)\\]{top:calc(var(--ui-control-size-md) + var(--ui-space-sm));}
.top-0{top:0;}
.top-1\\/2{top:50%;}
.top-full{top:100%;}
.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;}
.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;}
.line-clamp-4{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;line-clamp:4;}
.z-\\[1150\\]{z-index:1150;}
.z-\\[1200\\]{z-index:1200;}
.z-\\[1300\\]{z-index:1300;}
.z-1{z-index:1;}
.z-2{z-index:2;}
.z-3{z-index:3;}
.z-4{z-index:4;}
.grid{display:grid;}
.col-start-1{grid-column-start:1;}
.col-start-2{grid-column-start:2;}
.col-start-3{grid-column-start:3;}
.row-start-1{grid-row-start:1;}
.auto-rows-\\[100\\%\\]{grid-auto-rows:100%;}
.grid-cols-\\[1fr_1fr\\]{grid-template-columns:1fr 1fr;}
.grid-cols-\\[max-content_minmax\\(0\\,1fr\\)\\]{grid-template-columns:max-content minmax(0,1fr);}
.grid-cols-\\[max-content_minmax\\(var\\(--ui-control-size-md\\)\\,1fr\\)_var\\(--ui-control-size-xl\\)_var\\(--ui-control-size-xl\\)\\]{grid-template-columns:max-content minmax(var(--ui-control-size-md),1fr) var(--ui-control-size-xl) var(--ui-control-size-xl);}
.grid-cols-\\[minmax\\(0\\,1\\.6fr\\)_minmax\\(0\\,1fr\\)_minmax\\(0\\,1fr\\)\\]{grid-template-columns:minmax(0,1.6fr) minmax(0,1fr) minmax(0,1fr);}
.grid-cols-\\[minmax\\(0\\,1fr\\)_auto_minmax\\(0\\,1fr\\)\\]{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);}
.grid-cols-\\[repeat\\(3\\,minmax\\(0\\,1fr\\)\\)\\],
.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr));}
.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr));}
.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr));}
.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr));}
.m-0{margin:0;}
.mx-auto{margin-left:auto;margin-right:auto;}
.my-auto{margin-top:auto;margin-bottom:auto;}
.mb-0{margin-bottom:0;}
.mb-10px{margin-bottom:10px;}
.ml-auto{margin-left:auto;}
.mt--8px{margin-top:-8px;}
.mt-0{margin-top:0;}
.mt-2px{margin-top:2px;}
.mt-auto{margin-top:auto;}
.last\\:mb-0:last-child{margin-bottom:0;}
.box-border{box-sizing:border-box;}
.block{display:block;}
.inline-block{display:inline-block;}
.contents{display:contents;}
.\\!hidden{display:none !important;}
.\\[\\&\\:\\:-webkit-scrollbar\\]\\:hidden::-webkit-scrollbar,
.hidden{display:none;}
.aspect-\\[2\\/3\\]{aspect-ratio:2/3;}
.\\!h-\\[var\\(--ui-control-size-lg\\)\\]{height:var(--ui-control-size-lg) !important;}
.\\!min-w-\\[var\\(--ui-control-size-lg\\)\\]{min-width:var(--ui-control-size-lg) !important;}
.\\!min-w-0{min-width:0 !important;}
.\\!w-\\[calc\\(var\\(--ui-control-size-lg\\)\\*2\\)\\]{width:calc(var(--ui-control-size-lg) * 2) !important;}
.\\!w-\\[var\\(--ui-control-size-lg\\)\\]{width:var(--ui-control-size-lg) !important;}
.\\[\\&_\\.ehpeek-icon\\]\\:h-\\[var\\(--ui-icon-size-lg\\)\\] .ehpeek-icon{height:var(--ui-icon-size-lg);}
.\\[\\&_\\.ehpeek-icon\\]\\:w-\\[var\\(--ui-icon-size-lg\\)\\] .ehpeek-icon{width:var(--ui-icon-size-lg);}
.h-\\[2\\.4em\\]{height:2.4em;}
.h-\\[var\\(--reader-frame-height\\)\\]{height:var(--reader-frame-height);}
.h-\\[var\\(--reader-page-height\\)\\]{height:var(--reader-page-height);}
.h-\\[var\\(--scroll-preview-height\\)\\]{height:var(--scroll-preview-height);}
.h-\\[var\\(--ui-control-size-md\\)\\]{height:var(--ui-control-size-md);}
.h-\\[var\\(--ui-control-size-xl\\)\\]{height:var(--ui-control-size-xl);}
.h-\\[var\\(--ui-control-size-xs\\)\\]{height:var(--ui-control-size-xs);}
.h-\\[var\\(--ui-icon-size-md\\)\\]{height:var(--ui-icon-size-md);}
.h-\\[var\\(--ui-icon-size-sm\\)\\]{height:var(--ui-icon-size-sm);}
.h-\\[var\\(--ui-icon-size-xl\\)\\]{height:var(--ui-icon-size-xl);}
.h-108px{height:108px;}
.h-15px{height:15px;}
.h-24px{height:24px;}
.h-6px{height:6px;}
.h-8px{height:8px;}
.h-full{height:100%;}
.h1{height:0.25rem;}
.max-h-\\[60dvh\\]{max-height:60dvh;}
.max-h-\\[calc\\(100dvh-\\(var\\(--ui-space-lg\\)\\*2\\)\\)\\]{max-height:calc(100dvh - (var(--ui-space-lg) * 2));}
.max-h-\\[calc\\(100dvh-16px\\)\\]{max-height:calc(100dvh - 16px);}
.max-h-\\[min\\(calc\\(var\\(--ui-control-size-xl\\)\\*12\\.75\\)\\,calc\\(100dvh_-_var\\(--ui-space-lg\\)_-_var\\(--ui-space-lg\\)\\)\\)\\]{max-height:min(calc(var(--ui-control-size-xl) * 12.75),calc(100dvh - var(--ui-space-lg) - var(--ui-space-lg)));}
.max-h-240px{max-height:240px;}
.max-h-full{max-height:100%;}
.max-h-screen{max-height:100vh;}
.max-w-\\[calc\\(100vw-16px\\)\\]{max-width:calc(100vw - 16px);}
.max-w-\\[calc\\(100vw-20px\\)\\]{max-width:calc(100vw - 20px);}
.max-w-\\[calc\\(100vw-32px\\)\\]{max-width:calc(100vw - 32px);}
.max-w-\\[calc\\(100vw-var\\(--ui-space-md\\)\\)\\]{max-width:calc(100vw - var(--ui-space-md));}
.max-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*5\\.25\\)\\]{max-width:calc(var(--ui-control-size-xl) * 5.25);}
.max-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*7\\.5\\)\\]{max-width:calc(var(--ui-control-size-xl) * 7.5);}
.max-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*9\\.25\\)\\]{max-width:calc(var(--ui-control-size-xl) * 9.25);}
.max-w-\\[min\\(86vw\\,760px\\)\\]{max-width:min(86vw,760px);}
.max-w-960px{max-width:960px;}
.max-w-full{max-width:100%;}
.max-w-screen{max-width:100vw;}
.min-h-\\[calc\\(var\\(--ui-control-size-xl\\)\\*3\\)\\]{min-height:calc(var(--ui-control-size-xl) * 3);}
.min-h-\\[clamp\\(130px\\,21vh\\,170px\\)\\]{min-height:clamp(130px,21vh,170px);}
.min-h-\\[var\\(--ui-control-size-lg\\)\\]{min-height:var(--ui-control-size-lg);}
.min-h-\\[var\\(--ui-control-size-md\\)\\]{min-height:var(--ui-control-size-md);}
.min-h-\\[var\\(--ui-control-size-sm\\)\\]{min-height:var(--ui-control-size-sm);}
.min-h-\\[var\\(--ui-control-size-xl\\)\\]{min-height:var(--ui-control-size-xl);}
.min-h-\\[var\\(--ui-control-size-xs\\)\\]{min-height:var(--ui-control-size-xs);}
.min-h-0{min-height:0;}
.min-h-full{min-height:100%;}
.min-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*2\\.25\\)\\]{min-width:calc(var(--ui-control-size-xl) * 2.25);}
.min-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*2\\)\\]{min-width:calc(var(--ui-control-size-xl) * 2);}
.min-w-0{min-width:0;}
.min-w-full{min-width:100%;}
.w-\\[65\\%\\]{width:65%;}
.w-\\[calc\\(100\\%_-_\\(var\\(--ui-space-sm\\)\\*2\\)\\)\\]{width:calc(100% - (var(--ui-space-sm) * 2));}
.w-\\[calc\\(var\\(--ui-control-size-lg\\)\\*4\\+var\\(--ui-space-md\\)\\*4\\)\\]{width:calc(var(--ui-control-size-lg) * 4 + var(--ui-space-md) * 4);}
.w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*6\\)\\]{width:calc(var(--ui-control-size-xl) * 6);}
.w-\\[min\\(680px\\,calc\\(100vw-24px\\)\\)\\]{width:min(680px,calc(100vw - 24px));}
.w-\\[min\\(78vw\\,calc\\(var\\(--ui-control-size-xl\\)\\*4\\)\\)\\]{width:min(78vw,calc(var(--ui-control-size-xl) * 4));}
.w-\\[min\\(calc\\(100\\%-32px\\)\\,1212px\\)\\]{width:min(calc(100% - 32px),1212px);}
.w-\\[var\\(--reader-frame-width\\)\\]{width:var(--reader-frame-width);}
.w-\\[var\\(--reader-page-width\\)\\]{width:var(--reader-page-width);}
.w-\\[var\\(--ui-control-size-md\\)\\]{width:var(--ui-control-size-md);}
.w-\\[var\\(--ui-control-size-sm\\)\\]{width:var(--ui-control-size-sm);}
.w-\\[var\\(--ui-control-size-xl\\)\\]{width:var(--ui-control-size-xl);}
.w-\\[var\\(--ui-control-size-xs\\)\\]{width:var(--ui-control-size-xs);}
.w-\\[var\\(--ui-icon-size-md\\)\\]{width:var(--ui-icon-size-md);}
.w-\\[var\\(--ui-icon-size-sm\\)\\]{width:var(--ui-icon-size-sm);}
.w-\\[var\\(--ui-icon-size-xl\\)\\]{width:var(--ui-icon-size-xl);}
.w-15px{width:15px;}
.w-16px{width:16px;}
.w-24px{width:24px;}
.w-32px{width:32px;}
.w-42px{width:42px;}
.w-6px{width:6px;}
.w-8px{width:8px;}
.w-auto{width:auto;}
.w-full{width:100%;}
.w-max{width:max-content;}
.flex{display:flex;}
.inline-flex{display:inline-flex;}
.flex-\\[0_0_100\\%\\]{flex:0 0 100%;}
.flex-\\[0_0_var\\(--reader-page-width\\)\\]{flex:0 0 var(--reader-page-width);}
.flex-1{flex:1 1 0%;}
.flex-none{flex:none;}
.flex-row{flex-direction:row;}
.flex-row-reverse{flex-direction:row-reverse;}
.flex-col{flex-direction:column;}
.flex-wrap{flex-wrap:wrap;}
.table{display:table;}
.border-collapse{border-collapse:collapse;}
.border-separate{border-collapse:separate;}
.border-spacing-\\[var\\(--ui-space-xs\\)\\]{--un-border-spacing-x:var(--ui-space-xs);--un-border-spacing-y:var(--ui-space-xs);border-spacing:var(--un-border-spacing-x) var(--un-border-spacing-y);}
.origin-center{transform-origin:center;}
.-translate-x-1\\/2{--un-translate-x:-50%;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.-translate-y-1\\/2{--un-translate-y:-50%;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.\\[\\&\\[data-open\\=false\\]\\]\\:translate-y-\\[calc\\(100\\%\\+16px\\)\\][data-open=false]{--un-translate-y:calc(100% + 16px);transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.active\\:scale-96:active{--un-scale-x:0.96;--un-scale-y:0.96;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.active\\:scale-98:active{--un-scale-x:0.98;--un-scale-y:0.98;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.-scale-x-100{--un-scale-x:-1;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}
.animate-spin{animation:spin 1s linear infinite;}
.cursor-default{cursor:default;}
.disabled\\:cursor-default:disabled{cursor:default;}
.cursor-pointer{cursor:pointer;}
.cursor-grab{cursor:grab;}
.\\[\\&\\[data-dragging\\=true\\]\\]\\:cursor-grabbing[data-dragging=true]{cursor:grabbing;}
.active\\:cursor-grabbing:active{cursor:grabbing;}
.touch-pan-y{--un-pan-y:pan-y;touch-action:var(--un-pan-x) var(--un-pan-y) var(--un-pinch-zoom);}
.select-text{-webkit-user-select:text;user-select:text;}
.\\[\\&\\[data-dragging\\=true\\]\\]\\:select-none[data-dragging=true],
.select-none,
#ehpeek-reader[data-navigation-mode=paged] .\\[\\#ehpeek-reader\\[data-navigation-mode\\=paged\\]_\\&\\]\\:select-none{-webkit-user-select:none;user-select:none;}
.resize-y{resize:vertical;}
.resize{resize:both;}
.appearance-none{-webkit-appearance:none;appearance:none;}
.items-start{align-items:flex-start;}
.items-end{align-items:flex-end;}
.items-center{align-items:center;}
.items-stretch{align-items:stretch;}
.self-end{align-self:flex-end;}
.self-center{align-self:center;}
.self-stretch{align-self:stretch;}
.justify-start{justify-content:flex-start;}
.justify-end{justify-content:flex-end;}
.justify-center{justify-content:center;}
.justify-between{justify-content:space-between;}
.justify-self-start{justify-self:start;}
.justify-self-end{justify-self:end;}
.justify-self-stretch{justify-self:stretch;}
.gap-1px{gap:1px;}
.gap-3px{gap:3px;}
.gap-x-3px{column-gap:3px;}
.overflow-auto{overflow:auto;}
.overflow-hidden,
#ehpeek-reader[data-navigation-mode=paged] .\\[\\#ehpeek-reader\\[data-navigation-mode\\=paged\\]_\\&\\]\\:overflow-hidden{overflow:hidden;}
.overflow-visible{overflow:visible;}
.overflow-x-auto{overflow-x:auto;}
.overflow-x-hidden{overflow-x:hidden;}
.overflow-y-auto{overflow-y:auto;}
.overflow-y-hidden{overflow-y:hidden;}
.overscroll-auto{overscroll-behavior:auto;}
.overscroll-contain{overscroll-behavior:contain;}
.overscroll-x-contain{overscroll-behavior-x:contain;}
.scroll-auto{scroll-behavior:auto;}
.text-ellipsis{text-overflow:ellipsis;}
.whitespace-normal{white-space:normal;}
.whitespace-nowrap{white-space:nowrap;}
.whitespace-pre-line{white-space:pre-line;}
.break-normal{overflow-wrap:normal;word-break:normal;}
.\\!border{border-width:1px !important;}
.border{border-width:1px;}
.border-0{border-width:0px;}
.border-2px{border-width:2px;}
.border-4,
.border-4px{border-width:4px;}
.border-6{border-width:6px;}
.border-y{border-top-width:1px;border-bottom-width:1px;}
.\\[\\&\\>\\:last-child\\]\\:\\!border-b-0>:last-child{border-bottom-width:0px !important;}
.border-b{border-bottom-width:1px;}
.border-l{border-left-width:1px;}
.border-l-6{border-left-width:6px;}
.border-r-6{border-right-width:6px;}
.border-t{border-top-width:1px;}
.last\\:border-b-0:last-child{border-bottom-width:0px;}
.\\!border-transparent{border-color:transparent !important;}
.border-\\[var\\(--color-border\\)\\]{border-color:var(--color-border);}
.border-\\[var\\(--color-danger\\)\\]{border-color:var(--color-danger);}
.border-\\[var\\(--color-reader-border\\)\\]{border-color:var(--color-reader-border);}
.border-\\[var\\(--color-site-accent\\)\\]{border-color:var(--color-site-accent);}
.border-\\[var\\(--color-site-border-subtle\\)\\]{border-color:var(--color-site-border-subtle);}
.border-\\[var\\(--color-site-border\\)\\]{border-color:var(--color-site-border);}
.border-\\[var\\(--color-site-page\\)\\]{border-color:var(--color-site-page);}
.border-\\[var\\(--color-site-swipe-border\\)\\]{border-color:var(--color-site-swipe-border);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:border-\\[var\\(--color-site-border\\)\\]:hover{border-color:var(--color-site-border);}
.border-t-\\[var\\(--color-reader-accent\\)\\]{border-top-color:var(--color-reader-accent);}
.border-t-\\[var\\(--color-site-border-subtle\\)\\]{border-top-color:var(--color-site-border-subtle);}
.rounded{border-radius:0.25rem;}
.rounded-3px{border-radius:3px;}
.rounded-full{border-radius:9999px;}
.rounded-l-md{border-top-left-radius:0.375rem;border-bottom-left-radius:0.375rem;}
.rounded-t-md{border-top-left-radius:0.375rem;border-top-right-radius:0.375rem;}
.border-solid{border-style:solid;}
.\\!bg-\\[color-mix\\(in_srgb\\,var\\(--color-site-page\\)_82\\%\\,black\\)\\]{background-color:color-mix(in srgb,var(--color-site-page) 82%,black) !important;}
.\\!bg-transparent,
.\\[\\&_\\*\\]\\:\\!bg-transparent *{background-color:transparent !important;}
.bg-\\[var\\(--color-background\\)\\]{background-color:var(--color-background);}
.bg-\\[var\\(--color-badge\\)\\]{background-color:var(--color-badge);}
.bg-\\[var\\(--color-control\\)\\]{background-color:var(--color-control);}
.bg-\\[var\\(--color-loading\\)\\]{background-color:var(--color-loading);}
.bg-\\[var\\(--color-reader-border\\,var\\(--color-border\\)\\)\\]{background-color:var(--color-reader-border,var(--color-border));}
.bg-\\[var\\(--color-reader-scrollbar\\,var\\(--color-muted\\)\\)\\]{background-color:var(--color-reader-scrollbar,var(--color-muted));}
.bg-\\[var\\(--color-reader-surface\\)\\]{background-color:var(--color-reader-surface);}
.bg-\\[var\\(--color-site-accent-hover\\)\\]{background-color:var(--color-site-accent-hover);}
.bg-\\[var\\(--color-site-accent\\)\\]{background-color:var(--color-site-accent);}
.bg-\\[var\\(--color-site-elevated\\)\\]{background-color:var(--color-site-elevated);}
.bg-\\[var\\(--color-site-item-hover\\)\\]{background-color:var(--color-site-item-hover);}
.bg-\\[var\\(--color-site-surface\\)\\]{background-color:var(--color-site-surface);}
.bg-\\[var\\(--color-site-swipe-background\\)\\]{background-color:var(--color-site-swipe-background);}
.bg-\\[var\\(--color-state-off\\)\\]{background-color:var(--color-state-off);}
.bg-\\[var\\(--color-state-on\\)\\]{background-color:var(--color-state-on);}
.bg-\\[var\\(--color-surface\\)\\]{background-color:var(--color-surface);}
.bg-black\\/65{background-color:rgb(0 0 0 / 0.65);}
.bg-transparent{background-color:transparent;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:\\!bg-\\[var\\(--color-site-item-hover\\)\\]:hover{background-color:var(--color-site-item-hover) !important;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-badge\\)\\]:hover{background-color:var(--color-badge);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-site-accent-hover\\)\\]:hover{background-color:var(--color-site-accent-hover);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-site-item-hover\\)\\]:hover{background-color:var(--color-site-item-hover);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-site-page\\)\\]:hover{background-color:var(--color-site-page);}
.active\\:\\!bg-\\[var\\(--color-site-item-hover\\)\\]:active{background-color:var(--color-site-item-hover) !important;}
.active\\:bg-\\[var\\(--color-site-accent-hover\\)\\]:active{background-color:var(--color-site-accent-hover);}
.active\\:bg-\\[var\\(--color-site-item-hover\\)\\]:active{background-color:var(--color-site-item-hover);}
.bg-no-repeat{background-repeat:no-repeat;}
.object-contain{object-fit:contain;}
.\\!p-0{padding:0 !important;}
.p-\\[var\\(--reader-end-padding\\)\\]{padding:var(--reader-end-padding);}
.p-0{padding:0;}
.px{padding-left:1rem;padding-right:1rem;}
.px-\\[0\\.6em\\]{padding-left:0.6em;padding-right:0.6em;}
.px-0{padding-left:0;padding-right:0;}
.py-0{padding-top:0;padding-bottom:0;}
.py-56px{padding-top:56px;padding-bottom:56px;}
.pb-2px{padding-bottom:2px;}
.pb-72px{padding-bottom:72px;}
.pl-56px{padding-left:56px;}
.pl-72px{padding-left:72px;}
.pr-56px{padding-right:56px;}
.pr-72px{padding-right:72px;}
.pt-1px{padding-top:1px;}
.pt-2px{padding-top:2px;}
.text-center{text-align:center;}
.text-left{text-align:left;}
.text-right{text-align:right;}
.align-middle{vertical-align:middle;}
.\\!text-\\[var\\(--color-site-text\\)\\]{color:var(--color-site-text) !important;}
.text-\\[var\\(--color-accent\\)\\]{color:var(--color-accent);}
.text-\\[var\\(--color-danger\\)\\]{color:var(--color-danger);}
.text-\\[var\\(--color-muted\\)\\]{color:var(--color-muted);}
.text-\\[var\\(--color-rating-submitted\\)\\]{color:var(--color-rating-submitted);}
.text-\\[var\\(--color-reader-muted\\)\\]{color:var(--color-reader-muted);}
.text-\\[var\\(--color-site-accent\\)\\]{color:var(--color-site-accent);}
.text-\\[var\\(--color-site-surface\\)\\]{color:var(--color-site-surface);}
.text-\\[var\\(--color-site-text\\)\\]{color:var(--color-site-text);}
.text-\\[var\\(--color-text\\)\\]{color:var(--color-text);}
.visited\\:\\!text-\\[var\\(--color-site-text\\)\\]:visited{color:var(--color-site-text) !important;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:\\!text-\\[var\\(--color-site-text\\)\\]:hover{color:var(--color-site-text) !important;}
.active\\:\\!text-\\[var\\(--color-site-text\\)\\]:active{color:var(--color-site-text) !important;}
.\\[\\&_\\*\\]\\:\\!text-inherit *{color:inherit !important;}
.font-400{font-weight:400;}
.font-500{font-weight:500;}
.font-600{font-weight:600;}
.font-700{font-weight:700;}
.font-850{font-weight:850;}
.leading-\\[1\\.05\\]{line-height:1.05;}
.leading-\\[1\\.1\\]{line-height:1.1;}
.leading-\\[1\\.15\\]{line-height:1.15;}
.leading-\\[1\\.16\\]{line-height:1.16;}
.leading-\\[1\\.2\\]{line-height:1.2;}
.leading-\\[1\\.3\\]{line-height:1.3;}
.leading-\\[1\\.35\\]{line-height:1.35;}
.leading-\\[1\\.4\\]{line-height:1.4;}
.leading-\\[1\\.45\\]{line-height:1.45;}
.leading-\\[1\\],
.leading-none{line-height:1;}
.leading-1{line-height:0.25rem;}
.font-inherit{font-family:inherit;}
.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;}
.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";}
.uppercase{text-transform:uppercase;}
.lowercase{text-transform:lowercase;}
.normal-case{text-transform:none;}
.tabular-nums{--un-numeric-spacing:tabular-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:underline:hover{text-decoration-line:underline;}
.active\\:underline:active{text-decoration-line:underline;}
.no-underline{text-decoration:none;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:no-underline:hover{text-decoration:none;}
.active\\:no-underline:active{text-decoration:none;}
.tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4;}
.accent-\\[var\\(--color-reader-accent\\)\\]{accent-color:var(--color-reader-accent);}
.\\[\\&\\[data-open\\=false\\]\\]\\:opacity-0[data-open=false],
.opacity-0{opacity:0;}
.opacity-100{opacity:1;}
.opacity-40{opacity:0.4;}
.opacity-70{opacity:0.7;}
.opacity-72{opacity:0.72;}
.opacity-75{opacity:0.75;}
.opacity-78{opacity:0.78;}
.opacity-80{opacity:0.8;}
.opacity-82{opacity:0.82;}
.opacity-85{opacity:0.85;}
.opacity-90{opacity:0.9;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:opacity-100:hover{opacity:1;}
.focus-visible\\:opacity-100:focus-visible{opacity:1;}
.disabled\\:opacity-40:disabled{opacity:0.4;}
.disabled\\:opacity-50:disabled{opacity:0.5;}
.shadow-\\[0_2px_10px_var\\(--color-shadow-control\\)\\]{--un-shadow:0 2px 10px var(--un-shadow-color, var(--color-shadow-control));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_2px_10px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 2px 10px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_2px_8px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 2px 8px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_4px_14px_var\\(--color-shadow-floating\\)\\]{--un-shadow:0 4px 14px var(--un-shadow-color, var(--color-shadow-floating));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_6px_20px_var\\(--color-shadow-floating\\)\\]{--un-shadow:0 6px 20px var(--un-shadow-color, var(--color-shadow-floating));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_8px_24px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 8px 24px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-none{--un-shadow:0 0 var(--un-shadow-color, rgb(0 0 0 / 0));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-xl{--un-shadow:var(--un-shadow-inset) 0 20px 25px -5px var(--un-shadow-color, rgb(0 0 0 / 0.1)),var(--un-shadow-inset) 0 8px 10px -6px var(--un-shadow-color, rgb(0 0 0 / 0.1));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.focus-visible\\:outline-2:focus-visible{outline-width:2px;}
.focus-visible\\:outline-\\[var\\(--color-site-accent\\)\\]:focus-visible{outline-color:var(--color-site-accent);}
.focus-visible\\:outline-offset-3px:focus-visible{outline-offset:3px;}
.outline{outline-style:solid;}
.focus-visible\\:outline:focus-visible{outline-style:solid;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:brightness-108:hover{--un-brightness:brightness(1.08);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
.filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
.backdrop-filter{-webkit-backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);}
.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[background-color\\,transform\\]{transition-property:background-color,transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[border-color\\,background-color\\,color\\]{transition-property:border-color,background-color,color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[filter\\,transform\\,box-shadow\\]{transition-property:filter,transform,box-shadow;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[opacity\\,background-color\\]{transition-property:opacity,background-color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[opacity\\,transform\\]{transition-property:opacity,transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[width\\,height\\]{transition-property:width,height;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[width\\,opacity\\]{transition-property:width,opacity;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.duration-120{transition-duration:120ms;}
.duration-160{transition-duration:160ms;}
.ease-in-out{transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);}
.will-change-transform{will-change:transform;}
@container (max-width: 430px){
.viewport-toolbar-compact\\:grid-cols-\\[max-content_minmax\\(0\\,1fr\\)_var\\(--ui-control-size-lg\\)_var\\(--ui-control-size-lg\\)\\]{grid-template-columns:max-content minmax(0,1fr) var(--ui-control-size-lg) var(--ui-control-size-lg);}
}
@container (max-width: 540px){
.search-panel-compact\\:block{display:block;}
}`;

  // src/theme.css
  var theme_default = `:is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
  /* --color-background: #070707;
  --color-surface: #151515;
  --color-elevated: #232323;
  --color-text: #f3f3f3;
  --color-accent: #4da3ff; */
  --color-background: var(--color-site-page);
  --color-surface: var(--color-site-surface);
  --color-elevated: var(--color-site-elevated);
  --color-text: var(--color-site-text);
  --color-accent: var(--color-site-accent);
  --color-danger: #ffb2a7;
  --color-state-on: #4ec46a;
  --color-state-off: #8c8f96;
  --color-rating-submitted: #8595ff;
  --color-shadow: #000000;

  --color-site-favorite-0: #646464;
  --color-site-favorite-1: #ff6868;
  --color-site-favorite-2: #ffa561;
  --color-site-favorite-3: #fff56b;
  --color-site-favorite-4: #68ff8b;
  --color-site-favorite-5: #cdff84;
  --color-site-favorite-6: #8afeff;
  --color-site-favorite-7: #7268ff;
  --color-site-favorite-8: #ac57fe;
  --color-site-favorite-9: #fe50c8;

  --color-muted: color-mix(in srgb, var(--color-text) 72%, transparent);
  /* --color-border: color-mix(in srgb, var(--color-text) 18%, transparent); */
  --color-border: var(--color-site-border);
  --color-track: color-mix(in srgb, var(--color-text) 34%, var(--color-background));
  --color-danger-soft: color-mix(in srgb, var(--color-danger) 12%, transparent);
  --color-danger-border: color-mix(in srgb, var(--color-danger) 64%, transparent);
  --color-control: color-mix(in srgb, var(--color-elevated) 88%, transparent);
  --color-badge: color-mix(in srgb, var(--color-background) 34%, transparent);
  --color-shadow-panel: color-mix(in srgb, var(--color-shadow) 32%, transparent);
  --color-shadow-elevated: color-mix(in srgb, var(--color-shadow) 38%, transparent);
  --color-shadow-control: color-mix(in srgb, var(--color-shadow) 40%, transparent);
  --color-shadow-floating: color-mix(in srgb, var(--color-shadow) 42%, transparent);

  --color-site-accent-hover: color-mix(in srgb, var(--color-site-accent) 12%, transparent);
  --color-site-border-subtle: color-mix(in srgb, var(--color-site-border) 16%, transparent);
  --color-site-item-hover: color-mix(in srgb, var(--color-site-text) 8%, transparent);
  --color-loading: color-mix(
    in srgb,
    color-mix(in srgb, var(--color-site-elevated) 80%, var(--color-site-surface)) 92%,
    transparent
  );
  --color-site-swipe-background: color-mix(in srgb, var(--color-site-elevated) 94%, transparent);
  --color-site-swipe-border: color-mix(in srgb, var(--color-site-border) 38%, transparent);
}

html:has(#ehpeek-ui-state.ehpeek-site-e-hentai)
  :is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
  --color-site-page: #e3e0d1;
  --color-site-surface: #edebdf;
  --color-site-elevated: #f3f0e0;
  --color-site-text: #5c0d11;
  --color-site-accent: #8f4701;
  --color-site-border: #5c0d12;
}

html:has(#ehpeek-ui-state.ehpeek-site-exhentai)
  :is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
  --color-site-page: #34353b;
  --color-site-surface: #4f535b;
  --color-site-elevated: #3f4249;
  --color-site-text: #f1f1f1;
  --color-site-accent: #f0b35a;
  --color-site-border: #8d7454;
}

.ehpeek-ui-root {
  -webkit-tap-highlight-color: transparent;
}

.ehpeek-ui-root [data-ehpeek-pressed="true"] {
  opacity: 0.72;
}

html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root :is(
  a[href],
  button,
  input[type="button"],
  input[type="submit"],
  [role="button"],
  [role="tab"],
  [data-ehpeek-pressable="true"]
):not(:disabled, [aria-disabled="true"], .cursor-default):hover {
  filter: brightness(1.08);
  cursor: pointer;
}
`;

  // src/components/Reader/Viewport.tsx
  var _tmpl$41 = /* @__PURE__ */ template("<div tabindex=-1><main>"), _tmpl$214 = /* @__PURE__ */ template('<span class="pointer-events-none absolute [right:var(--ui-space-sm)] [bottom:var(--ui-space-sm)] z-1 block w-[var(--ui-icon-size-xl)] h-[var(--ui-icon-size-xl)] box-border animate-spin rounded-full border-2px border-solid border-[var(--color-reader-border)] border-t-[var(--color-reader-accent)]"role=status>'), _tmpl$311 = /* @__PURE__ */ template('<section><div class="relative flex w-[var(--reader-frame-width)] h-[var(--reader-frame-height)] items-center justify-center overflow-hidden [container-type:size]">'), _tmpl$410 = /* @__PURE__ */ template('<button type=button class="ehpeek-reader-page-reload appearance-none inline-flex ui-hit-square-xl items-center justify-center border border-[var(--color-border)] ui-rounded-md bg-[var(--color-control)] text-[var(--color-text)] cursor-pointer font-sans textsize-lg font-700 leading-1 hover:bg-[var(--color-badge)] active:scale-96 [touch-action:manipulation]">'), _tmpl$58 = /* @__PURE__ */ template('<div class="max-w-[min(86vw,760px)] break-anywhere [direction:ltr] [unicode-bidi:plaintext]">'), _tmpl$68 = /* @__PURE__ */ template('<div class="max-w-[min(86vw,760px)] opacity-80 break-anywhere textsize-sm font-500 leading-[1.4] [direction:ltr] [unicode-bidi:plaintext]">'), _tmpl$76 = /* @__PURE__ */ template("<div>"), _tmpl$85 = /* @__PURE__ */ template('<span class="flex w-full h-full flex-col items-center justify-center ui-gap-xl overflow-hidden"aria-hidden=true><span class="block max-w-full flex-none m-0 p-0 text-center leading-[1] whitespace-nowrap [direction:ltr] [unicode-bidi:plaintext]"></span><span class="block w-[var(--ui-icon-size-xl)] h-[var(--ui-icon-size-xl)] flex-none box-border animate-spin rounded-full border-4px border-solid border-[var(--color-reader-border)] border-t-[var(--color-reader-accent)]">'), FALLBACK_ASPECT_RATIO = 1.42, PAGE_SLOT_SPACING = 8, DEFAULT_DECODED_IMAGE_CACHE_LIMIT = 24, DECODED_IMAGE_CACHE_BYTES = 96 * 1024 * 1024, HORIZONTAL_FLING_VELOCITY_MULTIPLIER = 1.4, HORIZONTAL_FLING_MAX_VELOCITY = 1.8;
  function pageWindowNumbers(currentPageNum, windowSize) {
    let numbers = [];
    for (let offset = -windowSize; offset <= windowSize; offset += 1)
      numbers.push(currentPageNum + offset);
    return numbers;
  }
  function PagesViewport(props) {
    let [slots, setSlots] = createSignal([]), [revision, setRevision] = createSignal(0), [renderedScrollSizeScale, setRenderedScrollSizeScale] = createSignal(untrack(() => props.scrollSizeScale)), horizontalAnimator = new ScrollAnimator("x"), verticalAnimator = new ScrollAnimator("y"), flingAnimator = new ScrollFlingAnimator(), pageSlots2 = [], scroller, scrollerApi, dragStartPosition = null, resizeFrame = null, scrollScaleRevision = 0, moveRequestToken = 0, disposed = !1, syncedDirection = untrack(() => props.direction), syncedNavigationMode = untrack(() => props.navigationMode), decodedImageCacheLimit = Math.max(0, Math.floor(untrack(() => props.decodedImageCacheLimit) ?? DEFAULT_DECODED_IMAGE_CACHE_LIMIT)), cachedImages = /* @__PURE__ */ new Map(), pageErrors = /* @__PURE__ */ new Map(), cachedImageBytes = 0, refresh = () => setRevision((value) => value + 1), pagedMode = () => props.navigationMode === "paged", horizontalAxis = () => props.direction !== "ttb", slotFor = (pageNum) => pageSlots2.find((slot) => slot.pageNum === pageNum), viewportWidth = () => scrollerApi.viewportWidth(), viewportHeight = () => scrollerApi.viewportHeight(), scrollTop = () => scrollerApi.scrollTop(), visualSlotIndex = (index, slotCount) => props.direction === "rtl" ? slotCount - 1 - index : index, horizontalAnchorOffset = (pageSlots3, anchor2) => {
      let orderedSlots = props.direction === "rtl" ? pageSlots3.slice().reverse() : pageSlots3, offset = 0;
      for (let slot of orderedSlots) {
        let extent = slot.frameWidth + PAGE_SLOT_SPACING;
        if (slot.pageNum === anchor2.pageNum)
          return offset + extent * anchor2.xRatio;
        offset += extent;
      }
      return null;
    }, applySlotSize = (slot) => {
      let aspectRatio = pageSlotAspectRatio(slot);
      if (pagedMode()) {
        let availableWidth = props.pageLayout === "double" ? Math.max(1, (viewportWidth() - 3) / 2) : viewportWidth();
        if (slot.kind !== "page") {
          slot.frameWidth = availableWidth, slot.frameHeight = viewportHeight();
          return;
        }
        let frameSize = containFitFrame(aspectRatio, availableWidth, viewportHeight());
        slot.frameWidth = frameSize.width, slot.frameHeight = frameSize.height;
        return;
      }
      let sizeScale = renderedScrollSizeScale(), reference = props.scrollFitImageSize, referenceAspectRatio = reference ? reference.height / reference.width : props.window.pages.get(props.scrollFitPageNum)?.aspectRatio ?? FALLBACK_ASPECT_RATIO, scaleMultiplier = sizeScale === "one-to-one" && reference ? 1 / containFitScale(reference.width, reference.height, viewportWidth(), viewportHeight()) : typeof sizeScale == "number" ? sizeScale : 1, referenceFrame = containFitFrame(referenceAspectRatio, viewportWidth(), viewportHeight(), scaleMultiplier);
      horizontalAxis() ? (slot.frameHeight = referenceFrame.height, slot.frameWidth = referenceFrame.height / aspectRatio) : (slot.frameWidth = referenceFrame.width, slot.frameHeight = referenceFrame.width * aspectRatio);
    }, renderSlots = () => {
      for (let slot of pageSlots2)
        applySlotSize(slot);
      setSlots(pageSlots2.slice()), refresh();
    }, refreshSlot = (slot) => {
      applySlotSize(slot), refresh();
    }, pageOffset = (pageNum) => {
      let elements = slotFor(pageNum)?.elements;
      return elements ? scrollerApi.slotOffset(elements, props.navigationMode, props.direction, props.pageLayout) : null;
    }, verticalScrollBoundsForElements = (firstElements, lastElements) => {
      let bounds = {};
      if (firstElements && (bounds.min = scrollerApi.slotTop(firstElements)), lastElements) {
        let lastElementsRect = lastElements.node.getBoundingClientRect(), lastElementsTop = scrollerApi.slotTop(lastElements);
        bounds.max = lastElementsTop + lastElementsRect.height - viewportHeight();
      }
      return bounds.min === void 0 && bounds.max === void 0 ? null : (bounds.min !== void 0 && bounds.max !== void 0 && (bounds.max = Math.max(bounds.min, bounds.max)), bounds);
    }, verticalScrollBounds = () => props.navigationMode !== "scroll" || horizontalAxis() ? null : verticalScrollBoundsForElements(slotFor(1)?.elements, props.window.totalPages ? slotFor(props.window.totalPages + 1)?.elements : null), moveToTop = (nextScrollTop) => {
      scrollerApi.moveToTop(nextScrollTop, verticalScrollBounds());
    }, horizontalScrollBounds = () => {
      if (props.navigationMode !== "scroll" || !horizontalAxis())
        return null;
      let firstElements = slotFor(1)?.elements, endElements = props.window.totalPages ? slotFor(props.window.totalPages + 1)?.elements : null, bounds = {};
      return props.direction === "rtl" ? (firstElements && (bounds.max = scrollerApi.slotLeft(firstElements) + firstElements.node.getBoundingClientRect().width - viewportWidth()), endElements && (bounds.min = scrollerApi.slotLeft(endElements))) : (firstElements && (bounds.min = scrollerApi.slotLeft(firstElements)), endElements && (bounds.max = scrollerApi.slotLeft(endElements) + endElements.node.getBoundingClientRect().width - viewportWidth())), bounds.min !== void 0 && bounds.max !== void 0 && (bounds.max = Math.max(bounds.min, bounds.max)), bounds.min === void 0 && bounds.max === void 0 ? null : bounds;
    }, moveToLeft = (nextScrollLeft) => {
      let bounds = horizontalScrollBounds();
      scrollerApi.moveToLeft(bounds ? clamp(nextScrollLeft, bounds.min ?? Number.NEGATIVE_INFINITY, bounds.max ?? Number.POSITIVE_INFINITY) : nextScrollLeft);
    }, pageNumAtPoint = (point) => {
      let element = document.elementFromPoint(point.clientX, point.clientY), pageNode = element instanceof Element ? element.closest(".ehpeek-page") : null;
      if (!pageNode || !scroller.contains(pageNode))
        return null;
      let pageNum = Number(pageNode.dataset.ehpeekPageNum || "");
      return Number.isFinite(pageNum) ? pageNum : null;
    }, stopMotion = () => {
      moveRequestToken += 1, dragStartPosition = null, flingAnimator.cancel(), horizontalAnimator.cancel(), verticalAnimator.cancel();
    }, performPageMove = (pageNum, motion, onComplete) => {
      let delta = pageOffset(pageNum);
      return delta === null ? !1 : (horizontalAxis() ? horizontalAnimator.scrollTo(scroller, scrollerApi.scrollLeft() + delta, motion, onComplete) : pagedMode() ? verticalAnimator.scrollTo(scroller, scrollTop() + delta, motion, onComplete) : (moveToTop(scrollTop() + delta), onComplete?.()), !0);
    }, moveToPage = (pageNum, motion = "instant", onComplete) => {
      let requestToken = ++moveRequestToken;
      performPageMove(pageNum, motion, onComplete) || queueMicrotask(() => {
        untrack(() => {
          !disposed && requestToken === moveRequestToken && performPageMove(pageNum, motion, onComplete);
        });
      });
    }, resizePages = () => {
      for (let slot of pageSlots2)
        applySlotSize(slot);
      refresh();
    }, gestureDragging = createPointerGestureElement(() => scroller ?? null, () => props.callbacks.pointer), syncWindow = (options) => {
      let anchor2 = props.navigationMode === "scroll" && horizontalAxis() && syncedNavigationMode === props.navigationMode && syncedDirection === props.direction ? scrollerApi.centerAnchor() : null, oldAnchorOffset = anchor2 ? horizontalAnchorOffset(pageSlots2, anchor2) : null, oldScrollLeft = scrollerApi.scrollLeft(), oldSlots = new Map(pageSlots2.map((slot) => [slot.pageNum, slot])), nextSlots = [];
      for (let pageNum of pageWindowNumbers(options.currentPageNum, options.windowSize)) {
        let kind = pageSlotKind(pageNum, options.totalPages), oldSlot = oldSlots.get(pageNum), slot = oldSlot && oldSlot.kind === kind ? oldSlot : pageSlot(pageNum, kind);
        if (!oldSlot && kind === "page") {
          let errorMessage = pageErrors.get(pageNum), cached = cachedImages.get(pageNum);
          errorMessage ? (slot.state = "error", slot.errorMessage = errorMessage) : cached && (cachedImages.delete(pageNum), cachedImageBytes -= cached.bytes, slot.state = "ready", slot.image = cached.image, slot.width = cached.width, slot.height = cached.height);
        }
        if (kind === "page") {
          let page2 = options.pages.get(pageNum);
          page2 && applyPageMetaToSlot(slot, page2);
        } else
          clearNonPageSlotMeta(slot);
        nextSlots.push(slot);
      }
      let nextSet = new Set(nextSlots);
      for (let slot of pageSlots2)
        if (!nextSet.has(slot)) {
          if (slot.kind === "page" && slot.state === "ready" && slot.image) {
            let width = positiveNumber(slot.image.naturalWidth) ?? slot.width, height = positiveNumber(slot.image.naturalHeight) ?? slot.height, cached = {
              bytes: width && height ? width * height * 4 : 0,
              height,
              image: slot.image,
              width
            }, previous = cachedImages.get(slot.pageNum);
            previous && (cachedImageBytes -= previous.bytes), cachedImages.delete(slot.pageNum), cachedImages.set(slot.pageNum, cached), cachedImageBytes += cached.bytes;
          }
          slot.token += 1;
        }
      for (; cachedImages.size > decodedImageCacheLimit || cachedImageBytes > DECODED_IMAGE_CACHE_BYTES; ) {
        let oldest = cachedImages.entries().next().value;
        if (!oldest)
          break;
        cachedImages.delete(oldest[0]), cachedImageBytes -= oldest[1].bytes, oldest[1].image.removeAttribute("src");
      }
      pageSlots2 = nextSlots, pageSlots2.forEach((slot, index) => {
        slot.index = index;
      }), renderSlots();
      let newAnchorOffset = anchor2 ? horizontalAnchorOffset(pageSlots2, anchor2) : null;
      oldAnchorOffset !== null && newAnchorOffset !== null && moveToLeft(oldScrollLeft + newAnchorOffset - oldAnchorOffset), syncedNavigationMode = props.navigationMode, syncedDirection = props.direction;
    }, actions = {
      focus: () => scroller.focus({
        preventScroll: !0
      }),
      isDragging: gestureDragging,
      beginDrag() {
        stopMotion(), dragStartPosition = {
          left: scrollerApi.scrollLeft(),
          top: scrollTop()
        };
      },
      cancelDrag: () => {
        dragStartPosition = null;
      },
      moveDrag(delta) {
        return dragStartPosition === null ? !1 : (pagedMode() ? horizontalAxis() ? scrollerApi.moveToLeft(dragStartPosition.left - delta.dx) : moveToTop(dragStartPosition.top - delta.dy) : (moveToLeft(dragStartPosition.left - delta.dx), moveToTop(dragStartPosition.top - delta.dy)), !0);
      },
      moveToLeft,
      resetPosition: () => scrollerApi.resetPosition(),
      stopMotion,
      markPageLoading(pageNum) {
        let slot = slotFor(pageNum);
        return !slot || slot.kind !== "page" || slot.state !== "idle" ? null : (slot.state = "loading", slot.errorMessage = null, slot.token += 1, refreshSlot(slot), slot.token);
      },
      async loadPageImage(pageNum, token, slotImage) {
        let image2 = pageImageDom(pageNum, slotImage), pendingSlot = slotFor(pageNum);
        pendingSlot && pendingSlot.token === token && (slotImage.displayWhileLoading && (pendingSlot.image = image2), pendingSlot.width = slotImage.width, pendingSlot.height = slotImage.height, refreshSlot(pendingSlot)), await loadImage(image2);
        let slot = slotFor(pageNum);
        return !slot || slot.token !== token || !slot.elements ? !1 : (slot.state = "ready", slot.image = image2, slot.errorMessage = null, pageErrors.delete(pageNum), slot.width = positiveNumber(image2.naturalWidth) ?? slotImage.width, slot.height = positiveNumber(image2.naturalHeight) ?? slotImage.height, refreshSlot(slot), !0);
      },
      setPageError(pageNum, token, errorMessage) {
        let slot = slotFor(pageNum);
        return !slot || slot.token !== token ? !1 : (slot.state = "error", slot.image = null, slot.errorMessage = errorMessage, pageErrors.set(pageNum, errorMessage), refresh(), !0);
      },
      resetPageError(pageNum) {
        let slot = slotFor(pageNum);
        return !slot || slot.kind !== "page" || slot.state !== "error" ? !1 : (slot.state = "idle", slot.errorMessage = null, pageErrors.delete(pageNum), refreshSlot(slot), !0);
      },
      resetPageLoading(pageNum, token) {
        let slot = slotFor(pageNum);
        return !slot || slot.kind !== "page" || slot.state !== "loading" || slot.token !== token ? !1 : (slot.state = "idle", refreshSlot(slot), !0);
      },
      moveToPage,
      moveToTop,
      scrollLeft: () => scrollerApi.scrollLeft(),
      scrollTop,
      viewportWidth,
      pageOffset,
      centerPageNum() {
        for (let slot of pageSlots2)
          if (slot.elements && slot.kind !== "blank" && scrollerApi.slotContainsViewportTarget(slot.elements, props.direction))
            return slot.pageNum;
        return null;
      },
      firstVisiblePageNum() {
        let first = null;
        for (let slot of pageSlots2) {
          if (!slot.elements || slot.kind !== "page")
            continue;
          let distance = scrollerApi.slotViewportStartDistance(slot.elements, props.direction);
          distance !== null && (!first || distance < first.distance) && (first = {
            distance,
            pageNum: slot.pageNum
          });
        }
        return first?.pageNum ?? null;
      },
      isHitEndPage(point) {
        let pageNum = pageNumAtPoint(point);
        return pageNum !== null && slotFor(pageNum)?.kind === "end";
      },
      pageImageHeight(pageNum) {
        let slot = slotFor(pageNum);
        return slot?.image?.naturalHeight || slot?.height || null;
      },
      pageImageReady(pageNum) {
        let slot = slotFor(pageNum);
        return slot?.state === "ready" && slot.image !== null;
      },
      pageImageWidth(pageNum) {
        let slot = slotFor(pageNum);
        return slot?.image?.naturalWidth || slot?.width || null;
      },
      pageZoomScale(pageNum) {
        let slot = slotFor(pageNum), frameRect = slot?.elements?.frame.getBoundingClientRect(), imageWidth = slot?.image?.naturalWidth || slot?.width, imageHeight = slot?.image?.naturalHeight || slot?.height;
        if (!frameRect || !imageWidth || !imageHeight)
          return 1;
        let readerScale = Math.min(frameRect.width / imageWidth, frameRect.height / imageHeight), overlayScale = Math.min(1, viewportWidth() / imageWidth, viewportHeight() / imageHeight);
        return readerScale > 0 && overlayScale > 0 ? readerScale / overlayScale : 1;
      },
      pageNumAtPoint,
      startVerticalFlingFromDragVelocity(dragVelocityY, onStop) {
        flingAnimator.start({
          axis: "y",
          scroller,
          initialVelocity: -dragVelocityY,
          setScrollPosition: moveToTop,
          canRun: () => !disposed && props.navigationMode === "scroll" && !horizontalAxis(),
          onStop
        });
      },
      startHorizontalFlingFromDragVelocity(dragVelocityX, onStop) {
        flingAnimator.start({
          axis: "x",
          scroller,
          initialVelocity: -dragVelocityX * HORIZONTAL_FLING_VELOCITY_MULTIPLIER,
          maxVelocity: HORIZONTAL_FLING_MAX_VELOCITY,
          setScrollPosition: moveToLeft,
          canRun: () => !disposed && props.navigationMode === "scroll" && horizontalAxis(),
          onStop
        });
      }
    };
    untrack(() => props.actionsRef(actions)), createEffect(() => syncWindow(props.window)), createEffect(() => {
      let navigationMode = props.navigationMode, direction = props.direction, scrollFitImageSize = props.scrollFitImageSize, scrollSizeScale = props.scrollSizeScale;
      if (navigationMode !== "scroll") {
        setRenderedScrollSizeScale(1);
        return;
      }
      let anchor2 = scrollerApi.centerAnchor(), scaleRevision = ++scrollScaleRevision;
      setRenderedScrollSizeScale(scrollSizeScale), untrack(resizePages), queueMicrotask(() => {
        disposed || scaleRevision !== scrollScaleRevision || (anchor2 ? scrollerApi.restoreCenterAnchor(anchor2) : direction === "ttb" ? scrollerApi.centerHorizontal() : scrollerApi.centerVertical());
      });
    });
    let scrollStripStyle = () => (revision(), props.navigationMode !== "scroll" ? {} : props.direction === "ttb" ? {
      width: `${Math.max(viewportWidth(), ...pageSlots2.map((slot) => slot.frameWidth))}px`
    } : {
      height: `${Math.max(viewportHeight(), ...pageSlots2.map((slot) => slot.frameHeight))}px`,
      width: "max-content"
    }), stripClass = () => props.navigationMode === "paged" ? props.direction === "ttb" && props.pageLayout === "double" ? "grid grid-cols-2 auto-rows-[100%] w-full h-full gap-x-3px" : props.direction === "ttb" ? "flex flex-col w-full h-full" : `flex flex-row w-auto h-full${props.pageLayout === "double" ? " gap-3px" : ""}` : props.direction === "ttb" ? "flex flex-col min-h-full mx-auto py-56px px-0 pb-72px" : `flex flex-row min-w-full my-auto py-0 ${props.direction === "rtl" ? "pl-72px pr-56px" : "pl-56px pr-72px"}`;
    return onMount(() => {
      let observer = new ResizeObserver(() => {
        resizeFrame === null && (resizeFrame = window.requestAnimationFrame(() => {
          resizeFrame = null, untrack(resizePages);
        }));
      });
      observer.observe(scroller), onCleanup(() => observer.disconnect());
    }), onCleanup(() => {
      disposed = !0, stopMotion();
      for (let cached of cachedImages.values())
        cached.image.removeAttribute("src");
      cachedImages.clear(), cachedImageBytes = 0, resizeFrame !== null && (window.cancelAnimationFrame(resizeFrame), resizeFrame = null);
    }), (() => {
      var _el$ = _tmpl$41(), _el$2 = _el$.firstChild;
      return _el$.addEventListener("wheel", (event) => {
        let delta = Math.abs(event.deltaX) > Math.abs(event.deltaY) ? event.deltaX : event.deltaY;
        props.callbacks.onWheel(delta, event);
      }), _el$.addEventListener("scroll", () => props.callbacks.onNativeScroll()), _el$.$$dblclick = (event) => props.callbacks.onDoubleClick(event), use((element) => {
        scroller = element, scrollerApi = createPagesScroller(element);
      }, _el$), insert(_el$2, createComponent(For, {
        get each() {
          return slots();
        },
        children: (slot) => createComponent(PageSlotView, {
          get doublePageSide() {
            return doublePageSide(slot.pageNum, props.window.currentPageNum, props.navigationMode, props.pageLayout, props.direction);
          },
          get direction() {
            return props.direction;
          },
          get navigationMode() {
            return props.navigationMode;
          },
          get pageLayout() {
            return props.pageLayout;
          },
          slot,
          get revision() {
            return revision();
          },
          get visualIndex() {
            return visualSlotIndex(slot.index, slots().length);
          },
          onReloadPage: (pageNum) => props.callbacks.onReloadPage(pageNum)
        })
      })), createRenderEffect((_p$) => {
        var _v$ = "w-full h-full overflow-auto overscroll-contain scroll-auto cursor-grab scrollbar-hidden " + (!props.zoomActive && props.navigationMode === "scroll" && props.direction === "ttb" ? "[touch-action:pan-x_pan-y] " : "touch-none ") + "[&[data-dragging=true]]:cursor-grabbing [&[data-dragging=true]]:select-none [#ehpeek-reader[data-navigation-mode=paged]_&]:overflow-hidden [#ehpeek-reader[data-navigation-mode=paged]_&]:touch-none [#ehpeek-reader[data-navigation-mode=paged]_&]:select-none", _v$2 = `ehpeek-reader-page-strip ${stripClass()}`, _v$3 = scrollStripStyle();
        return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && className(_el$2, _p$.t = _v$2), _p$.a = style(_el$2, _v$3, _p$.a), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$;
    })();
  }
  function PageSlotView(props) {
    let node, frame, content = createMemo(() => (props.revision, {
      pageNum: props.slot.pageNum,
      kind: props.slot.kind,
      state: props.slot.state,
      errorMessage: props.slot.errorMessage ?? void 0
    })), image2 = createMemo(() => (props.revision, props.slot.state === "ready" || props.slot.state === "loading" ? props.slot.image : null)), imageLoading = createMemo(() => (props.revision, props.slot.state === "loading" && props.slot.image !== null)), slotStyle = createMemo(() => {
      props.revision;
      let frameShortSide = Math.min(props.slot.frameWidth, props.slot.frameHeight);
      return {
        "--reader-page-height": `${props.slot.frameHeight + PAGE_SLOT_SPACING}px`,
        "--reader-page-width": `${props.slot.frameWidth + PAGE_SLOT_SPACING}px`,
        "--reader-frame-width": `${props.slot.frameWidth}px`,
        "--reader-frame-height": `${props.slot.frameHeight}px`,
        "--reader-end-font-size": `${Math.max(10, frameShortSide * 0.11)}px`,
        "--reader-end-padding": `${Math.min(24, Math.max(4, frameShortSide * 0.06))}px`,
        order: String(props.visualIndex)
      };
    });
    return onCleanup(() => {
      props.slot.elements?.node === node && (props.slot.elements = null);
    }), (() => {
      var _el$3 = _tmpl$311(), _el$4 = _el$3.firstChild, _ref$ = node;
      return typeof _ref$ == "function" ? use(_ref$, _el$3) : node = _el$3, use((element) => {
        frame = element, props.slot.elements = {
          node,
          frame
        };
      }, _el$4), insert(_el$4, createComponent(Show, {
        get when() {
          return image2();
        },
        keyed: !0,
        get fallback() {
          return createComponent(PageSlotPlaceholder, {
            get content() {
              return content();
            },
            get text() {
              return slotPlaceholderText(content());
            },
            get onReloadPage() {
              return props.onReloadPage;
            }
          });
        },
        children: (currentImage) => currentImage
      }), null), insert(_el$4, createComponent(Show, {
        get when() {
          return imageLoading();
        },
        get children() {
          var _el$5 = _tmpl$214();
          return createRenderEffect(() => setAttribute(_el$5, "aria-label", i18n_default.common.status.loading)), _el$5;
        }
      }), null), createRenderEffect((_p$) => {
        var _v$4 = `ehpeek-page flex items-center ${props.doublePageSide === "left" ? "justify-end" : props.doublePageSide === "right" ? "justify-start" : "justify-center"} ${pageSlotClass(props.navigationMode, props.direction, props.pageLayout)}`, _v$5 = String(props.slot.pageNum), _v$6 = slotStyle();
        return _v$4 !== _p$.e && className(_el$3, _p$.e = _v$4), _v$5 !== _p$.t && setAttribute(_el$3, "data-ehpeek-page-num", _p$.t = _v$5), _p$.a = style(_el$3, _v$6, _p$.a), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$3;
    })();
  }
  function doublePageSide(pageNum, currentPageNum, navigationMode, pageLayout, direction) {
    if (navigationMode !== "paged" || pageLayout !== "double")
      return null;
    let firstInPair = Math.abs(pageNum - currentPageNum) % 2 === 0;
    return direction === "rtl" ? firstInPair ? "right" : "left" : firstInPair ? "left" : "right";
  }
  function pageSlotClass(navigationMode, direction, pageLayout) {
    return navigationMode === "scroll" ? direction === "ttb" ? "w-full h-[var(--reader-page-height)] items-start pb-sm" : "flex-[0_0_var(--reader-page-width)] w-[var(--reader-page-width)] h-full pr-sm" : direction === "ttb" ? pageLayout === "double" ? "w-full h-full" : "flex-[0_0_100%] w-full h-full" : pageLayout === "double" ? "h-full" : "flex-[0_0_100%] w-full h-full";
  }
  function PageSlotPlaceholder(props) {
    let stop = (event) => {
      event.preventDefault(), event.stopPropagation();
    };
    return (() => {
      var _el$6 = _tmpl$76();
      return insert(_el$6, createComponent(Show, {
        get when() {
          return props.content.state === "error";
        },
        get fallback() {
          return createComponent(Show, {
            get when() {
              return props.content.state === "loading";
            },
            get fallback() {
              return props.text;
            },
            get children() {
              var _el$0 = _tmpl$85(), _el$1 = _el$0.firstChild;
              return insert(_el$1, () => props.text), _el$0;
            }
          });
        },
        get children() {
          return [(() => {
            var _el$7 = _tmpl$410();
            return _el$7.$$click = (event) => {
              stop(event), props.onReloadPage(props.content.pageNum);
            }, _el$7.$$pointerdown = stop, insert(_el$7, createComponent(Icon2, {
              name: "refresh",
              size: "var(--ui-icon-size-xl)"
            })), createRenderEffect((_p$) => {
              var _v$7 = `${i18n_default.reader.reloadPage} ${props.content.pageNum}`, _v$8 = i18n_default.reader.reloadPage;
              return _v$7 !== _p$.e && setAttribute(_el$7, "aria-label", _p$.e = _v$7), _v$8 !== _p$.t && setAttribute(_el$7, "title", _p$.t = _v$8), _p$;
            }, {
              e: void 0,
              t: void 0
            }), _el$7;
          })(), (() => {
            var _el$8 = _tmpl$58();
            return insert(_el$8, () => i18n_default.common.status.failed), _el$8;
          })(), createComponent(Show, {
            get when() {
              return props.content.errorMessage;
            },
            get children() {
              var _el$9 = _tmpl$68();
              return insert(_el$9, () => props.content.errorMessage), _el$9;
            }
          })];
        }
      })), createRenderEffect((_p$) => {
        var _v$9 = props.content.state === "error" ? "flex w-full h-full flex-col items-center justify-center ui-gap-lg bg-[var(--color-reader-surface)] ui-p-xl text-[var(--color-danger)] text-center textsize-md font-700 leading-1" : "relative flex w-full h-full items-center justify-center bg-[var(--color-reader-surface)] text-[var(--color-reader-muted)] text-center " + (props.content.kind === "end" ? "p-[var(--reader-end-padding)] [direction:ltr] [font-size:min(var(--ui-font-size-xl),var(--reader-end-font-size))] font-700 leading-[1.3] [unicode-bidi:plaintext]" : "[font-size:min(25vw,35cqi,35cqb,180px)] font-mono font-850 leading-[1] [font-variant-numeric:tabular-nums]"), _v$0 = props.content.state === "loading" ? "status" : void 0, _v$1 = props.content.state === "loading" ? `${i18n_default.common.status.loading} ${props.text}` : void 0;
        return _v$9 !== _p$.e && className(_el$6, _p$.e = _v$9), _v$0 !== _p$.t && setAttribute(_el$6, "role", _p$.t = _v$0), _v$1 !== _p$.a && setAttribute(_el$6, "aria-label", _p$.a = _v$1), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$6;
    })();
  }
  function pageImageDom(pageNum, slotImage) {
    let image2 = document.createElement("img");
    return image2.className = "block w-full h-full object-contain select-none [-webkit-user-drag:none]", image2.alt = `Page ${pageNum}`, image2.decoding = "async", image2.loading = "eager", image2.draggable = !1, image2.setAttribute("fetchpriority", slotImage.highPriority ? "high" : "low"), image2.src = slotImage.imageUrl, slotImage.width && slotImage.height && (image2.width = slotImage.width, image2.height = slotImage.height), image2;
  }
  async function loadImage(image2) {
    if (!(image2.complete && image2.naturalWidth > 0)) {
      await new Promise((resolve, reject) => {
        image2.addEventListener("load", () => resolve(), {
          once: !0
        }), image2.addEventListener("error", () => reject(new Error(i18n_default.errors.imageLoadFailed)), {
          once: !0
        });
      });
      try {
        await image2.decode();
      } catch {
      }
    }
  }
  function createPagesScroller(element) {
    let clampedTop = (scrollTop, bounds) => bounds ? clamp(scrollTop, bounds.min ?? Number.NEGATIVE_INFINITY, bounds.max ?? Number.POSITIVE_INFINITY) : scrollTop;
    return {
      element,
      resetPosition() {
        element.scrollLeft = 0, element.scrollTop = 0;
      },
      scrollLeft() {
        return element.scrollLeft;
      },
      scrollTop() {
        return element.scrollTop;
      },
      viewportWidth() {
        return element.clientWidth || window.innerWidth || 1;
      },
      viewportHeight() {
        return element.clientHeight;
      },
      moveToLeft(scrollLeft) {
        element.scrollLeft = scrollLeft;
      },
      centerHorizontal() {
        element.scrollLeft = Math.max(0, (element.scrollWidth - element.clientWidth) / 2);
      },
      centerVertical() {
        element.scrollTop = Math.max(0, (element.scrollHeight - element.clientHeight) / 2);
      },
      centerAnchor() {
        let viewportRect = element.getBoundingClientRect(), centerX = viewportRect.left + viewportRect.width / 2, centerY = viewportRect.top + viewportRect.height / 2, pages = Array.from(element.querySelectorAll(".ehpeek-page")), closest = null;
        for (let node of pages) {
          let rect2 = node.getBoundingClientRect(), dx = centerX < rect2.left ? rect2.left - centerX : centerX > rect2.right ? centerX - rect2.right : 0, dy = centerY < rect2.top ? rect2.top - centerY : centerY > rect2.bottom ? centerY - rect2.bottom : 0, distance = Math.hypot(dx, dy);
          (!closest || distance < closest.distance) && (closest = {
            distance,
            node
          });
        }
        if (!closest)
          return null;
        let rect = closest.node.getBoundingClientRect(), pageNum = Number(closest.node.dataset.ehpeekPageNum || "");
        return Number.isFinite(pageNum) && rect.width > 0 && rect.height > 0 ? {
          pageNum,
          xRatio: (centerX - rect.left) / rect.width,
          yRatio: (centerY - rect.top) / rect.height
        } : null;
      },
      restoreCenterAnchor(anchor2) {
        let node = element.querySelector(`.ehpeek-page[data-ehpeek-page-num="${anchor2.pageNum}"]`);
        if (!node)
          return;
        let viewportRect = element.getBoundingClientRect(), pageRect = node.getBoundingClientRect(), centerX = viewportRect.left + viewportRect.width / 2, centerY = viewportRect.top + viewportRect.height / 2;
        element.scrollLeft += pageRect.left + pageRect.width * anchor2.xRatio - centerX, element.scrollTop += pageRect.top + pageRect.height * anchor2.yRatio - centerY;
      },
      moveToTop(scrollTop, bounds) {
        element.scrollTop = clampedTop(scrollTop, bounds);
      },
      slotTop(elements) {
        let elementsRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
        return element.scrollTop + elementsRect.top - scrollerRect.top;
      },
      slotLeft(elements) {
        let elementsRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
        return element.scrollLeft + elementsRect.left - scrollerRect.left;
      },
      slotOffset(elements, navigationMode, direction, pageLayout) {
        let pageRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
        return direction === "ttb" ? pageRect.top - scrollerRect.top : direction === "rtl" && (navigationMode === "scroll" || pageLayout === "double") ? pageRect.right - scrollerRect.right : pageRect.left - scrollerRect.left;
      },
      slotContainsViewportTarget(elements, direction) {
        let scrollerRect = element.getBoundingClientRect(), rect = elements.node.getBoundingClientRect();
        if (direction === "ttb") {
          let target2 = scrollerRect.top + Math.min(80, scrollerRect.height * 0.14);
          return rect.top <= target2 && rect.bottom > target2;
        }
        let offset = Math.min(80, scrollerRect.width * 0.14), target = direction === "rtl" ? scrollerRect.right - offset : scrollerRect.left + offset;
        return rect.left <= target && rect.right > target;
      },
      slotViewportStartDistance(elements, direction) {
        let scrollerRect = element.getBoundingClientRect(), rect = elements.node.getBoundingClientRect();
        return rect.bottom <= scrollerRect.top || rect.top >= scrollerRect.bottom || rect.right <= scrollerRect.left || rect.left >= scrollerRect.right ? null : direction === "ttb" ? Math.max(0, rect.top - scrollerRect.top) : direction === "rtl" ? Math.max(0, scrollerRect.right - rect.right) : Math.max(0, rect.left - scrollerRect.left);
      }
    };
  }
  function slotPlaceholderText(content) {
    return content.state === "error" ? i18n_default.common.status.failed : content.kind === "end" ? i18n_default.reader.end : content.kind === "blank" ? "" : String(content.pageNum);
  }
  function pageSlotKind(pageNum, totalPages) {
    return pageNum < 1 ? "blank" : totalPages && pageNum === totalPages + 1 ? "end" : totalPages && pageNum > totalPages + 1 ? "blank" : "page";
  }
  function pageSlot(pageNum, kind) {
    return {
      pageNum,
      index: 0,
      kind,
      state: kind === "page" ? "idle" : "ready",
      aspectRatio: FALLBACK_ASPECT_RATIO,
      width: null,
      height: null,
      image: null,
      errorMessage: null,
      frameWidth: 1,
      frameHeight: Math.ceil(FALLBACK_ASPECT_RATIO),
      elements: null,
      token: 0
    };
  }
  function applyPageMetaToSlot(slot, page2) {
    let aspectRatio = normalizedAspectRatio(page2.aspectRatio, FALLBACK_ASPECT_RATIO);
    slot.aspectRatio !== aspectRatio && (slot.aspectRatio = aspectRatio);
  }
  function clearNonPageSlotMeta(slot) {
    slot.kind !== "blank" && slot.kind !== "end" || (slot.state = "ready", slot.image = null, slot.errorMessage = null, slot.width = null, slot.height = null, slot.token += 1);
  }
  function pageSlotAspectRatio(slot) {
    return slot.width && slot.height && slot.width > 0 && slot.height > 0 ? slot.height / slot.width : normalizedAspectRatio(slot.aspectRatio, FALLBACK_ASPECT_RATIO);
  }
  function containFitScale(imageWidth, imageHeight, viewportWidth, viewportHeight) {
    return Math.min(Math.max(1, viewportWidth) / Math.max(1, imageWidth), Math.max(1, viewportHeight) / Math.max(1, imageHeight));
  }
  function containFitFrame(aspectRatio, viewportWidth, viewportHeight, scale = 1) {
    let width = Math.max(1, Math.min(Math.max(1, viewportWidth), Math.max(1, viewportHeight) / aspectRatio) * scale);
    return {
      height: width * aspectRatio,
      width
    };
  }
  delegateEvents(["dblclick", "pointerdown", "click"]);

  // src/components/Widgets/ProgressBar.css
  var ProgressBar_default = `.ehpeek-progress-bar::-webkit-slider-runnable-track {
  height: 0.4em;
  border-radius: 9999px;
  background: linear-gradient(
    var(--progress-bar-track-direction),
    var(--color-accent) 0 var(--progress-bar-fill),
    var(--color-track) var(--progress-bar-fill) 100%
  );
}

.ehpeek-progress-bar::-webkit-slider-thumb {
  width: 1.4em;
  height: 1.4em;
  margin-top: -0.5em;
  border: 2px solid var(--color-border);
  border-radius: 9999px;
  background: var(--color-text);
  box-shadow: 0 2px 10px var(--color-shadow-control);
  appearance: none;
  -webkit-appearance: none;
}

.ehpeek-progress-bar::-moz-range-track,
.ehpeek-progress-bar::-moz-range-progress {
  height: 0.4em;
  border-radius: 9999px;
}

.ehpeek-progress-bar::-moz-range-track {
  background: var(--color-track);
}

.ehpeek-progress-bar::-moz-range-progress {
  background: var(--color-accent);
}

.ehpeek-progress-bar::-moz-range-thumb {
  width: 1.4em;
  height: 1.4em;
  border: 2px solid var(--color-border);
  border-radius: 9999px;
  background: var(--color-text);
  box-shadow: 0 2px 10px var(--color-shadow-control);
}
`;

  // src/components/Widgets/ProgressBar.tsx
  var _tmpl$50 = /* @__PURE__ */ template("<input type=range>"), PROGRESS_BAR_CLASS = "ehpeek-progress-bar", PROGRESS_BAR_CLASS_NAME = [PROGRESS_BAR_CLASS, "w-full h-[2.4em] px-[0.6em] py-0 m-0", "bg-transparent", "cursor-grab active:cursor-grabbing touch-none select-none", "[-webkit-appearance:none] [appearance:none]", "[--progress-bar-fill:0%] [--progress-bar-track-direction:to_right]", "[accent-color:var(--color-text)]"].join(" ");
  registerGlobalStyle(PROGRESS_BAR_CLASS, ProgressBar_default);
  function ProgressBar(props) {
    let input2;
    createEffect(() => {
      let direction = props.direction ?? "ltr";
      input2.min = String(props.min), input2.max = String(Math.max(1, props.max ?? props.min)), input2.step = String(props.step), input2.dir = direction, input2.style.setProperty("--progress-bar-track-direction", direction === "rtl" ? "to left" : "to right"), input2.style.setProperty("--progress-bar-fill", `${Math.min(100, Math.max(0, props.fillPercent ?? 0))}%`), !props.keepInputValue && props.value !== void 0 && (input2.value = String(props.value));
    });
    let currentValue = (event) => Number(event.currentTarget.value || "");
    return (() => {
      var _el$ = _tmpl$50();
      return _el$.addEventListener("pointercancel", (event) => {
        props.onCommit?.(currentValue(event));
      }), _el$.$$pointerup = (event) => {
        props.onCommit?.(currentValue(event));
      }, _el$.addEventListener("change", (event) => {
        props.onCommit?.(currentValue(event));
      }), _el$.$$input = (event) => {
        props.onInput?.(currentValue(event));
      }, _el$.$$pointerdown = (event) => {
        props.onPointerDown?.(event);
      }, use((element) => {
        input2 = element, element.min = String(props.min), element.max = String(Math.max(1, props.max ?? props.min)), element.step = String(props.step), element.value = String(props.value ?? props.min);
      }, _el$), createRenderEffect((_p$) => {
        var _v$ = `${PROGRESS_BAR_CLASS_NAME}${props.class ? ` ${props.class}` : ""}`, _v$2 = String(props.min), _v$3 = String(Math.max(1, props.max ?? props.min)), _v$4 = String(props.step), _v$5 = props.direction ?? "ltr";
        return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "min", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "max", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$, "step", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$, "dir", _p$.i = _v$5), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0
      }), _el$;
    })();
  }
  delegateEvents(["pointerdown", "input", "pointerup"]);

  // src/components/Reader/Toolbar.tsx
  var _tmpl$51 = /* @__PURE__ */ template("<div><button type=button></button><button type=button></button><button type=button></button><button type=button></button><button type=button></button><button type=button>"), _tmpl$215 = /* @__PURE__ */ template("<div role=status><span>"), _tmpl$312 = /* @__PURE__ */ template('<div class="grid ui-gap-md font-sans textsize-md"><details class="textsize-sm opacity-75"><summary class="cursor-pointer font-700"></summary><p class="m-0 ui-mt-sm leading-[1.4]"></p><div class="ui-mt-md flex flex-wrap items-center ui-gap-x-md ui-gap-y-sm"><span class=font-700>:'), _tmpl$411 = /* @__PURE__ */ template('<div class=contents><div><div class="flex flex-col ui-gap-sm"><button type=button></button><button type=button></button><button type=button></button></div></div><div><div><div><button type=button></button><button type=button></button><button type=button>?</button><button type=button></button></div></div></div><div></div><div class="fixed z-2 flex items-center p-0 transition-[opacity,transform] duration-160 ease-in-out safe-right-md bottom-[calc(12px+env(safe-area-inset-bottom,0px))] safe-left-md [&amp;[data-open=false]]:opacity-0 [&amp;[data-open=false]]:translate-y-[calc(100%+16px)] [&amp;[data-open=false]]:pointer-events-none">'), _tmpl$59 = /* @__PURE__ */ template('<div class="fixed z-overlay top-1/2 left-1/2 w-max max-w-[calc(100vw-32px)] -translate-x-1/2 -translate-y-1/2 pointer-events-none ui-rounded-lg bg-[var(--color-badge)] ehp-color-text ui-px-xl ui-py-lg font-sans textsize-lg font-700 leading-[1.3] whitespace-pre-line text-center shadow-xl">'), _tmpl$69 = /* @__PURE__ */ template('<div class="grid ui-gap-md"><button type=button><span class="textsize-md font-700"></span><span class="max-w-full overflow-hidden text-ellipsis whitespace-nowrap textsize-sm opacity-75"></span></button><button type=button><span class="textsize-md font-700"></span><span class="textsize-sm opacity-75">'), _tmpl$77 = /* @__PURE__ */ template('<a class="text-[var(--color-accent)] hover:underline"rel="noopener noreferrer"target=_blank>'), READER_BUTTON_CLASS = ["inline-flex ui-hit-min-w-md ui-hit-h-md items-center justify-center ui-px-md py-0 ui-rounded-md", "border border-[var(--color-border)] bg-[var(--color-control)] text-[var(--color-text)] cursor-pointer font-sans textsize-md font-700 leading-1 disabled:opacity-40 disabled:cursor-default"].join(" "), READER_TOOLBAR_BUTTON_CLASS = `${READER_BUTTON_CLASS} !w-[var(--ui-control-size-lg)] !min-w-0 !ui-px-sm flex-none`, READER_FLOATING_ACTION_CLASS = [READER_BUTTON_CLASS, "!min-w-[var(--ui-control-size-lg)] !h-[var(--ui-control-size-lg)] opacity-85 hover:opacity-100 focus-visible:opacity-100 transition-opacity duration-160"].join(" "), READER_FLOATING_ICON_ACTION_CLASS = `${READER_FLOATING_ACTION_CLASS} !w-[calc(var(--ui-control-size-lg)*2)] px-0`, READER_ICON_SIZE = "var(--ui-icon-size-md)", TIME_FORMATTER = new Intl.DateTimeFormat(void 0, {
    hour: "2-digit",
    minute: "2-digit"
  }), DOWNLOAD_OPTION_CLASS = ["flex w-full ui-hit-min-h-lg flex-col items-start justify-center ui-gap-xs ui-px-lg ui-py-md ui-rounded-md", "border border-[var(--color-border)] bg-[var(--color-control)] text-[var(--color-text)] cursor-pointer text-left", "hover:bg-[var(--color-badge)] disabled:opacity-40 disabled:cursor-default"].join(" ");
  function Toolbar(props) {
    let leftHandedControls = state.app.leftHandedControls.value, [downloadDialogPageNum, setDownloadDialogPageNum] = createSignal(null), [helpOpen, setHelpOpen] = createSignal(!1), [moreOpen, setMoreOpen] = createSignal(!1), [controlChange, setControlChange] = createSignal(null), [fullscreenToolbarTop, setFullscreenToolbarTop] = createSignal(), pageNumber, fullscreenStatus, controlChangeTimer = null, fullscreenTime = createFullscreenTime(() => props.fullscreenActive), showControlChange = (message) => {
      controlChangeTimer !== null && window.clearTimeout(controlChangeTimer), setControlChange(message), controlChangeTimer = window.setTimeout(() => {
        setControlChange(null), controlChangeTimer = null;
      }, 1200);
    };
    return onCleanup(() => {
      controlChangeTimer !== null && window.clearTimeout(controlChangeTimer);
    }), onMount(() => {
      let updateFullscreenToolbarTop = () => {
        if (!props.fullscreenActive) {
          setFullscreenToolbarTop(void 0);
          return;
        }
        let statusBottom = fullscreenStatus?.getBoundingClientRect().bottom ?? 0, pageNumberBottom = pageNumber.getBoundingClientRect().bottom;
        setFullscreenToolbarTop(`${Math.ceil(Math.max(statusBottom, pageNumberBottom) + 8)}px`);
      }, observer = new ResizeObserver(updateFullscreenToolbarTop);
      observer.observe(pageNumber), window.addEventListener("resize", updateFullscreenToolbarTop), createEffect(() => {
        props.fullscreenActive ? queueMicrotask(updateFullscreenToolbarTop) : updateFullscreenToolbarTop();
      }), onCleanup(() => {
        observer.disconnect(), window.removeEventListener("resize", updateFullscreenToolbarTop);
      });
    }), createEffect(() => {
      props.open || setMoreOpen(!1);
    }), createEffect(() => {
      let pageNum = downloadDialogPageNum();
      pageNum !== null && pageNum !== props.progress.pageNum && setDownloadDialogPageNum(null);
    }), createEffect(() => {
      if (downloadDialogPageNum() === null)
        return;
      let closeOnEscape = (event) => {
        event.key === "Escape" && (event.preventDefault(), event.stopPropagation(), setDownloadDialogPageNum(null));
      };
      window.addEventListener("keydown", closeOnEscape, !0), onCleanup(() => window.removeEventListener("keydown", closeOnEscape, !0));
    }), (() => {
      var _el$ = _tmpl$411(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.nextSibling, _el$7 = _el$2.nextSibling, _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _el$1 = _el$0.nextSibling, _el$10 = _el$1.nextSibling, _el$11 = _el$10.nextSibling, _el$19 = _el$7.nextSibling, _el$22 = _el$19.nextSibling;
      addEventListener(_el$2, "wheel", stopEvent), addEventListener(_el$2, "pointerdown", stopEvent, !0), addEventListener(_el$2, "click", stopEvent, !0), className(_el$2, "fixed z-2 flex justify-end transition-[opacity,transform] duration-160 ease-in-out " + (leftHandedControls ? "safe-left-md " : "safe-right-md ") + "bottom-[calc(var(--ui-control-size-lg)*2+var(--ui-font-size-lg)*2.4+env(safe-area-inset-bottom,0px))] [&[data-open=false]]:opacity-0 [&[data-open=false]]:translate-y-[calc(100%+16px)] [&[data-open=false]]:pointer-events-none"), _el$4.$$click = () => props.callbacks.onOpenScrollPreviewClick(), className(_el$4, READER_FLOATING_ICON_ACTION_CLASS), insert(_el$4, createComponent(Icon2, {
        name: "grid",
        size: READER_ICON_SIZE
      })), _el$5.$$click = () => props.callbacks.onFullscreenClick(), className(_el$5, READER_FLOATING_ICON_ACTION_CLASS), insert(_el$5, createComponent(Icon2, {
        get name() {
          return props.fullscreenActive ? "fullscreen-exit" : "fullscreen";
        },
        size: READER_ICON_SIZE
      })), _el$6.$$click = () => setDownloadDialogPageNum(props.progress.pageNum), className(_el$6, READER_FLOATING_ICON_ACTION_CLASS), insert(_el$6, createComponent(Icon2, {
        name: "download",
        size: READER_ICON_SIZE
      })), addEventListener(_el$7, "wheel", stopEvent), addEventListener(_el$7, "pointerdown", stopEvent, !0), addEventListener(_el$7, "click", stopEvent, !0), className(_el$7, "ehpeek-reader-toolbar fixed z-3 flex justify-end pointer-events-none top-[calc(10px+env(safe-area-inset-top,0px))] " + (leftHandedControls ? "safe-left-sm " : "safe-right-sm ")), className(_el$9, `flex flex-row ui-gap-md${leftHandedControls ? " flex-row-reverse" : ""}`), _el$0.$$click = () => props.callbacks.onOpenOriginalPageClick(), className(_el$0, READER_TOOLBAR_BUTTON_CLASS), insert(_el$0, createComponent(Icon2, {
        name: "external-link",
        size: READER_ICON_SIZE
      })), _el$1.$$click = () => setMoreOpen((open) => !open), className(_el$1, READER_TOOLBAR_BUTTON_CLASS), insert(_el$1, createComponent(Icon2, {
        name: "book-open",
        size: READER_ICON_SIZE
      })), _el$10.$$click = () => setHelpOpen(!0), className(_el$10, READER_TOOLBAR_BUTTON_CLASS), _el$11.$$click = () => props.callbacks.onCloseClick(), className(_el$11, READER_TOOLBAR_BUTTON_CLASS), insert(_el$11, createComponent(Icon2, {
        name: "close",
        size: READER_ICON_SIZE
      })), insert(_el$8, createComponent(Show, {
        get when() {
          return moreOpen();
        },
        get children() {
          var _el$12 = _tmpl$51(), _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, _el$15 = _el$14.nextSibling, _el$16 = _el$15.nextSibling, _el$17 = _el$16.nextSibling, _el$18 = _el$17.nextSibling;
          return className(_el$12, `flex w-[calc(var(--ui-control-size-lg)*4+var(--ui-space-md)*4)] flex-row flex-wrap ui-gap-md${leftHandedControls ? " flex-row-reverse" : ""}`), _el$13.$$click = () => {
            let navigationMode = props.controls.navigationMode === "scroll" ? "paged" : "scroll";
            props.callbacks.onControlsChange({
              ...props.controls,
              navigationMode
            }), showControlChange(navigationMode === "paged" ? i18n_default.reader.pagedMode : i18n_default.reader.scrollMode);
          }, className(_el$13, READER_TOOLBAR_BUTTON_CLASS), insert(_el$13, createComponent(Icon2, {
            get name() {
              return props.controls.navigationMode === "paged" ? "page" : "scroll-continuous";
            },
            size: READER_ICON_SIZE
          })), _el$14.$$click = () => {
            let direction = props.controls.direction === "rtl" ? "ltr" : props.controls.direction === "ltr" ? "ttb" : "rtl";
            props.callbacks.onControlsChange({
              ...props.controls,
              direction
            }), showControlChange(direction === "rtl" ? i18n_default.reader.directionRtl : direction === "ltr" ? i18n_default.reader.directionLtr : i18n_default.reader.directionTtb);
          }, className(_el$14, READER_TOOLBAR_BUTTON_CLASS), insert(_el$14, createComponent(Icon2, {
            get name() {
              return memo(() => props.controls.direction === "rtl")() ? "arrow-left" : props.controls.direction === "ltr" ? "arrow-right" : "arrow-down";
            },
            size: READER_ICON_SIZE
          })), _el$15.$$click = () => {
            let pageLayout = props.controls.pageLayout === "single" ? "double" : "single";
            props.callbacks.onControlsChange({
              ...props.controls,
              pageLayout
            }), showControlChange(pageLayout === "double" ? i18n_default.reader.doublePageMode : i18n_default.reader.singlePageMode);
          }, className(_el$15, READER_TOOLBAR_BUTTON_CLASS), insert(_el$15, () => props.controls.pageLayout === "double" ? "2P" : "1P"), _el$16.$$click = () => {
            let firstPageSeparate = !props.controls.firstPageSeparate;
            props.callbacks.onControlsChange({
              ...props.controls,
              firstPageSeparate
            }), showControlChange(firstPageSeparate ? i18n_default.reader.pairSecondAndThirdPages : i18n_default.reader.pairFirstAndSecondPages);
          }, className(_el$16, READER_TOOLBAR_BUTTON_CLASS), insert(_el$16, () => props.controls.firstPageSeparate ? "2+3" : "1+2"), _el$17.$$click = () => {
            let rightTapAction = props.controls.rightTapAction === "previous" ? "next" : "previous";
            props.callbacks.onControlsChange({
              ...props.controls,
              rightTapAction
            }), showControlChange(rightTapAction === "previous" ? i18n_default.reader.rightTapPrevious : i18n_default.reader.rightTapNext);
          }, className(_el$17, READER_TOOLBAR_BUTTON_CLASS), insert(_el$17, () => props.controls.rightTapAction === "previous" ? "R-" : "R+"), _el$18.$$click = () => props.callbacks.onViewportAdjustClick(), className(_el$18, READER_TOOLBAR_BUTTON_CLASS), insert(_el$18, createComponent(Icon2, {
            name: "viewport",
            size: READER_ICON_SIZE
          })), createRenderEffect((_p$) => {
            var _v$ = props.controls.navigationMode === "scroll" ? i18n_default.reader.scrollMode : i18n_default.reader.pagedMode, _v$2 = props.controls.navigationMode === "scroll" ? i18n_default.reader.scrollMode : i18n_default.reader.pagedMode, _v$3 = props.controls.direction === "rtl" ? i18n_default.reader.directionRtl : props.controls.direction === "ltr" ? i18n_default.reader.directionLtr : i18n_default.reader.directionTtb, _v$4 = props.controls.pageLayout === "double" ? i18n_default.reader.doublePageMode : i18n_default.reader.singlePageMode, _v$5 = props.controls.navigationMode !== "paged", _v$6 = props.controls.firstPageSeparate, _v$7 = props.controls.firstPageSeparate ? i18n_default.reader.pairSecondAndThirdPages : i18n_default.reader.pairFirstAndSecondPages, _v$8 = props.controls.firstPageSeparate ? i18n_default.reader.pairSecondAndThirdPages : i18n_default.reader.pairFirstAndSecondPages, _v$9 = props.controls.navigationMode !== "paged" || props.controls.pageLayout !== "double", _v$0 = props.controls.rightTapAction === "previous" ? i18n_default.reader.rightTapPrevious : i18n_default.reader.rightTapNext, _v$1 = i18n_default.reader.adjustScrollViewport, _v$10 = i18n_default.reader.adjustScrollViewport, _v$11 = props.controls.navigationMode !== "scroll";
            return _v$ !== _p$.e && setAttribute(_el$13, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$13, "title", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$14, "aria-label", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$15, "aria-label", _p$.o = _v$4), _v$5 !== _p$.i && (_el$15.disabled = _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$16, "aria-pressed", _p$.n = _v$6), _v$7 !== _p$.s && setAttribute(_el$16, "aria-label", _p$.s = _v$7), _v$8 !== _p$.h && setAttribute(_el$16, "title", _p$.h = _v$8), _v$9 !== _p$.r && (_el$16.disabled = _p$.r = _v$9), _v$0 !== _p$.d && setAttribute(_el$17, "aria-label", _p$.d = _v$0), _v$1 !== _p$.l && setAttribute(_el$18, "aria-label", _p$.l = _v$1), _v$10 !== _p$.u && setAttribute(_el$18, "title", _p$.u = _v$10), _v$11 !== _p$.c && (_el$18.disabled = _p$.c = _v$11), _p$;
          }, {
            e: void 0,
            t: void 0,
            a: void 0,
            o: void 0,
            i: void 0,
            n: void 0,
            s: void 0,
            h: void 0,
            r: void 0,
            d: void 0,
            l: void 0,
            u: void 0,
            c: void 0
          }), _el$12;
        }
      }), null);
      var _ref$ = pageNumber;
      return typeof _ref$ == "function" ? use(_ref$, _el$19) : pageNumber = _el$19, className(_el$19, "ehpeek-reader-page-number fixed z-3 pointer-events-none top-[calc(10px+env(safe-area-inset-top,0px))] " + (leftHandedControls ? "safe-right-sm left-auto " : "safe-left-sm right-auto ") + "min-w-0 max-w-[calc(100vw-20px)] ui-py-xs ui-px-md ui-rounded-md bg-[var(--color-badge)] ehp-color-text font-sans textsize-md font-600 leading-[1.4] whitespace-nowrap " + (leftHandedControls ? "text-right" : "text-left")), insert(_el$19, () => pageNumberText(props.progress.pageNum, props.progress.totalPages, props.controls.navigationMode, props.controls.pageLayout, props.controls.firstPageSeparate)), insert(_el$, createComponent(Show, {
        get when() {
          return props.fullscreenActive;
        },
        get children() {
          var _el$20 = _tmpl$215(), _el$21 = _el$20.firstChild, _ref$2 = fullscreenStatus;
          return typeof _ref$2 == "function" ? use(_ref$2, _el$20) : fullscreenStatus = _el$20, className(_el$20, "ehpeek-reader-fullscreen-status fixed z-3 flex items-center ui-gap-sm pointer-events-none top-[calc(10px+env(safe-area-inset-top,0px))] " + (leftHandedControls ? "safe-right-sm " : "safe-left-sm ") + "ui-py-xs ui-px-md ui-rounded-md bg-[var(--color-badge)] ehp-color-text font-sans textsize-md font-600 leading-[1.4] whitespace-nowrap"), insert(_el$21, fullscreenTime), _el$20;
        }
      }), _el$22), insert(_el$, createComponent(Show, {
        get when() {
          return controlChange();
        },
        keyed: !0,
        children: (message) => (() => {
          var _el$30 = _tmpl$59();
          return insert(_el$30, message), _el$30;
        })()
      }), _el$22), addEventListener(_el$22, "wheel", stopEvent), addEventListener(_el$22, "pointerdown", stopEvent, !0), addEventListener(_el$22, "click", stopEvent, !0), insert(_el$22, createComponent(ProgressBar, {
        class: "textsize-lg",
        get direction() {
          return props.controls.direction === "rtl" ? "rtl" : "ltr";
        },
        get fillPercent() {
          return progressFillPercent(props.progress);
        },
        get keepInputValue() {
          return props.progress.keepInputValue;
        },
        get max() {
          return Math.max(1, props.progress.maxProgressPageNum);
        },
        min: 1,
        step: 1,
        get value() {
          return props.progress.pageNum;
        },
        get onPointerDown() {
          return props.callbacks.onProgressPointerDown;
        },
        get onInput() {
          return props.callbacks.onProgressInput;
        },
        get onCommit() {
          return props.callbacks.onProgressCommit;
        }
      })), insert(_el$, createComponent(Show, {
        get when() {
          return memo(() => downloadDialogPageNum() !== null)() && props.downloadInfos.length > 0;
        },
        get children() {
          return createComponent(Dialog, {
            bodyClass: "ui-pt-lg ui-px-lg",
            get label() {
              return i18n_default.reader.download;
            },
            onClose: () => setDownloadDialogPageNum(null),
            get title() {
              return `${i18n_default.reader.download} · ${props.downloadInfos.map((info) => info.pageNum).join(", ")}`;
            },
            variant: "reader",
            width: "lg",
            get children() {
              var _el$23 = _tmpl$312(), _el$24 = _el$23.firstChild, _el$25 = _el$24.firstChild, _el$26 = _el$25.nextSibling, _el$27 = _el$26.nextSibling, _el$28 = _el$27.firstChild, _el$29 = _el$28.firstChild;
              return insert(_el$23, createComponent(For, {
                get each() {
                  return props.downloadInfos;
                },
                children: (downloadInfo) => (() => {
                  var _el$31 = _tmpl$69(), _el$32 = _el$31.firstChild, _el$33 = _el$32.firstChild, _el$34 = _el$33.nextSibling, _el$35 = _el$32.nextSibling, _el$36 = _el$35.firstChild, _el$37 = _el$36.nextSibling;
                  return _el$32.$$click = () => {
                    startImageDownload(downloadInfo.currentImageUrl, downloadInfo.currentFileName) && setDownloadDialogPageNum(null);
                  }, className(_el$32, DOWNLOAD_OPTION_CLASS), insert(_el$33, () => `${i18n_default.reader.downloadDisplayedImage} · ${downloadInfo.pageNum}`), insert(_el$34, () => downloadInfo.currentFileName), _el$35.$$click = () => {
                    downloadInfo.originalImageUrl && startImageDownload(downloadInfo.originalImageUrl, downloadInfo.originalFileName) && setDownloadDialogPageNum(null);
                  }, className(_el$35, DOWNLOAD_OPTION_CLASS), insert(_el$36, () => `${i18n_default.reader.downloadOriginalImage} · ${downloadInfo.pageNum}`), insert(_el$37, (() => {
                    var _c$ = memo(() => !!downloadInfo.originalImageUrl);
                    return () => _c$() ? i18n_default.reader.originalImageSource : i18n_default.reader.originalImageUnavailable;
                  })()), createRenderEffect(() => _el$35.disabled = !downloadInfo.originalImageUrl), _el$31;
                })()
              }), _el$24), insert(_el$25, () => i18n_default.reader.downloadHelpLabel), insert(_el$26, () => i18n_default.reader.downloadHelp), insert(_el$28, () => i18n_default.reader.openImage, _el$29), insert(_el$27, createComponent(For, {
                get each() {
                  return props.downloadInfos;
                },
                children: (downloadInfo) => [(() => {
                  var _el$38 = _tmpl$77();
                  return insert(_el$38, () => `${i18n_default.reader.displayedImageShort} ${downloadInfo.pageNum}`), createRenderEffect(() => setAttribute(_el$38, "href", downloadInfo.currentImageUrl)), _el$38;
                })(), createComponent(Show, {
                  get when() {
                    return downloadInfo.originalImageUrl;
                  },
                  children: (originalImageUrl) => (() => {
                    var _el$39 = _tmpl$77();
                    return insert(_el$39, () => `${i18n_default.reader.originalImageShort} ${downloadInfo.pageNum}`), createRenderEffect(() => setAttribute(_el$39, "href", originalImageUrl())), _el$39;
                  })()
                })]
              }), null), _el$23;
            }
          });
        }
      }), null), insert(_el$, createComponent(Show, {
        get when() {
          return helpOpen();
        },
        get children() {
          return createComponent(InteractionHelp, {
            variant: "reader",
            onClose: () => setHelpOpen(!1)
          });
        }
      }), null), createRenderEffect((_p$) => {
        var _v$12 = String(props.open), _v$13 = i18n_default.gallery.scrollPreview, _v$14 = i18n_default.gallery.scrollPreview, _v$15 = props.fullscreenActive ? i18n_default.reader.exitFullscreen : i18n_default.reader.fullscreen, _v$16 = props.fullscreenActive ? i18n_default.reader.exitFullscreen : i18n_default.reader.fullscreen, _v$17 = props.downloadInfos.length === 0, _v$18 = i18n_default.reader.download, _v$19 = i18n_default.reader.download, _v$20 = fullscreenToolbarTop(), _v$21 = `flex flex-col ${leftHandedControls ? "items-start" : "items-end"} ui-gap-md pointer-events-auto${props.open ? "" : " !hidden"}`, _v$22 = i18n_default.reader.readingOptions, _v$23 = i18n_default.reader.readingOptions, _v$24 = moreOpen(), _v$25 = i18n_default.help.title, _v$26 = i18n_default.help.title, _v$27 = i18n_default.common.actions.close, _v$28 = i18n_default.common.actions.close, _v$29 = props.controls.navigationMode === "scroll" && !props.open && !props.fullscreenActive, _v$30 = String(props.open);
        return _v$12 !== _p$.e && setAttribute(_el$2, "data-open", _p$.e = _v$12), _v$13 !== _p$.t && setAttribute(_el$4, "aria-label", _p$.t = _v$13), _v$14 !== _p$.a && setAttribute(_el$4, "title", _p$.a = _v$14), _v$15 !== _p$.o && setAttribute(_el$5, "aria-label", _p$.o = _v$15), _v$16 !== _p$.i && setAttribute(_el$5, "title", _p$.i = _v$16), _v$17 !== _p$.n && (_el$6.disabled = _p$.n = _v$17), _v$18 !== _p$.s && setAttribute(_el$6, "aria-label", _p$.s = _v$18), _v$19 !== _p$.h && setAttribute(_el$6, "title", _p$.h = _v$19), _v$20 !== _p$.r && setStyleProperty(_el$7, "top", _p$.r = _v$20), _v$21 !== _p$.d && className(_el$8, _p$.d = _v$21), _v$22 !== _p$.l && setAttribute(_el$1, "aria-label", _p$.l = _v$22), _v$23 !== _p$.u && setAttribute(_el$1, "title", _p$.u = _v$23), _v$24 !== _p$.c && setAttribute(_el$1, "aria-expanded", _p$.c = _v$24), _v$25 !== _p$.w && setAttribute(_el$10, "aria-label", _p$.w = _v$25), _v$26 !== _p$.m && setAttribute(_el$10, "title", _p$.m = _v$26), _v$27 !== _p$.f && setAttribute(_el$11, "aria-label", _p$.f = _v$27), _v$28 !== _p$.y && setAttribute(_el$11, "title", _p$.y = _v$28), _v$29 !== _p$.g && (_el$19.hidden = _p$.g = _v$29), _v$30 !== _p$.p && setAttribute(_el$22, "data-open", _p$.p = _v$30), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0,
        h: void 0,
        r: void 0,
        d: void 0,
        l: void 0,
        u: void 0,
        c: void 0,
        w: void 0,
        m: void 0,
        f: void 0,
        y: void 0,
        g: void 0,
        p: void 0
      }), _el$;
    })();
  }
  function startImageDownload(url, name) {
    try {
      return GM_download({
        url,
        ...name ? {
          name
        } : {},
        onerror: (error) => {
          console.error("[ehpeek]", error), window.alert(i18n_default.errors.downloadFailed);
        }
      }), !0;
    } catch (error) {
      return console.error("[ehpeek]", error), window.alert(i18n_default.errors.downloadFailed), !1;
    }
  }
  function createFullscreenTime(enabled) {
    let [time, setTime] = createSignal(TIME_FORMATTER.format(/* @__PURE__ */ new Date()));
    return createEffect(() => {
      if (!enabled())
        return;
      let updateTime = () => setTime(TIME_FORMATTER.format(/* @__PURE__ */ new Date()));
      updateTime();
      let interval = null, timeout = window.setTimeout(() => {
        updateTime(), interval = window.setInterval(updateTime, 6e4);
      }, 6e4 - Date.now() % 6e4);
      onCleanup(() => {
        window.clearTimeout(timeout), interval !== null && window.clearInterval(interval);
      });
    }), time;
  }
  function progressFillPercent(progress) {
    let max = Math.max(1, progress.maxProgressPageNum), value = Math.min(max, Math.max(1, progress.pageNum));
    return max > 1 ? (value - 1) / (max - 1) * 100 : 100;
  }
  function pageNumberText(pageNum, totalPages, navigationMode, pageLayout, firstPageSeparate) {
    if (totalPages && pageNum === totalPages + 1)
      return i18n_default.reader.endPage;
    let doublePage = navigationMode === "paged" && pageLayout === "double" && !(firstPageSeparate && pageNum === 1);
    if (!totalPages)
      return doublePage ? `${pageNum}–${pageNum + 1}` : String(pageNum);
    let doublePageEnd = Math.min(totalPages, pageNum + 1);
    return doublePage && doublePageEnd > pageNum ? `${pageNum}–${doublePageEnd} / ${totalPages}` : `${pageNum} / ${totalPages}`;
  }
  delegateEvents(["click", "pointerdown"]);

  // src/components/Reader/ZoomOverlay.tsx
  var _tmpl$60 = /* @__PURE__ */ template('<div class="fixed inset-0 z-4 flex items-center justify-center overflow-hidden ehp-color-reader pointer-events-none"><img class="block max-w-screen max-h-screen object-contain origin-center select-none will-change-transform [-webkit-user-drag:none]">'), MIN_SCALE = 1, MAX_SCALE = 5, CLOSE_SCALE = 1.02;
  function ZoomOverlay(props) {
    let [transform, setTransform] = createSignal("translate3d(0px, 0px, 0) scale(1)"), element, scale = 1, requestedScale = 1, closeScale = CLOSE_SCALE, minScale = MIN_SCALE, maxScale = MAX_SCALE, offsetX = 0, offsetY = 0, pinchStartScale = 1, pinchStartOffsetX = 0, pinchStartOffsetY = 0, pinchStartCenterX = 0, pinchStartCenterY = 0, dragStartOffsetX = 0, dragStartOffsetY = 0, renderTransform = () => {
      setTransform(`translate3d(${offsetX}px, ${offsetY}px, 0) scale(${scale})`);
    }, startPinch = (pinch) => {
      pinchStartScale = scale, pinchStartOffsetX = offsetX, pinchStartOffsetY = offsetY, pinchStartCenterX = pinch.centerX, pinchStartCenterY = pinch.centerY;
    }, actions = {
      reset(reset2) {
        scale = Math.max(0.01, reset2.scale), requestedScale = scale, closeScale = scale * CLOSE_SCALE, minScale = Math.min(MIN_SCALE, scale), maxScale = Math.max(MAX_SCALE, scale * MAX_SCALE), offsetX = 0, offsetY = 0, startPinch(reset2), renderTransform();
      },
      startPinch,
      movePinch(pinch) {
        if (!props.image)
          return;
        requestedScale = pinchStartScale * pinch.scale, scale = clamp(requestedScale, minScale, maxScale);
        let rect = element.getBoundingClientRect(), viewportCenterX = rect.left + rect.width / 2, viewportCenterY = rect.top + rect.height / 2, ratio = scale / pinchStartScale;
        offsetX = pinch.centerX - viewportCenterX - (pinchStartCenterX - viewportCenterX - pinchStartOffsetX) * ratio, offsetY = pinch.centerY - viewportCenterY - (pinchStartCenterY - viewportCenterY - pinchStartOffsetY) * ratio, renderTransform();
      },
      moveWheel(wheel) {
        if (!props.image)
          return;
        let nextScale = clamp(scale * Math.exp(-clamp(wheel.delta, -100, 100) * 25e-4), minScale, maxScale);
        if (nextScale === scale)
          return;
        let rect = element.getBoundingClientRect(), viewportCenterX = rect.left + rect.width / 2, viewportCenterY = rect.top + rect.height / 2, ratio = nextScale / scale;
        offsetX = wheel.centerX - viewportCenterX - (wheel.centerX - viewportCenterX - offsetX) * ratio, offsetY = wheel.centerY - viewportCenterY - (wheel.centerY - viewportCenterY - offsetY) * ratio, scale = nextScale, requestedScale = nextScale, renderTransform();
      },
      endPinch() {
        if (requestedScale <= closeScale) {
          props.onClose();
          return;
        }
        renderTransform();
      },
      startDrag() {
        dragStartOffsetX = offsetX, dragStartOffsetY = offsetY;
      },
      moveDrag(move) {
        props.image && (offsetX = dragStartOffsetX + move.dx, offsetY = dragStartOffsetY + move.dy, renderTransform());
      }
    };
    return untrack(() => props.actionsRef(actions)), (() => {
      var _el$ = _tmpl$60(), _el$2 = _el$.firstChild, _ref$ = element;
      return typeof _ref$ == "function" ? use(_ref$, _el$) : element = _el$, createRenderEffect((_p$) => {
        var _v$ = !props.image, _v$2 = props.image ? "" : "none", _v$3 = props.image?.imageUrl, _v$4 = props.image ? `Page ${props.image.pageNum}` : "", _v$5 = props.image?.width ?? void 0, _v$6 = props.image?.height ?? void 0, _v$7 = transform();
        return _v$ !== _p$.e && (_el$.hidden = _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "display", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$2, "src", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$2, "alt", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$2, "width", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$2, "height", _p$.n = _v$6), _v$7 !== _p$.s && setStyleProperty(_el$2, "transform", _p$.s = _v$7), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0,
        o: void 0,
        i: void 0,
        n: void 0,
        s: void 0
      }), _el$;
    })();
  }

  // src/components/Reader/session.ts
  var DEFAULT_WINDOW_SIZE = 10, ReaderSession = class {
    constructor(options) {
      this.animationFrames = /* @__PURE__ */ new Set();
      this.timers = /* @__PURE__ */ new Set();
      this.disposed = !1;
      this.imageQueue = new PriorityLoadQueue(
        options.concurrentLoads
      );
      let readerControls2 = currentReaderControlsState(), navigationMode = readerControls2.navigationMode.value, initialControls = {
        navigationMode,
        direction: navigationMode === "scroll" ? readerControls2.scrollDirection.value : readerControls2.pagedDirection.value,
        firstPageSeparate: !1,
        pageLayout: readerControls2.pageLayout.value,
        rightTapAction: readerControls2.rightTapAction.value
      }, [controls, setControls] = createSignal(initialControls), initialPageNum = initialControls.navigationMode === "paged" && initialControls.pageLayout === "double" ? doublePagePairStart(initialPageNumber(options), initialControls.firstPageSeparate) : initialPageNumber(options), [toolbarOpen, setToolbarOpen] = createSignal(!1), [viewportWindow, setViewportWindow] = createSignal(
        initialViewportWindow(options, initialPageNum)
      ), [zoomImage, setZoomImage] = createSignal(null), [currentPageNum, setCurrentPageNum] = createSignal(initialPageNum), [direction, setDirection] = createSignal(1), [downloadInfos, setDownloadInfos] = createSignal([]), [maxProgressPageNum, setMaxProgressPageNum] = createSignal(initialMaxProgressPageNumber(options)), [progressInputActive, setProgressInputActive] = createSignal(!1), [scrollBarVisible, setScrollBarVisible] = createSignal(!1), [scrollBarExpanded, setScrollBarExpanded] = createSignal(!1), [scrollViewportAdjusting, setScrollViewportAdjusting] = createSignal(!1), [scrollViewportTtbScale, setScrollViewportTtbScale] = createSignal(
        state.reader.scrollTtbScale.value
      ), [scrollViewportHorizontalScale, setScrollViewportHorizontalScale] = createSignal(
        state.reader.scrollHorizontalScale.value
      ), [scrollFitImageSize, setScrollFitImageSize] = createSignal(null), [readerViewportWidth, setReaderViewportWidth] = createSignal(Math.max(1, window.innerWidth)), [readerViewportHeight, setReaderViewportHeight] = createSignal(Math.max(1, window.innerHeight)), scrollViewportSizeScale = () => controls().direction === "ttb" ? scrollViewportTtbScale() : scrollViewportHorizontalScale(), setScrollViewportSizeScale = (scale) => {
        controls().direction === "ttb" ? setScrollViewportTtbScale(scale) : setScrollViewportHorizontalScale(scale);
      }, scrollFitScale = () => {
        let imageSize = scrollFitImageSize();
        return imageSize ? containFitScale(
          imageSize.width,
          imageSize.height,
          readerViewportWidth(),
          readerViewportHeight()
        ) : null;
      };
      this.state = {
        navi: {
          currentPageNum,
          direction,
          setCurrentPageNum,
          setDirection,
          setViewportWindow,
          viewportWindow,
          leftDragDelta: () => controls().direction === "rtl" ? -1 : 1,
          leftTapDelta: () => controls().rightTapAction === "previous" ? 1 : -1,
          rightDragDelta: () => controls().direction === "rtl" ? 1 : -1,
          rightTapDelta: () => controls().rightTapAction === "previous" ? -1 : 1,
          downloadInfos,
          maxProgressPageNum,
          progressInputActive,
          setDownloadInfos,
          setMaxProgressPageNum,
          setProgressInputActive
        },
        ctrls: { update: setControls, value: controls },
        toolbar: {
          open: toolbarOpen,
          toggle: () => setToolbarOpen((open) => !open)
        },
        scrollBar: {
          expanded: scrollBarExpanded,
          updateExpanded: setScrollBarExpanded,
          updateVisible: setScrollBarVisible,
          visible: scrollBarVisible
        },
        scrollViewport: {
          adjusting: scrollViewportAdjusting,
          scaleMode: () => scrollViewportSizeScale() === null ? "fit" : scrollViewportSizeScale() === "one-to-one" ? "one-to-one" : "custom",
          scalePercent: () => {
            let sizeScale = scrollViewportSizeScale();
            if (sizeScale === "one-to-one")
              return 100;
            let fitScale = scrollFitScale();
            return fitScale ? (sizeScale ?? 1) * fitScale * 100 : null;
          },
          fitImageSize: scrollFitImageSize,
          fitScale: scrollFitScale,
          setAdjusting: setScrollViewportAdjusting,
          setFitImageSize: setScrollFitImageSize,
          setViewportWidth: setReaderViewportWidth,
          setSizeScale: setScrollViewportSizeScale,
          setViewportHeight: setReaderViewportHeight,
          viewportWidth: readerViewportWidth,
          viewportHeight: readerViewportHeight,
          sizeScale: scrollViewportSizeScale
        },
        overlay: { image: zoomImage, update: setZoomImage }
      };
    }
    setTimeout(callback, delay) {
      let timer = window.setTimeout(() => {
        this.timers.delete(timer), callback();
      }, delay);
      return this.timers.add(timer), timer;
    }
    clearTimeout(timer) {
      timer !== null && (window.clearTimeout(timer), this.timers.delete(timer));
    }
    requestAnimationFrame(callback) {
      let frame = window.requestAnimationFrame((time) => {
        this.animationFrames.delete(frame), callback(time);
      });
      return this.animationFrames.add(frame), frame;
    }
    cancelAnimationFrame(frame) {
      frame !== null && (window.cancelAnimationFrame(frame), this.animationFrames.delete(frame));
    }
    dispose() {
      if (!this.disposed) {
        this.disposed = !0;
        for (let timer of this.timers)
          window.clearTimeout(timer);
        for (let frame of this.animationFrames)
          window.cancelAnimationFrame(frame);
        this.imageQueue.dispose(), this.timers.clear(), this.animationFrames.clear();
      }
    }
  };
  function initialViewportWindow(options, initialPageNum) {
    return {
      currentPageNum: initialPageNum,
      windowSize: options.renderWindowSize ?? DEFAULT_WINDOW_SIZE,
      totalPages: options.totalPages && options.totalPages > 0 ? options.totalPages : void 0,
      pages: /* @__PURE__ */ new Map()
    };
  }
  function doublePagePairStart(pageNum, firstPageSeparate) {
    return firstPageSeparate ? pageNum <= 1 ? 1 : pageNum - pageNum % 2 : pageNum % 2 === 0 ? pageNum - 1 : pageNum;
  }
  function initialPageNumber(options) {
    let totalPages = options.totalPages && options.totalPages > 0 ? options.totalPages : Number.MAX_SAFE_INTEGER;
    return clamp(Math.round(options.initialPageNum), 1, totalPages);
  }
  function initialMaxProgressPageNumber(options) {
    return options.totalPages && options.totalPages > 0 ? options.totalPages + 1 : 1;
  }

  // src/components/Reader/ScrollBar.tsx
  function ReaderScrollBar(props) {
    return createComponent(PositionBar, {
      ariaLabel: "Reader position",
      axis: "vertical",
      get currentValue() {
        return props.currentPage;
      },
      get expanded() {
        return props.expanded;
      },
      get maxValue() {
        return props.totalPages;
      },
      get onCommit() {
        return props.callbacks.onProgressCommit;
      },
      get onInput() {
        return props.callbacks.onProgressInput;
      },
      get onPointerDown() {
        return props.callbacks.onProgressPointerDown;
      },
      get pixelScale() {
        return props.pixelScale;
      },
      position: "fixed",
      trackClickEnabled: !1,
      trackVisible: !1,
      get visible() {
        return props.visible;
      },
      visibleValueCount: 1
    });
  }

  // src/components/Reader/ViewportCanvas.tsx
  var _tmpl$61 = /* @__PURE__ */ template('<div class="absolute inset-0 z-2 touch-none select-none">'), _tmpl$216 = /* @__PURE__ */ template("<span>"), _tmpl$313 = /* @__PURE__ */ template('<div class="fixed bottom-[calc(12px+env(safe-area-inset-bottom,0px))] left-1/2 z-3 flex w-[min(680px,calc(100vw-24px))] -translate-x-1/2 flex-col items-center ui-gap-sm ui-rounded-lg border border-[var(--color-reader-border)] bg-[var(--color-control)] ui-p-sm shadow-xl [container-type:inline-size]"role=toolbar><div class="grid w-full grid-cols-[max-content_minmax(var(--ui-control-size-md),1fr)_var(--ui-control-size-xl)_var(--ui-control-size-xl)] viewport-toolbar-compact:grid-cols-[max-content_minmax(0,1fr)_var(--ui-control-size-lg)_var(--ui-control-size-lg)] items-center justify-center ui-gap-sm"><span class="flex w-full flex-col items-center justify-center text-center font-mono textsize-sm font-600 leading-[1.05]"><span></span></span><input type=range class="w-full min-w-0 accent-[var(--color-reader-accent)]"min=10 max=500 step=1><button type=button></button><button type=button>1:1</button></div><div class="grid w-full max-w-full grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)_minmax(0,1fr)] items-stretch justify-center ui-gap-sm"><button type=button></button><button type=button></button><button type=button>'), _tmpl$412 = /* @__PURE__ */ template('<div class="fixed inset-0 z-1">'), MIN_SCALE_PERCENT = 10, MAX_SCALE_PERCENT = 500;
  function ViewportCanvas(props) {
    let pointers = /* @__PURE__ */ new Map(), pinchStart = null, interactionLayer, sliderPercent = () => Math.min(MAX_SCALE_PERCENT, Math.max(MIN_SCALE_PERCENT, props.scalePercent ?? 100)), clampScale = (scale) => Math.min(MAX_SCALE_PERCENT / 100, Math.max(MIN_SCALE_PERCENT / 100, scale)), stopInteraction = (event) => {
      event.preventDefault(), event.stopPropagation();
    }, endPointer = (event) => {
      pointers.delete(event.pointerId), pointers.size < 2 && (pinchStart = null);
    };
    return createEffect(() => {
      props.adjusting || (pointers.clear(), pinchStart = null);
    }), (() => {
      var _el$ = _tmpl$412();
      return insert(_el$, () => props.children, null), insert(_el$, createComponent(Show, {
        get when() {
          return props.adjusting;
        },
        get children() {
          return [(() => {
            var _el$2 = _tmpl$61();
            _el$2.addEventListener("pointercancel", endPointer), _el$2.$$pointerup = endPointer, _el$2.$$pointermove = (event) => {
              if (!pointers.has(event.pointerId) || (pointers.set(event.pointerId, {
                x: event.clientX,
                y: event.clientY
              }), !pinchStart || pointers.size < 2))
                return;
              let [first, second] = Array.from(pointers.values());
              if (!first || !second)
                return;
              let distance = Math.hypot(second.x - first.x, second.y - first.y);
              props.callbacks.onScaleChange(clampScale(pinchStart.scale * distance / pinchStart.distance));
            }, _el$2.$$pointerdown = (event) => {
              if (stopInteraction(event), pointers.set(event.pointerId, {
                x: event.clientX,
                y: event.clientY
              }), interactionLayer.setPointerCapture(event.pointerId), pointers.size !== 2)
                return;
              let [first, second] = Array.from(pointers.values());
              !first || !second || (pinchStart = {
                distance: Math.max(1, Math.hypot(second.x - first.x, second.y - first.y)),
                scale: (props.scalePercent ?? 100) / 100
              });
            }, _el$2.addEventListener("wheel", (event) => {
              stopInteraction(event);
              let deltaPixels = event.deltaY * (event.deltaMode === WheelEvent.DOM_DELTA_LINE ? 16 : event.deltaMode === WheelEvent.DOM_DELTA_PAGE ? interactionLayer.clientHeight : 1);
              props.callbacks.onScaleChange(clampScale((props.scalePercent ?? 100) / 100 * Math.exp(-deltaPixels * 15e-4)));
            }), _el$2.$$click = stopInteraction;
            var _ref$ = interactionLayer;
            return typeof _ref$ == "function" ? use(_ref$, _el$2) : interactionLayer = _el$2, _el$2;
          })(), (() => {
            var _el$3 = _tmpl$313(), _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$7 = _el$5.firstChild, _el$8 = _el$5.nextSibling, _el$9 = _el$8.nextSibling, _el$0 = _el$9.nextSibling, _el$1 = _el$4.nextSibling, _el$10 = _el$1.firstChild, _el$11 = _el$10.nextSibling, _el$12 = _el$11.nextSibling;
            return insert(_el$5, createComponent(Show, {
              get when() {
                return props.scaleMode !== "custom";
              },
              get children() {
                var _el$6 = _tmpl$216();
                return insert(_el$6, (() => {
                  var _c$ = memo(() => props.scaleMode === "fit");
                  return () => _c$() ? i18n_default.reader.fit : "1:1";
                })()), _el$6;
              }
            }), _el$7), insert(_el$7, (() => {
              var _c$2 = memo(() => props.scalePercent === null);
              return () => _c$2() ? "—" : `${Math.round(props.scalePercent)}%`;
            })()), _el$8.$$input = (event) => props.callbacks.onScaleChange(event.currentTarget.valueAsNumber / 100), _el$9.$$click = () => props.callbacks.onFit(), className(_el$9, `${READER_BUTTON_CLASS} w-full`), insert(_el$9, () => i18n_default.reader.fit), _el$0.$$click = () => props.callbacks.onOneToOne(), className(_el$0, `${READER_BUTTON_CLASS} w-full`), _el$10.$$click = () => props.callbacks.onApplyAll(), className(_el$10, `${READER_BUTTON_CLASS} w-full whitespace-normal leading-[1.1]`), insert(_el$10, () => i18n_default.reader.applyGlobally), _el$11.$$click = () => props.callbacks.onApply(), className(_el$11, `${READER_BUTTON_CLASS} w-full`), insert(_el$11, () => i18n_default.common.actions.apply), _el$12.$$click = () => props.callbacks.onClose(), className(_el$12, `${READER_BUTTON_CLASS} w-full`), insert(_el$12, () => i18n_default.common.actions.close), createRenderEffect((_p$) => {
              var _v$ = i18n_default.reader.adjustScrollViewport, _v$2 = i18n_default.reader.resizeScrollViewport;
              return _v$ !== _p$.e && setAttribute(_el$3, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$8, "aria-label", _p$.t = _v$2), _p$;
            }, {
              e: void 0,
              t: void 0
            }), createRenderEffect(() => _el$8.value = sliderPercent()), _el$3;
          })()];
        }
      }), null), _el$;
    })();
  }
  delegateEvents(["click", "pointerdown", "pointermove", "pointerup", "input"]);

  // src/components/Reader/index.css
  var Reader_default = `#ehpeek-reader {
  --color-reader-background: #070707;
  --color-reader-surface: #151515;
  --color-reader-elevated: #232323;
  --color-reader-text: #f3f3f3;
  --color-reader-accent: #4da3ff;
  --color-reader-border: color-mix(in srgb, var(--color-reader-text) 18%, transparent);
  --color-reader-muted: color-mix(in srgb, var(--color-reader-text) 72%, transparent);
  --color-reader-scrollbar: color-mix(in srgb, var(--color-reader-text) 56%, transparent);
  --color-background: var(--color-reader-background);
  --color-surface: var(--color-reader-surface);
  --color-elevated: var(--color-reader-elevated);
  --color-text: var(--color-reader-text);
  --color-accent: var(--color-reader-accent);
  --color-border: color-mix(in srgb, var(--color-text) 18%, transparent);
  --color-muted: color-mix(in srgb, var(--color-text) 72%, transparent);
  --color-track: color-mix(in srgb, var(--color-text) 34%, var(--color-background));
  --color-control: color-mix(in srgb, var(--color-elevated) 88%, transparent);
  --color-badge: color-mix(in srgb, var(--color-background) 34%, transparent);
}

#ehpeek-reader,
#ehpeek-reader * {
  box-sizing: border-box;
}

[data-ehpeek-overlay-host="true"]:fullscreen {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--color-background);
}

[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-fullscreen-status {
  top: 0;
  right: max(10px, env(safe-area-inset-right, 0px));
  left: auto;
  transform: translateY(50%);
}

[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-page-number {
  top: 0;
  right: auto;
  left: max(10px, env(safe-area-inset-left, 0px));
  min-width: 0;
  transform: translateY(50%);
  text-align: left;
}

[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-toolbar {
  top: calc(max(var(--ui-control-size-xs), env(safe-area-inset-top, 0px)) + 8px);
}

[data-ehpeek-overlay-host="true"]:fullscreen
  #ehpeek-reader[data-navigation-mode="scroll"][data-read-direction="ttb"]
  .ehpeek-reader-page-strip {
  padding-top: 0;
}

#ehpeek-reader[data-navigation-mode="paged"][data-page-layout="double"]:not([data-read-direction="ttb"])
  .ehpeek-page {
  width: calc(50% - 1.5px);
  flex: 0 0 calc(50% - 1.5px);
}
`;

  // src/components/Reader/index.tsx
  var _tmpl$70 = /* @__PURE__ */ template("<header class=contents>"), _tmpl$217 = /* @__PURE__ */ template('<div id=ehpeek-reader class="fixed inset-0 z-reader overflow-hidden ehp-color-reader font-sans textsize-sm leading-[1.4]">');
  registerGlobalStyle("ehpeek-reader-style", Reader_default);
  var DEFAULT_WINDOW_SIZE2 = 10, PAGED_SWIPE_THRESHOLD = 24, PAGED_PREVIEW_SWIPE_THRESHOLD = 48, PAGED_PREVIEW_SWIPE_AXIS_LIMIT = 32, PAGED_WHEEL_THRESHOLD = 8, HORIZONTAL_SCROLL_WHEEL_FACTOR = 0.5, PROGRESS_IDLE_COMMIT_MS = 180, LOADED_IMAGE_INFO_CACHE_LIMIT = 160, PROGRESSIVE_IMAGE_SIZE_THRESHOLD = 2 * 1024 * 1024, CONCURRENT_IMAGE_BYTE_LIMIT = 6 * 1024 * 1024, MIN_CONCURRENT_IMAGE_LOADS = 3, SCROLL_GESTURE_IDLE_MS = 160, SCROLL_BAR_IDLE_MS = 900, SCROLL_BAR_SHOW_DISTANCE = 48, SCROLL_BAR_EXPAND_VIEWPORTS = 2, MOUSE_HOLD_ZOOM_MS = 350, ZOOM_DOUBLE_TAP_MS = 300, ZOOM_DOUBLE_TAP_DISTANCE = 36, TAP_CANCEL_DISTANCE = 8, FALLBACK_ASPECT_RATIO2 = 1.42;
  function Reader(props) {
    let overlayHost2 = useOverlayHost(), options = untrack(() => props.options), totalPages = options.totalPages ?? 0, previewCache = untrack(() => props.previewCache), session = new ReaderSession(options), readerState = session.state, scrollFitPageNum = readerState.navi.currentPageNum(), readerCallbacks = wireReaderCallbacks(session, options, previewCache, untrack(() => props.coordinator)), coordinator = untrack(() => props.coordinator);
    coordinator.attachReader({
      gotoPage: readerCallbacks.gotoPage
    });
    let previousFullscreenActive = untrack(() => props.fullscreenActive), viewportPageLayout = () => readerState.ctrls.value().pageLayout === "double" && readerState.ctrls.value().firstPageSeparate && readerState.navi.currentPageNum() === 1 ? "single" : readerState.ctrls.value().pageLayout;
    return createEffect(() => {
      let fullscreenActive = props.fullscreenActive;
      fullscreenActive !== previousFullscreenActive && (previousFullscreenActive = fullscreenActive, session.requestAnimationFrame(() => {
        session.requestAnimationFrame(readerCallbacks.realignCurrentPage);
      }));
    }), onMount(() => {
      readerCallbacks.init(), onCleanup(() => {
        coordinator.attachReader(null), readerCallbacks.cleanup(), session.dispose();
      });
    }), (() => {
      var _el$ = _tmpl$217();
      return insert(_el$, createComponent(Show, {
        get when() {
          return !readerState.scrollViewport.adjusting();
        },
        get children() {
          var _el$2 = _tmpl$70();
          return insert(_el$2, createComponent(Toolbar, {
            get callbacks() {
              return readerCallbacks.toolbar;
            },
            get controls() {
              return readerState.ctrls.value();
            },
            get downloadInfos() {
              return readerState.navi.downloadInfos();
            },
            get fullscreenActive() {
              return props.fullscreenActive;
            },
            get open() {
              return readerState.toolbar.open();
            },
            get progress() {
              return {
                pageNum: readerState.navi.currentPageNum(),
                totalPages: options.totalPages,
                maxProgressPageNum: readerState.navi.maxProgressPageNum(),
                keepInputValue: readerState.navi.progressInputActive()
              };
            }
          })), _el$2;
        }
      }), null), insert(_el$, createComponent(ViewportCanvas, {
        get adjusting() {
          return readerState.scrollViewport.adjusting();
        },
        get callbacks() {
          return readerCallbacks.viewportCanvas;
        },
        get scaleMode() {
          return readerState.scrollViewport.scaleMode();
        },
        get scalePercent() {
          return readerState.scrollViewport.scalePercent();
        },
        get children() {
          return createComponent(PagesViewport, {
            get actionsRef() {
              return readerCallbacks.viewportActionsRef;
            },
            get callbacks() {
              return readerCallbacks.viewport;
            },
            get decodedImageCacheLimit() {
              return options.decodedImageCacheLimit;
            },
            get direction() {
              return readerState.ctrls.value().direction;
            },
            get navigationMode() {
              return readerState.ctrls.value().navigationMode;
            },
            get pageLayout() {
              return viewportPageLayout();
            },
            get scrollFitImageSize() {
              return readerState.scrollViewport.fitImageSize();
            },
            scrollFitPageNum,
            get scrollSizeScale() {
              return readerState.scrollViewport.sizeScale();
            },
            get window() {
              return readerState.navi.viewportWindow();
            },
            get zoomActive() {
              return readerState.overlay.image() !== null;
            }
          });
        }
      }), null), insert(_el$, createComponent(Show, {
        get when() {
          return readerState.ctrls.value().navigationMode === "scroll" && readerState.ctrls.value().direction === "ttb" && totalPages > 1;
        },
        get children() {
          return createComponent(ReaderScrollBar, {
            get callbacks() {
              return readerCallbacks.toolbar;
            },
            get currentPage() {
              return readerState.navi.currentPageNum();
            },
            get expanded() {
              return readerState.scrollBar.expanded();
            },
            get pixelScale() {
              return overlayHost2.fullscreenPixelScale();
            },
            totalPages,
            get visible() {
              return readerState.scrollBar.visible();
            }
          });
        }
      }), null), insert(_el$, createComponent(ZoomOverlay, {
        get actionsRef() {
          return readerCallbacks.zoomOverlayActionsRef;
        },
        get image() {
          return readerState.overlay.image();
        },
        onClose: () => readerState.overlay.update(null)
      }), null), createRenderEffect((_p$) => {
        var _v$ = readerState.ctrls.value().navigationMode, _v$2 = viewportPageLayout(), _v$3 = readerState.ctrls.value().direction;
        return _v$ !== _p$.e && setAttribute(_el$, "data-navigation-mode", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "data-page-layout", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "data-read-direction", _p$.a = _v$3), _p$;
      }, {
        e: void 0,
        t: void 0,
        a: void 0
      }), _el$;
    })();
  }
  function wireReaderCallbacks(session, options, previewCache, coordinator) {
    let state2 = session.state, viewportActions, zoomOverlay, totalPages = options.totalPages && options.totalPages > 0 ? options.totalPages : void 0, renderWindowSize = options.renderWindowSize ?? DEFAULT_WINDOW_SIZE2, preloadWindowSize = options.preloadWindowSize ?? DEFAULT_WINDOW_SIZE2, pages = /* @__PURE__ */ new Map(), loadedImages = /* @__PURE__ */ new Map(), pagedTargetPageNumber = null, syncToken = 0, closed = !1, loadDirection = 1, loadDirectionEdgePageNum = state2.navi.currentPageNum(), scrollFitPageNum = state2.navi.currentPageNum(), pagedMode = () => state2.ctrls.value().navigationMode === "paged", doublePageActive = () => pagedMode() && state2.ctrls.value().pageLayout === "double" && !(state2.ctrls.value().firstPageSeparate && state2.navi.currentPageNum() === 1), readerOrientation = currentReaderOrientation(), updateReaderViewportSize = () => {
      state2.scrollViewport.setViewportWidth(Math.max(1, window.innerWidth)), state2.scrollViewport.setViewportHeight(Math.max(1, window.innerHeight));
      let nextOrientation = currentReaderOrientation();
      nextOrientation !== readerOrientation && (readerOrientation = nextOrientation, updateControls(configuredReaderControls()));
    };
    function configuredReaderControls() {
      let controls = currentReaderControlsState(), navigationMode = controls.navigationMode.value;
      return {
        navigationMode,
        direction: navigationMode === "scroll" ? controls.scrollDirection.value : controls.pagedDirection.value,
        firstPageSeparate: state2.ctrls.value().firstPageSeparate,
        pageLayout: controls.pageLayout.value,
        rightTapAction: controls.rightTapAction.value
      };
    }
    function updateControls(requestedControls) {
      let previous = state2.ctrls.value(), persistedControls = currentReaderControlsState(), controls = requestedControls.navigationMode === previous.navigationMode ? requestedControls : {
        ...requestedControls,
        direction: requestedControls.navigationMode === "scroll" ? persistedControls.scrollDirection.value : persistedControls.pagedDirection.value
      };
      persistedControls.navigationMode.set(controls.navigationMode), controls.navigationMode === "scroll" ? persistedControls.scrollDirection.set(controls.direction) : persistedControls.pagedDirection.set(controls.direction), persistedControls.pageLayout.set(controls.pageLayout), persistedControls.rightTapAction.set(controls.rightTapAction), state2.ctrls.update(controls), controls.navigationMode !== "scroll" && state2.scrollViewport.setAdjusting(!1), controls.navigationMode !== previous.navigationMode || controls.pageLayout !== previous.pageLayout || controls.firstPageSeparate !== previous.firstPageSeparate ? (viewportActions.stopMotion(), viewportActions.resetPosition(), setCurrentPageNumber(state2.navi.currentPageNum(), !0)) : controls.direction !== previous.direction && (syncViewportWindow(), scrollToCurrentPage());
    }
    function requestReaderClose() {
      closed || (closed = coordinator.requestCloseReader());
    }
    function imageAtPoint(point) {
      let pageNum = viewportActions.pageNumAtPoint(point);
      return pageNum === null || !viewportActions.pageImageReady(pageNum) ? null : loadedImages.get(pageNum) ?? null;
    }
    function prepareZoomAtPoint(point) {
      let image2 = imageAtPoint(point);
      if (!image2)
        return !1;
      viewportActions.stopMotion(), viewportActions.cancelDrag();
      let zoomScale = viewportActions.pageZoomScale(image2.pageNum);
      return state2.overlay.update(image2), zoomOverlay.reset({
        centerX: point.clientX,
        centerY: point.clientY,
        scale: zoomScale
      }), !0;
    }
    function setCurrentPageNumber(pageNumber, scrollIntoView, scrollMotion = "instant") {
      pagedTargetPageNumber = null;
      let target = normalizedPageNumber(clamp(Math.round(pageNumber), 1, maxProgressPageNum()));
      target !== state2.navi.currentPageNum() && (state2.navi.setDirection(target > state2.navi.currentPageNum() ? 1 : -1), state2.navi.setCurrentPageNum(target)), syncAfterPageChange({
        scrollIntoView,
        scrollMotion
      });
    }
    function normalizedPageNumber(pageNum) {
      return !pagedMode() || state2.ctrls.value().pageLayout !== "double" || totalPages !== void 0 && pageNum === totalPages + 1 ? pageNum : doublePagePairStart(pageNum, state2.ctrls.value().firstPageSeparate);
    }
    function syncAfterPageChange(options2) {
      let token = ++syncToken, missing = pageWindowNumbers(state2.navi.currentPageNum(), renderWindowSize).filter((number) => isRealPageNum(number) && !pages.has(number));
      syncViewportWindow(), maintainLoadQueue(), notifyActivePageChange(), options2.scrollIntoView && scrollToCurrentPage(options2.scrollMotion), missing.length > 0 && loadMissingPages(missing, token);
    }
    async function loadMissingPages(pageNums, token) {
      let pageGroups = /* @__PURE__ */ new Map();
      for (let pageNum of pageNums) {
        let previewIndex = previewCache.previewIndexForPage(pageNum);
        pageGroups.set(previewIndex, [...pageGroups.get(previewIndex) ?? [], pageNum]);
      }
      await Promise.all(Array.from(pageGroups.values(), async (groupPageNums) => {
        let loadingTokens = new Map(groupPageNums.flatMap((pageNum) => {
          let loadingToken = viewportActions.markPageLoading(pageNum);
          return loadingToken === null ? [] : [[pageNum, loadingToken]];
        })), incoming;
        try {
          incoming = await previewCache.getPages(groupPageNums);
        } catch (error) {
          console.error("[ehpeek]", error);
          let message = error instanceof Error ? error.message : i18n_default.errors.loadFailed;
          for (let [pageNum, loadingToken] of loadingTokens)
            viewportActions.setPageError(pageNum, loadingToken, message);
          return;
        }
        if (closed)
          return;
        addPages(incoming);
        let loadedPageNums = new Set(incoming.flatMap((page2) => page2.pageNum && page2.pageNum > 0 ? [page2.pageNum] : []));
        for (let [pageNum, loadingToken] of loadingTokens)
          loadedPageNums.has(pageNum) ? viewportActions.resetPageLoading(pageNum, loadingToken) : viewportActions.setPageError(pageNum, loadingToken, i18n_default.errors.imageNotFound);
      })), !(closed || token !== syncToken) && (syncViewportWindow(), maintainLoadQueue(), notifyActivePageChange(), state2.ctrls.value().navigationMode === "scroll" && state2.navi.currentPageNum() === scrollFitPageNum && scrollToCurrentPage());
    }
    function addPages(incomingPages) {
      for (let [index, page2] of incomingPages.entries()) {
        let pageNum = pageNumForPage(page2, index);
        pageNum > 0 && pages.set(pageNum, {
          ...page2,
          aspectRatio: normalizedAspectRatio(page2.aspectRatio, FALLBACK_ASPECT_RATIO2),
          pageNum
        });
      }
    }
    function syncViewportWindow() {
      state2.navi.setViewportWindow({
        currentPageNum: state2.navi.currentPageNum(),
        windowSize: renderWindowSize,
        totalPages,
        pages: pageMetaForViewport()
      }), updatePageNumber();
    }
    function maintainLoadQueue() {
      let firstVisiblePageNum = viewportActions.firstVisiblePageNum() ?? state2.navi.currentPageNum(), movement = (firstVisiblePageNum - loadDirectionEdgePageNum) * loadDirection;
      movement >= 0 ? loadDirectionEdgePageNum = firstVisiblePageNum : -movement > 2 && (loadDirection = loadDirection === 1 ? -1 : 1, loadDirectionEdgePageNum = firstVisiblePageNum);
      let pageNums = [firstVisiblePageNum];
      for (let offset = 1; offset <= preloadWindowSize; offset += 1)
        pageNums.push(firstVisiblePageNum + offset * loadDirection);
      pageNums.push(firstVisiblePageNum - loadDirection), session.imageQueue.sync(Array.from(new Set(pageNums)).flatMap((pageNum, priority) => {
        let target = loadTargetFor(pageNum);
        return target ? [{
          key: pageNum,
          priority,
          target
        }] : [];
      }));
    }
    function pageMetaForViewport() {
      return new Map(Array.from(pages, ([pageNum, page2]) => [pageNum, {
        aspectRatio: page2.aspectRatio
      }]));
    }
    function loadTargetFor(pageNum) {
      let page2 = pages.get(pageNum);
      return page2 ? {
        pageNum,
        page: page2
      } : null;
    }
    function maxProgressPageNum() {
      return totalPages ? totalPages + 1 : Number.MAX_SAFE_INTEGER;
    }
    function isRealPageNum(pageNum) {
      return pageNum >= 1 && (!totalPages || pageNum <= totalPages);
    }
    function turnPageBy(delta) {
      if (pagedMode()) {
        let base = pagedTargetPageNumber ?? state2.navi.currentPageNum(), firstPageSeparate = state2.ctrls.value().firstPageSeparate, pageDelta = delta;
        state2.ctrls.value().pageLayout === "double" && (totalPages !== void 0 && base === totalPages + 1 && delta < 0 ? pageDelta = doublePagePairStart(totalPages, firstPageSeparate) - base : firstPageSeparate && base === 1 && delta > 0 ? pageDelta = 1 : firstPageSeparate && base === 2 && delta < 0 ? pageDelta = -1 : pageDelta = delta * 2), animatePagedStep(pageDelta);
        return;
      }
      setCurrentPageNumber(state2.navi.currentPageNum() + delta, !0);
    }
    function animatePagedStep(delta) {
      let base = pagedTargetPageNumber ?? state2.navi.currentPageNum(), target = clamp(Math.round(base + delta), 1, maxProgressPageNum());
      if (target === base) {
        scrollToCurrentPage("animated");
        return;
      }
      if (viewportActions.pageOffset(target) === null) {
        pagedTargetPageNumber = null, setCurrentPageNumber(target, !0, "animated");
        return;
      }
      state2.navi.setDirection(target > base ? 1 : -1), pagedTargetPageNumber = target, viewportActions.moveToPage(target, "animated", () => {
        pagedTargetPageNumber === target && (pagedTargetPageNumber = null, setCurrentPageNumber(target, !0));
      });
    }
    function scrollToCurrentPage(motion = "instant") {
      viewportActions.moveToPage(state2.navi.currentPageNum(), motion);
    }
    function updatePageNumber() {
      let pageNum = state2.navi.currentPageNum(), downloadPageNums = doublePageActive() ? [pageNum, pageNum + 1] : [pageNum];
      state2.navi.setDownloadInfos(downloadPageNums.flatMap((downloadPageNum) => {
        let image2 = loadedImages.get(downloadPageNum);
        return !image2 || !isRealPageNum(downloadPageNum) ? [] : (loadedImages.delete(downloadPageNum), loadedImages.set(downloadPageNum, image2), [{
          currentFileName: imageDownloadFileName(options.galleryId, options.galleryToken, downloadPageNum, image2.imageUrl),
          currentImageUrl: image2.imageUrl,
          imageHeight: viewportActions.pageImageHeight(downloadPageNum) ?? image2.height,
          imageWidth: viewportActions.pageImageWidth(downloadPageNum) ?? image2.width,
          originalFileName: imageDownloadFileName(options.galleryId, options.galleryToken, downloadPageNum, image2.originalImageUrl ?? "", image2.imageUrl),
          originalImageUrl: image2.originalImageUrl,
          pageNum: downloadPageNum
        }]);
      })), state2.navi.setMaxProgressPageNum(Math.max(1, maxProgressPageNum()));
    }
    function notifyActivePageChange() {
      let page2 = pages.get(state2.navi.currentPageNum());
      page2 && coordinator.readerActivePageChanged(page2);
    }
    function updateCurrentFromScroll() {
      let next = viewportActions.centerPageNum();
      if (next !== null && next !== state2.navi.currentPageNum()) {
        state2.navi.setDirection(next > state2.navi.currentPageNum() ? 1 : -1), state2.navi.setCurrentPageNum(next), syncAfterPageChange({
          scrollIntoView: !1
        });
        return;
      }
      maintainLoadQueue();
    }
    let onKeydown = (event) => {
      shouldIgnoreKeyboardEvent(event) || (event.key === "Escape" ? (state2.overlay.image() !== null ? state2.overlay.update(null) : requestReaderClose(), event.preventDefault()) : (event.key === "ArrowLeft" || event.key === "ArrowRight" || state2.ctrls.value().direction === "ttb" && (event.key === "ArrowUp" || event.key === "ArrowDown")) && (event.preventDefault(), state2.overlay.image() === null && (event.key === "ArrowUp" || event.key === "ArrowDown" ? turnPageBy(event.key === "ArrowUp" ? -1 : 1) : turnPageBy(event.key === "ArrowLeft" ? state2.navi.leftTapDelta() : state2.navi.rightTapDelta()))));
    }, gesture = wireGesture(), viewport = wireViewport(), scrollViewport = wireScrollViewport();
    wireImageQueue();
    let toolbar = wireToolbar();
    return {
      viewportActionsRef: (actions) => {
        viewportActions = actions;
      },
      zoomOverlayActionsRef: (actions) => {
        zoomOverlay = actions;
      },
      init: () => {
        document.addEventListener("keydown", onKeydown, !0), window.addEventListener("resize", updateReaderViewportSize), viewportActions.focus(), updatePageNumber(), syncAfterPageChange({
          scrollIntoView: !0
        });
      },
      cleanup: () => {
        document.removeEventListener("keydown", onKeydown, !0), window.removeEventListener("resize", updateReaderViewportSize);
      },
      gotoPage: (pageNum) => setCurrentPageNumber(pageNum, !0),
      realignCurrentPage: () => {
        scrollToCurrentPage();
      },
      toolbar,
      viewport,
      viewportCanvas: scrollViewport.callbacks
    };
    function wireScrollViewport() {
      let adjustmentStartSizeScale = state2.scrollViewport.sizeScale(), pinchStartScale = null, updateImageScale = (scale) => {
        if (scale === null) {
          state2.scrollViewport.setSizeScale(null);
          return;
        }
        let fitScale = state2.scrollViewport.fitScale();
        fitScale && state2.scrollViewport.setSizeScale(normalizeReaderScrollSizeScale(scale / fitScale));
      };
      return {
        startPinch: () => {
          let scalePercent = state2.scrollViewport.scalePercent();
          return scalePercent === null ? !1 : (pinchStartScale = scalePercent / 100, !0);
        },
        movePinch: (scale) => {
          pinchStartScale !== null && updateImageScale(clamp(pinchStartScale * scale, 0.1, 5));
        },
        endPinch: () => {
          pinchStartScale = null;
        },
        pinching: () => pinchStartScale !== null,
        open: () => {
          adjustmentStartSizeScale = state2.scrollViewport.sizeScale(), state2.scrollViewport.setAdjusting(!0);
        },
        callbacks: {
          onApply: () => state2.scrollViewport.setAdjusting(!1),
          onApplyAll: () => {
            (state2.ctrls.value().direction === "ttb" ? state.reader.scrollTtbScale : state.reader.scrollHorizontalScale).set(state2.scrollViewport.sizeScale()), state2.scrollViewport.setAdjusting(!1);
          },
          onClose: () => {
            state2.scrollViewport.setSizeScale(adjustmentStartSizeScale), state2.scrollViewport.setAdjusting(!1);
          },
          onFit: () => updateImageScale(null),
          onOneToOne: () => state2.scrollViewport.setSizeScale("one-to-one"),
          onScaleChange: updateImageScale
        }
      };
    }
    function wireViewport() {
      let scrollFrame = null, scrollBarTimer = null, scrollGestureTimer = null, previousScrollPosition = null, scrollDistance = 0, scrollPosition = () => state2.ctrls.value().direction === "ttb" ? viewportActions.scrollTop() : viewportActions.scrollLeft(), updateScrollBarActivity = () => {
        let currentScrollPosition = scrollPosition();
        previousScrollPosition !== null && (scrollDistance += Math.abs(currentScrollPosition - previousScrollPosition)), previousScrollPosition = currentScrollPosition, scrollDistance >= SCROLL_BAR_SHOW_DISTANCE && state2.scrollBar.updateVisible(!0);
        let viewportSize = state2.ctrls.value().direction === "ttb" ? window.innerHeight : window.innerWidth;
        scrollDistance >= viewportSize * SCROLL_BAR_EXPAND_VIEWPORTS && state2.scrollBar.updateExpanded(!0), session.clearTimeout(scrollGestureTimer), scrollGestureTimer = session.setTimeout(() => {
          scrollGestureTimer = null, scrollDistance = 0, previousScrollPosition = scrollPosition();
        }, SCROLL_GESTURE_IDLE_MS), session.clearTimeout(scrollBarTimer), scrollBarTimer = session.setTimeout(() => {
          scrollBarTimer = null, scrollDistance = 0, previousScrollPosition = scrollPosition(), state2.scrollBar.updateExpanded(!1), state2.scrollBar.updateVisible(!1);
        }, SCROLL_BAR_IDLE_MS);
      };
      return onCleanup(() => {
        session.clearTimeout(scrollBarTimer), session.clearTimeout(scrollGestureTimer);
      }), {
        onDoubleClick: (event) => {
          state2.overlay.image() !== null && (event.preventDefault(), event.stopPropagation(), state2.overlay.update(null));
        },
        onNativeScroll: () => {
          if (state2.overlay.image() !== null || pagedMode() || state2.scrollViewport.adjusting() || (updateScrollBarActivity(), viewportActions.isDragging()))
            return;
          let previousPosition = scrollPosition();
          state2.ctrls.value().direction === "ttb" ? viewportActions.moveToTop(previousPosition) : viewportActions.moveToLeft(previousPosition), !(scrollPosition() !== previousPosition || scrollFrame !== null) && (scrollFrame = session.requestAnimationFrame(() => {
            scrollFrame = null, updateCurrentFromScroll();
          }));
        },
        onReloadPage: (pageNum) => {
          viewportActions.resetPageError(pageNum) && (pages.has(pageNum) ? maintainLoadQueue() : loadMissingPages([pageNum], ++syncToken));
        },
        onWheel: (delta, event) => {
          let deltaPixels = wheelDeltaPixels(delta, event.deltaMode);
          if (state2.overlay.image() !== null) {
            event.preventDefault(), zoomOverlay.moveWheel({
              centerX: event.clientX,
              centerY: event.clientY,
              delta: deltaPixels
            });
            return;
          }
          if (event.ctrlKey || event.metaKey) {
            if (event.preventDefault(), !pagedMode()) {
              scrollViewport.startPinch() && (scrollViewport.movePinch(Math.exp(-clamp(deltaPixels, -100, 100) * 25e-4)), scrollViewport.endPinch());
              return;
            }
            if (!prepareZoomAtPoint(event))
              return;
            zoomOverlay.moveWheel({
              centerX: event.clientX,
              centerY: event.clientY,
              delta: deltaPixels
            });
            return;
          }
          if (!(!pagedMode() && state2.ctrls.value().direction === "ttb")) {
            if (event.preventDefault(), !pagedMode()) {
              let direction = state2.ctrls.value().direction === "rtl" ? -1 : 1;
              viewportActions.moveToLeft(viewportActions.scrollLeft() + deltaPixels * direction * HORIZONTAL_SCROLL_WHEEL_FACTOR);
              return;
            }
            !viewportActions.isDragging() && Math.abs(delta) >= PAGED_WHEEL_THRESHOLD && turnPageBy(delta > 0 ? 1 : -1);
          }
        },
        pointer: gesture
      };
    }
    function wireImageQueue() {
      let acquireImageLoadBudget = createImageLoadBudget(CONCURRENT_IMAGE_BYTE_LIMIT, MIN_CONCURRENT_IMAGE_LOADS), rememberLoadedImage = (pageNum, loaded) => {
        let image2 = {
          pageNum,
          imageUrl: loaded.imageUrl,
          originalImageUrl: loaded.originalImageUrl ?? null,
          width: positiveNumber(loaded.width),
          height: positiveNumber(loaded.height)
        };
        for (pageNum === scrollFitPageNum && image2.width && image2.height && !state2.scrollViewport.fitImageSize() && state2.scrollViewport.setFitImageSize({
          height: image2.height,
          width: image2.width
        }), loadedImages.delete(pageNum), loadedImages.set(pageNum, image2); loadedImages.size > LOADED_IMAGE_INFO_CACHE_LIMIT; ) {
          let oldestPageNum = loadedImages.keys().next().value;
          if (oldestPageNum === void 0)
            break;
          loadedImages.delete(oldestPageNum);
        }
        return image2;
      }, installImage = async (target, loaded, token) => {
        let imageUrl = loaded.imageUrl, width = positiveNumber(loaded.width), height = positiveNumber(loaded.height), installed = !1;
        try {
          installed = await viewportActions.loadPageImage(target.pageNum, token, {
            displayWhileLoading: shouldDisplayImageWhileLoading(imageUrl, loaded.originalImageUrl),
            imageUrl,
            highPriority: target.pageNum === state2.navi.currentPageNum() || doublePageActive() && target.pageNum === state2.navi.currentPageNum() + 1,
            width,
            height
          });
        } catch (error) {
          let message = error instanceof Error ? error.message : i18n_default.errors.imageLoadFailed;
          viewportActions.setPageError(target.pageNum, token, message);
          return;
        }
        if (installed && target.pageNum === scrollFitPageNum && !state2.scrollViewport.fitImageSize()) {
          let fitWidth = viewportActions.pageImageWidth(target.pageNum), fitHeight = viewportActions.pageImageHeight(target.pageNum);
          fitWidth && fitHeight && state2.scrollViewport.setFitImageSize({
            height: fitHeight,
            width: fitWidth
          });
        }
        if (!closed) {
          let currentPageNum = state2.navi.currentPageNum();
          (target.pageNum === currentPageNum || doublePageActive() && target.pageNum === currentPageNum + 1) && updatePageNumber();
        }
      };
      session.imageQueue.updateCallbacks({
        loadTarget: (target) => Promise.resolve(loadedImages.get(target.pageNum) ?? previewCache.loadImage(target.page)),
        markLoading: (target) => viewportActions.markPageLoading(target.pageNum),
        onLoaded: async (target, loaded, token) => {
          let image2 = rememberLoadedImage(target.pageNum, loaded);
          if (!pageWindowNumbers(state2.navi.currentPageNum(), renderWindowSize).includes(target.pageNum))
            return;
          let releaseBudget = await acquireImageLoadBudget(imageFileByteSize(image2.imageUrl) ?? CONCURRENT_IMAGE_BYTE_LIMIT);
          try {
            if (!pageWindowNumbers(state2.navi.currentPageNum(), renderWindowSize).includes(target.pageNum))
              return;
            await installImage(target, image2, token);
          } finally {
            releaseBudget();
          }
        },
        onError: (target, error, token) => {
          let message = error instanceof Error ? error.message : i18n_default.errors.loadFailed;
          viewportActions.setPageError(target.pageNum, token, message);
        }
      });
    }
    function wireToolbar() {
      let toolbar2 = {}, progressNavigationTimer = null, pendingProgressPageNum = null, cancelProgressNavigation = () => {
        progressNavigationTimer !== null && (session.clearTimeout(progressNavigationTimer), progressNavigationTimer = null);
      }, previewProgress = (pageNum) => {
        let target = normalizedPageNumber(clamp(Math.round(pageNum), 1, maxProgressPageNum()));
        target !== state2.navi.currentPageNum() && (state2.navi.setDirection(target > state2.navi.currentPageNum() ? 1 : -1), state2.navi.setCurrentPageNum(target)), ++syncToken, syncViewportWindow(), scrollToCurrentPage(), updatePageNumber();
      };
      return onCleanup(cancelProgressNavigation), toolbar2.onCloseClick = requestReaderClose, toolbar2.onControlsChange = updateControls, toolbar2.onFullscreenClick = coordinator.toggleReaderFullscreen, toolbar2.onOpenOriginalPageClick = () => {
        let page2 = pages.get(state2.navi.currentPageNum());
        page2 && isRealPageNum(state2.navi.currentPageNum()) && coordinator.openOriginalPage(page2);
      }, toolbar2.onOpenScrollPreviewClick = () => {
        coordinator.openPreviewPage(state2.navi.currentPageNum());
      }, toolbar2.onViewportAdjustClick = scrollViewport.open, toolbar2.onProgressPointerDown = (event) => {
        state2.navi.setProgressInputActive(!0), cancelProgressNavigation(), event.stopPropagation();
      }, toolbar2.onProgressInput = (pageNum) => {
        !Number.isFinite(pageNum) || pageNum <= 0 || (state2.navi.setProgressInputActive(!0), pendingProgressPageNum = clamp(Math.round(pageNum), 1, maxProgressPageNum()), previewProgress(pendingProgressPageNum), cancelProgressNavigation(), progressNavigationTimer = session.setTimeout(() => toolbar2.onProgressCommit(pendingProgressPageNum ?? state2.navi.currentPageNum()), PROGRESS_IDLE_COMMIT_MS));
      }, toolbar2.onProgressCommit = (value) => {
        if (!state2.navi.progressInputActive() && pendingProgressPageNum === null)
          return;
        let pageNum = pendingProgressPageNum ?? value;
        state2.navi.setProgressInputActive(!1), pendingProgressPageNum = null, cancelProgressNavigation(), Number.isFinite(pageNum) && pageNum > 0 && setCurrentPageNumber(pageNum, !0);
      }, toolbar2;
    }
    function wireGesture() {
      let gesture2 = {
        dragAxis: "any"
      }, lastZoomTouchTap = null, isPageReloadButtonTarget = (event) => event.target instanceof Element && event.target.closest(".ehpeek-reader-page-reload") !== null, shouldStartDrag = (event) => state2.overlay.image() !== null || pagedMode() || state2.ctrls.value().direction !== "ttb" || event.pointerType === "mouse", isPreviewSwipe = (info) => pagedMode() ? state2.ctrls.value().direction === "ttb" ? Math.abs(info.dx) >= PAGED_PREVIEW_SWIPE_THRESHOLD && Math.abs(info.dy) <= PAGED_PREVIEW_SWIPE_AXIS_LIMIT : info.dy >= PAGED_PREVIEW_SWIPE_THRESHOLD && Math.abs(info.dx) <= PAGED_PREVIEW_SWIPE_AXIS_LIMIT : !1, runSingleTap = (info, event) => {
        if (state2.overlay.image() !== null)
          event.preventDefault();
        else if (viewportActions.isHitEndPage(info))
          requestReaderClose();
        else {
          let zone = info.clientX / viewportActions.viewportWidth();
          zone >= 1 / 3 && zone <= 2 / 3 ? state2.toolbar.toggle() : turnPageBy(zone < 1 / 3 ? state2.navi.leftTapDelta() : state2.navi.rightTapDelta());
        }
      };
      return gesture2.onTap = (info, event) => {
        if (viewportActions.cancelDrag(), state2.overlay.image() !== null && event instanceof PointerEvent && event.pointerType === "touch") {
          let now = event.timeStamp || performance.now(), doubleTap = lastZoomTouchTap !== null && now - lastZoomTouchTap.time <= ZOOM_DOUBLE_TAP_MS && Math.hypot(info.clientX - lastZoomTouchTap.clientX, info.clientY - lastZoomTouchTap.clientY) <= ZOOM_DOUBLE_TAP_DISTANCE;
          lastZoomTouchTap = doubleTap ? null : {
            clientX: info.clientX,
            clientY: info.clientY,
            time: now
          }, doubleTap && state2.overlay.update(null), event.preventDefault();
          return;
        }
        lastZoomTouchTap = null, runSingleTap(info, event);
      }, gesture2.holdDelay = MOUSE_HOLD_ZOOM_MS, gesture2.onHold = (info, event) => (event instanceof PointerEvent ? event.pointerType === "mouse" : event instanceof MouseEvent) ? (lastZoomTouchTap = null, state2.overlay.image() !== null ? (state2.overlay.update(null), "consume") : prepareZoomAtPoint(info) ? (zoomOverlay.movePinch({
        centerX: info.clientX,
        centerY: info.clientY,
        scale: 2
      }), zoomOverlay.endPinch(), "drag") : !1) : !1, gesture2.onStart = () => {
        if (state2.overlay.image() !== null) {
          zoomOverlay.startDrag();
          return;
        }
        viewportActions.beginDrag();
      }, gesture2.onMove = (info) => {
        if (state2.overlay.image() !== null) {
          zoomOverlay.moveDrag(info);
          return;
        }
        viewportActions.moveDrag({
          dx: info.dx,
          dy: info.dy
        });
      }, gesture2.onEnd = (info) => {
        if (state2.overlay.image() === null) {
          if (viewportActions.cancelDrag(), isPreviewSwipe(info)) {
            scrollToCurrentPage("animated"), coordinator.openPreviewPage(state2.navi.currentPageNum());
            return;
          }
          if (!pagedMode()) {
            state2.ctrls.value().direction === "ttb" ? (viewportActions.moveToTop(viewportActions.scrollTop()), viewportActions.startVerticalFlingFromDragVelocity(info.velocityY, () => updateCurrentFromScroll())) : (viewportActions.moveToLeft(viewportActions.scrollLeft()), viewportActions.startHorizontalFlingFromDragVelocity(info.velocityX, () => updateCurrentFromScroll())), updateCurrentFromScroll();
            return;
          }
          if (state2.ctrls.value().direction === "ttb") {
            info.dy >= PAGED_SWIPE_THRESHOLD ? turnPageBy(-1) : info.dy <= -PAGED_SWIPE_THRESHOLD ? turnPageBy(1) : scrollToCurrentPage("animated");
            return;
          }
          info.dx >= PAGED_SWIPE_THRESHOLD ? turnPageBy(state2.navi.rightDragDelta()) : info.dx <= -PAGED_SWIPE_THRESHOLD ? turnPageBy(state2.navi.leftDragDelta()) : scrollToCurrentPage("animated");
        }
      }, gesture2.onPinchStart = (info) => {
        if (lastZoomTouchTap = null, viewportActions.stopMotion(), viewportActions.cancelDrag(), !pagedMode() && state2.overlay.image() === null)
          return scrollViewport.startPinch();
        if (state2.overlay.image() !== null)
          return zoomOverlay.startPinch({
            centerX: info.clientX,
            centerY: info.clientY
          }), !0;
        let image2 = imageAtPoint(info);
        if (!image2)
          return !1;
        let zoomScale = viewportActions.pageZoomScale(image2.pageNum);
        return state2.overlay.update(image2), zoomOverlay.reset({
          centerX: info.clientX,
          centerY: info.clientY,
          scale: zoomScale
        }), !0;
      }, gesture2.onPinchMove = (info) => {
        if (scrollViewport.pinching()) {
          scrollViewport.movePinch(info.scale);
          return;
        }
        zoomOverlay.movePinch({
          centerX: info.clientX,
          centerY: info.clientY,
          scale: info.scale
        });
      }, gesture2.onPinchEnd = () => {
        if (scrollViewport.pinching()) {
          scrollViewport.endPinch();
          return;
        }
        zoomOverlay.endPinch();
      }, gesture2.shouldCaptureDrag = (event) => isPageReloadButtonTarget(event) || !(event instanceof PointerEvent) || event.pointerType === "mouse" && event.button !== 0 ? !1 : shouldStartDrag(event), gesture2.shouldObserveTap = (event) => event instanceof PointerEvent && !isPageReloadButtonTarget(event) && event.pointerType !== "mouse" && !shouldStartDrag(event), gesture2.dragStartThreshold = TAP_CANCEL_DISTANCE, gesture2.tapMoveThreshold = TAP_CANCEL_DISTANCE, gesture2;
    }
  }
  function wheelDeltaPixels(delta, mode) {
    return mode === WheelEvent.DOM_DELTA_LINE ? delta * 16 : mode === WheelEvent.DOM_DELTA_PAGE ? delta * window.innerHeight : delta;
  }
  function imageDownloadFileName(galleryId, galleryToken, pageNum, imageUrl, fallbackImageUrl = "") {
    let extension = imageFileExtension(imageUrl) || imageFileExtension(fallbackImageUrl) || "webp";
    return `${galleryId}-${galleryToken}-p${pageNum}.${extension}`;
  }
  function imageFileExtension(imageUrl) {
    try {
      let extension = decodeURIComponent(new URL(imageUrl).pathname.split("/").pop() ?? "").match(/\.([a-z0-9]{2,5})$/i)?.[1]?.toLowerCase();
      if (extension && ["avif", "bmp", "gif", "jpeg", "jpg", "png", "webp"].includes(extension))
        return extension;
    } catch {
      return "";
    }
    return "";
  }
  function shouldDisplayImageWhileLoading(imageUrl, originalImageUrl) {
    if (imageFileExtension(imageUrl) === "gif" || originalImageUrl && imageFileExtension(originalImageUrl) === "gif")
      return !0;
    let byteSize = imageFileByteSize(imageUrl);
    return byteSize !== null && byteSize > PROGRESSIVE_IMAGE_SIZE_THRESHOLD;
  }
  function imageFileByteSize(imageUrl) {
    try {
      let hathImageKey = new URL(imageUrl).pathname.split("/").find((part) => /^[a-f0-9]{40}-\d+-\d+-\d+-[a-z0-9]+$/i.test(part)), byteSize = Number(hathImageKey?.split("-")[1]);
      return Number.isSafeInteger(byteSize) && byteSize > 0 ? byteSize : null;
    } catch {
      return null;
    }
  }
  function createImageLoadBudget(maxBytes, minConcurrentLoads) {
    let waiters = [], activeBytes = 0, activeLoads = 0, drain = () => {
      let next = waiters[0];
      if (!next || activeLoads >= minConcurrentLoads && activeBytes + next.bytes > maxBytes)
        return;
      waiters.shift(), activeBytes += next.bytes, activeLoads += 1;
      let released = !1;
      next.resolve(() => {
        released || (released = !0, activeBytes = Math.max(0, activeBytes - next.bytes), activeLoads = Math.max(0, activeLoads - 1), drain());
      }), drain();
    };
    return (bytes) => new Promise((resolve) => {
      waiters.push({
        bytes,
        resolve
      }), drain();
    });
  }
  function pageNumForPage(page2, index) {
    let pageNum = page2?.pageNum;
    return typeof pageNum == "number" && Number.isFinite(pageNum) && pageNum > 0 ? pageNum : index + 1;
  }
  function shouldIgnoreKeyboardEvent(event) {
    if (event.isComposing)
      return !0;
    let eventTarget = event.target;
    return eventTarget instanceof Element ? !!eventTarget.closest("input, textarea, select, [contenteditable='true'], [contenteditable='']") : !1;
  }

  // src/App/Reader.tsx
  var READER_THEME_COLOR = "#070707";
  function mountReaderSurface(options) {
    let host = document.createElement("div");
    options.overlayHost.element.append(host);
    let setFullscreenActive = (_active) => {
    }, disposed = !1, unlockPageScroll = lockPageScroll(), unlockPageThemeColor = lockPageThemeColor(READER_THEME_COLOR), disposeRoot;
    try {
      disposeRoot = render(() => {
        let [fullscreenActive, updateFullscreenActive] = createSignal(options.overlayHost.fullscreen.active());
        return setFullscreenActive = updateFullscreenActive, createComponent(OverlayHostProvider, {
          get host() {
            return options.overlayHost;
          },
          get children() {
            return createComponent(Reader, {
              get coordinator() {
                return options.coordinator;
              },
              get fullscreenActive() {
                return fullscreenActive();
              },
              get options() {
                return options.options;
              },
              get previewCache() {
                return options.previewCache;
              }
            });
          }
        });
      }, host);
    } catch (error) {
      throw options.coordinator.attachReader(null), unlockPageThemeColor(), unlockPageScroll(), host.remove(), error;
    }
    return {
      dispose: () => {
        disposed || (disposed = !0, disposeRoot(), unlockPageThemeColor(), unlockPageScroll(), host.remove());
      },
      setFullscreenActive
    };
  }
  async function openOriginalReader(pageNum, previewCache) {
    let page2 = (await previewCache.getPages([pageNum]))[0];
    if (!page2 || page2.pageNum !== pageNum)
      throw new Error(i18n_default.errors.imageNotFound);
    window.location.assign(page2.url);
  }
  function reportReaderOpenError(error) {
    let message = error instanceof Error ? error.message : i18n_default.errors.loadFailed;
    console.error("[ehpeek]", error), window.alert(message);
  }

  // src/App/GalleryCoordinator.ts
  function createGalleryCoordinator(options) {
    let previewCache = options.previewCache, preview = previewCache.current().data, gallery2 = galleryIdentityFromUrl(preview.currentUrl);
    if (!gallery2)
      throw new Error("Cannot identify Gallery for Reader.");
    let progress = createProgressSession(
      gallery2.galleryId,
      gallery2.token,
      preview.totalImages,
      options.readHistoryEnabled,
      options.includeUnreadHistoryEnabled
    ), historySessionId = crypto.randomUUID(), surfaces = [], reader = null, readerActions = null, readerInitialPage = 1, readerInitialPreviewIndex = preview.currentIndex, readerLastPage = 1, previewActions = null, thumbsActions = null, afterHistoryClose = null, historyClosePending = !1, preserveSurfacesOnFullscreenExit = !1, fullscreenWasActive = options.overlayHost.fullscreen.active(), topSurface = () => surfaces[surfaces.length - 1], previewOpen = () => topSurface() === "preview", enhancedPreviewActive = () => options.enhanceThumbsGridsEnabled || options.replacePreviewWithScroll || previewOpen(), pushSurface = (surface) => {
      surfaces.push(surface);
      let currentState = window.history.state;
      window.history.pushState({
        ...currentState !== null && typeof currentState == "object" ? currentState : {},
        ehpeekOverlay: {
          depth: surfaces.length,
          sessionId: historySessionId,
          surface
        }
      }, "", window.location.href);
    }, exitFullscreen = async () => {
      preserveSurfacesOnFullscreenExit = !0;
      try {
        return await options.overlayHost.fullscreen.exit(), !0;
      } catch (error) {
        return console.warn("[ehpeek] Failed to exit fullscreen", error), !1;
      } finally {
        preserveSurfacesOnFullscreenExit = !1;
      }
    }, closePreview = () => {
      previewOpen() && (surfaces.pop(), previewActions?.close());
    }, syncReaderExit = () => {
      if (progress.flush(), clearPeekLocation(), readerLastPage === readerInitialPage)
        return;
      let exitIndex = previewCache.previewIndexForPage(readerLastPage), galleryUrl = previewUrlForIndex(exitIndex);
      enhancedPreviewActive() ? (gotoPreviewIndex(exitIndex), previewCache.select(exitIndex).catch(() => {
        window.location.replace(galleryUrl);
      })) : exitIndex === readerInitialPreviewIndex ? window.history.replaceState(window.history.state, "", galleryUrl) : window.location.replace(galleryUrl);
    }, closeReader = async () => {
      let activeReader = reader;
      if (!activeReader)
        return;
      reader = null;
      let index = surfaces.lastIndexOf("reader");
      index >= 0 && surfaces.splice(index, 1), await exitFullscreen(), activeReader.dispose(), syncReaderExit();
    }, reconcileHistory = async (event) => {
      let marker = overlayHistoryState(event.state), depth = marker?.sessionId === historySessionId ? marker.depth : 0;
      for (; surfaces.length > depth; )
        topSurface() === "preview" ? closePreview() : await closeReader();
      let afterClose = afterHistoryClose;
      afterHistoryClose = null, historyClosePending = !1, afterClose?.();
    }, onPopState = (event) => {
      reconcileHistory(event);
    };
    window.addEventListener("popstate", onPopState);
    let stopFullscreen = options.overlayHost.fullscreen.subscribe((active) => {
      reader?.setFullscreenActive(active), fullscreenWasActive && !active && !preserveSurfacesOnFullscreenExit && options.exitReaderOnFullscreenExit && reader && window.history.go(-surfaces.length), fullscreenWasActive = active;
    }), gotoPreviewIndex = (previewIndex) => {
      previewOpen() ? previewActions?.gotoPreview(previewIndex) : thumbsActions?.gotoPreview(previewIndex);
    }, activePageChanged = (page2) => {
      page2.pageNum && (readerLastPage = page2.pageNum, enhancedPreviewActive() && gotoPreviewIndex(previewCache.previewIndexForPage(page2.pageNum))), progress.update(page2.pageNum, preview.totalImages), updatePeekLocation(page2.pageNum, preview.pageSize, preview.maxIndex);
    }, requestClose = (surface, afterClose) => {
      historyClosePending || topSurface() !== surface || (historyClosePending = !0, afterHistoryClose = afterClose ?? null, surface === "reader" && clearPeekLocation(), window.history.back());
    }, requestReaderClose = () => !reader || topSurface() !== "reader" ? !1 : (clearPeekLocation(), closeReader(), window.history.back(), !0), toggleFullscreen = () => {
      (options.overlayHost.fullscreen.active() ? exitFullscreen().then(() => {
      }) : options.overlayHost.fullscreen.enter()).catch((error) => {
        console.warn("[ehpeek] Fullscreen request failed", error);
      });
    }, openOriginalPage = (page2) => {
      (async () => await exitFullscreen() && (progress.flush(), window.location.assign(page2.url)))();
    }, mountReader = (startPageNum) => {
      let current = previewCache.current().data;
      readerInitialPage = startPageNum, readerLastPage = startPageNum, readerInitialPreviewIndex = current.currentIndex, pushSurface("reader");
      try {
        reader = mountReaderSurface({
          coordinator,
          options: {
            galleryId: gallery2.galleryId,
            galleryToken: gallery2.token,
            initialPageNum: startPageNum,
            totalPages: current.totalImages
          },
          overlayHost: options.overlayHost,
          previewCache
        });
      } catch (error) {
        throw surfaces.pop(), window.history.back(), error;
      }
    }, openReader = async (startPageUrl, preferredPageNum, requestConfiguredFullscreen = !1) => {
      if (!options.readerEnabled) {
        preferredPageNum !== void 0 && await openOriginalReader(preferredPageNum, previewCache);
        return;
      }
      if (reader) {
        preferredPageNum !== void 0 && readerActions?.gotoPage(preferredPageNum);
        return;
      }
      let startPageNum = preferredPageNum ?? peekPageFromHash() ?? galleryPageNumber(startPageUrl);
      if (!startPageNum)
        throw new Error(i18n_default.errors.imageNotFound);
      let enteredFullscreen = await (requestConfiguredFullscreen && options.readerFullscreenEnabled && !document.fullscreenElement && document.fullscreenEnabled && typeof options.overlayHost.element.requestFullscreen == "function" ? options.overlayHost.fullscreen.enter().then(
        () => !0,
        (error) => (console.warn("[ehpeek] Fullscreen request failed", error), !1)
      ) : null);
      if (enteredFullscreen && !options.overlayHost.fullscreen.active()) {
        await options.overlayHost.fullscreen.restore();
        return;
      }
      try {
        mountReader(startPageNum);
      } catch (error) {
        throw enteredFullscreen && await exitFullscreen(), error;
      }
    };
    function openPreviewPage(pageNum) {
      previewOpen() || pushSurface("preview"), previewActions?.gotoPage(pageNum);
    }
    let coordinator = {
      attachPreview: (actions) => {
        previewActions = actions;
      },
      attachReader: (actions) => {
        readerActions = actions;
      },
      attachThumbs: (actions) => {
        thumbsActions = actions;
      },
      dispose: () => {
        progress.dispose(), reader?.dispose(), reader = null, readerActions = null, previewActions?.close(), window.removeEventListener("popstate", onPopState), stopFullscreen();
      },
      openFromReadButton: () => {
        let pageNum = options.readHistoryEnabled ? progress.progress().currentPage : 1, firstPage = previewCache.current().data.pages[0];
        firstPage && openReader(firstPage.url, pageNum, !0).catch(reportReaderOpenError);
      },
      openGalleryPage: (pageUrl, preferredPageNum) => {
        openReader(pageUrl, preferredPageNum, !0).catch(reportReaderOpenError);
      },
      openPreviewIndex: (previewIndex) => {
        previewOpen() || pushSurface("preview"), previewActions?.gotoPreview(previewIndex);
      },
      openPreviewPage,
      openReaderFromHash: async () => {
        let pageNum = peekPageFromHash();
        if (pageNum === null)
          return;
        let current = previewCache.current().data, page2 = current.pages.find((item) => item.pageNum === pageNum) ?? current.pages[0];
        page2 && await openReader(page2.url, pageNum).catch(reportReaderOpenError);
      },
      openOriginalPage,
      readerActivePageChanged: activePageChanged,
      progress: progress.progress,
      requestClosePreview: (previewIndex) => {
        requestClose("preview", () => syncPreviewExit(previewIndex));
      },
      requestCloseReader: requestReaderClose,
      selectPreviewPage: (pageUrl, pageNum) => {
        requestClose("preview", () => {
          openReader(pageUrl, pageNum, !0).catch(reportReaderOpenError);
        });
      },
      toggleReaderFullscreen: toggleFullscreen
    };
    return coordinator;
    function syncPreviewExit(previewIndex) {
      previewIndex !== previewCache.current().data.currentIndex && (options.enhanceThumbsGridsEnabled || options.replacePreviewWithScroll ? previewCache.select(previewIndex).catch(reportReaderOpenError) : window.location.assign(
        previewUrlForIndex(previewIndex, previewCache.current().data.currentUrl)
      ));
    }
  }
  function createProgressSession(galleryId, token, totalPages, enabled, includeUnread) {
    if (!enabled)
      return new ReadingProgressSession(null, {
        currentPage: 1,
        hasHistory: !1,
        totalPages
      });
    let existing = loadReadHistory(galleryId, token), galleryInfo = extractGalleryHistoryInfo(), record = existing;
    return includeUnread ? record = recordGalleryVisit(galleryId, token, totalPages, galleryInfo) : existing && (record = updateReadHistoryGalleryInfo(galleryId, token, galleryInfo)), new ReadingProgressSession({
      gallery: galleryInfo,
      galleryId,
      token,
      totalPages
    }, {
      currentPage: record?.pageNum && record.pageNum > 0 ? record.pageNum : 1,
      hasHistory: !!(record && record.pageNum > 0),
      totalPages: record?.totalPages ?? totalPages
    });
  }
  function overlayHistoryState(value) {
    if (value === null || typeof value != "object")
      return null;
    let marker = value.ehpeekOverlay;
    return marker === null || typeof marker != "object" || typeof marker.depth != "number" || typeof marker.sessionId != "string" ? null : marker;
  }

  // src/App/GalleryPreviewCache.ts
  var PREVIEW_CACHE_LIMIT = 10;
  function createGalleryPreviewCache(initialPreview) {
    let [current, setCurrent] = createSignal(initialPreview), [loading, setLoading] = createSignal(!1), [previewDataVersion, setPreviewDataVersion] = createSignal(0), previews = /* @__PURE__ */ new Map(), pages = /* @__PURE__ */ new Map(), previewItems = /* @__PURE__ */ new Map(), pending = /* @__PURE__ */ new Map(), pageSize = initialPreview.data.pageSize, maxPreviewIndex = initialPreview.data.maxIndex, currentPreviewIndex = initialPreview.data.currentIndex, selectionId = 0, remember = (preview) => {
      let index = preview.data.currentIndex, expectedItems = preview.data.endImage - preview.data.startImage + 1;
      preview.data.previewItems.length >= expectedItems && (previews.delete(index), previews.set(index, preview));
      for (let page2 of preview.data.pages)
        page2.pageNum && page2.pageNum > 0 && pages.set(page2.pageNum, page2);
      for (let item of preview.data.previewItems)
        previewItems.set(item.pageNum, item);
      for (setPreviewDataVersion((version) => version + 1); previews.size > PREVIEW_CACHE_LIMIT; ) {
        let removable;
        for (let candidate of previews.keys())
          if (candidate !== currentPreviewIndex && candidate !== index) {
            removable = candidate;
            break;
          }
        if (removable === void 0)
          break;
        previews.delete(removable);
      }
    }, previewIndexForPage = (pageNum) => previewPageIndexForGalleryPage(
      pageNum,
      pageSize,
      maxPreviewIndex
    ), load = (previewIndex) => {
      if (previewIndex < 0 || previewIndex > maxPreviewIndex)
        return Promise.reject(new RangeError(`Invalid Preview index: ${previewIndex}`));
      let cached = previews.get(previewIndex);
      if (cached)
        return previews.delete(previewIndex), previews.set(previewIndex, cached), Promise.resolve(cached);
      let existing = pending.get(previewIndex);
      if (existing)
        return existing;
      setLoading(!0);
      let request = loadGalleryPreviewPage(
        previewIndex,
        initialPreview.data.currentUrl
      ).then(
        (preview) => (pending.delete(previewIndex), setLoading(pending.size > 0), remember(preview), preview),
        (error) => {
          throw pending.delete(previewIndex), setLoading(pending.size > 0), error;
        }
      );
      return pending.set(previewIndex, request), request;
    }, getPages = async (pageNums) => {
      let requested = Array.from(new Set(pageNums.filter((pageNum) => pageNum > 0))), previewIndexes = Array.from(new Set(requested.filter((pageNum) => !pages.has(pageNum)).map(previewIndexForPage)));
      return await Promise.all(previewIndexes.map(load)), requested.flatMap((pageNum) => pages.get(pageNum) ?? []);
    }, getPreviewItems = async (pageNums) => {
      let requested = Array.from(new Set(pageNums.filter((pageNum) => pageNum > 0))), previewIndexes = Array.from(new Set(requested.filter((pageNum) => !previewItems.has(pageNum)).map(previewIndexForPage)));
      return await Promise.all(previewIndexes.map(load)), requested.flatMap((pageNum) => previewItems.get(pageNum) ?? []);
    }, select2 = async (previewIndex) => {
      if (previewIndex === current().data.currentIndex)
        return current();
      let activeSelection = ++selectionId, preview = await load(previewIndex);
      return activeSelection === selectionId && (currentPreviewIndex = preview.data.currentIndex, setCurrent(preview), window.history.replaceState(
        window.history.state,
        "",
        preview.data.currentUrl
      )), preview;
    };
    return remember(initialPreview), {
      current,
      getPages,
      getPreviewItems,
      load,
      loadImage: loadEhImagePage,
      loading,
      previewDataVersion,
      previewIndexForPage,
      previewItem: (pageNum) => (previewDataVersion(), previewItems.get(pageNum) ?? null),
      select: select2
    };
  }

  // src/App/host.ts
  function createAppMount(className2 = "", host = document.body) {
    let mount = createManagedElement("div");
    return className2 && mount.replaceClasses(className2), host.append(mount.Component()), mount;
  }

  // src/App/index.tsx
  var _tmpl$71 = /* @__PURE__ */ template('<span class="inline-block ml-auto opacity-72 [font-size:0.9em] font-600 whitespace-nowrap">'), _tmpl$218 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full max-w-full min-h-sm items-center gap-sm py-sm px-xs border-0 bg-transparent text-[var(--color-site-accent)] hover:bg-[var(--color-site-accent-hover)] shadow-none cursor-pointer text-left font-inherit [font-size:1.05em] font-700 leading-[1.2]">'), _tmpl$314 = /* @__PURE__ */ template('<span class="block ehp-color-site-accent [font-size:var(--ui-font-size-sm)] font-600 opacity-78 normal-case">'), _tmpl$413 = /* @__PURE__ */ template('<button type=button class="flex min-w-0 w-full h-full ui-hit-min-h-xl flex-col items-center justify-center ui-gap-xs ui-py-md ui-px-lg border-0 bg-transparent ehp-color-site-accent text-center uppercase [touch-action:manipulation] [font-size:var(--ui-font-size-lg)] font-700">'), _tmpl$510 = /* @__PURE__ */ template("<a href=#>"), _tmpl$610 = /* @__PURE__ */ template("<div>");
  function settingsMenuState(defaults = !1) {
    let read = (setting) => defaults ? setting.defaultValue : setting.value;
    return {
      openGalleryInNewTab: read(state.app.openGalleryInNewTab),
      locale: read(state.app.locale),
      readerEnabled: read(state.reader.enabled),
      exitReaderOnFullscreenExit: read(state.reader.exitOnFullscreenExit),
      readerFullscreenEnabled: read(state.reader.fullscreen),
      replacePreviewWithScroll: read(state.gallery.replacePreviewWithScroll),
      enhanceThumbsGridsEnabled: read(state.gallery.enhanceThumbs),
      enhanceSearchGridsEnabled: read(state.search.enhance),
      myTagsEnabled: read(state.gallery.myTags),
      readHistoryEnabled: read(state.gallery.readHistory),
      includeUnreadHistoryEnabled: read(state.gallery.includeUnreadHistory),
      searchHistoryEnabled: read(state.search.history),
      touchUiEnabled: read(state.touch.enabled),
      uiScale: read(currentUiScaleSetting())
    };
  }
  function applySettingsMenuState(next) {
    next.touchUiEnabled || clearBackToTopPosition(), state.app.openGalleryInNewTab.set(next.openGalleryInNewTab), state.app.locale.set(next.locale), state.reader.enabled.set(next.readerEnabled), state.reader.exitOnFullscreenExit.set(next.exitReaderOnFullscreenExit), state.reader.fullscreen.set(next.readerFullscreenEnabled), state.gallery.replacePreviewWithScroll.set(next.replacePreviewWithScroll), state.gallery.enhanceThumbs.set(next.enhanceThumbsGridsEnabled), state.search.enhance.set(next.enhanceSearchGridsEnabled), state.gallery.myTags.set(next.myTagsEnabled), state.gallery.readHistory.set(next.readHistoryEnabled), state.gallery.includeUnreadHistory.set(next.includeUnreadHistoryEnabled), state.search.history.set(next.searchHistoryEnabled), state.touch.enabled.set(next.touchUiEnabled), currentUiScaleSetting().set(next.uiScale), window.location.reload();
  }
  var gState = (() => {
    let settings2 = settingsMenuState(), [columnsEnabled, setColumnsEnabled] = createSignal(currentColumnsEnabled()), [leftHandedControls, setLeftHandedControls2] = createSignal(state.app.leftHandedControls.value), [settingsMenuOpen, setSettingsMenuOpen] = createSignal(!1), [uiScale, setUiScale] = createSignal(currentUiScale());
    return {
      columnsEnabled,
      leftHandedControls,
      setLeftHandedControls: setLeftHandedControls2,
      settings: settings2,
      settingsMenuOpen,
      setUiScale,
      setColumnsEnabled,
      setSettingsMenuOpen,
      uiScale
    };
  })();
  function currentUiScale() {
    return currentUiScaleSetting().value;
  }
  function currentUiScaleSetting() {
    return window.matchMedia("(orientation: landscape)").matches ? state.app.landscapeUiScale : state.app.portraitUiScale;
  }
  function currentColumnsEnabled() {
    return window.matchMedia("(orientation: landscape)").matches ? state.touch.landscapeColumns.value : state.touch.portraitColumns.value;
  }
  var overlayHost;
  function updateUiScale() {
    let scale = currentUiScale();
    gState.setUiScale(scale), applyUiScale(scale), overlayHost?.setUiScale(scale);
  }
  function updateColumnsLayout() {
    gState.settings.touchUiEnabled && gState.setColumnsEnabled(currentColumnsEnabled());
  }
  function setCurrentColumnsEnabled(enabled) {
    (window.matchMedia("(orientation: landscape)").matches ? state.touch.landscapeColumns : state.touch.portraitColumns).set(enabled), gState.setColumnsEnabled(enabled);
  }
  function setCurrentUiScale(scale) {
    currentUiScaleSetting().set(scale), gState.setUiScale(scale), applyUiScale(scale), overlayHost?.setUiScale(scale);
  }
  function setLeftHandedControls(enabled) {
    state.app.leftHandedControls.set(enabled), gState.setLeftHandedControls(enabled);
  }
  configureUi({
    pointer: window.matchMedia("(hover: hover) and (pointer: fine)").matches ? "mouse" : "touch",
    site: ehSiteTheme()
  });
  var PRESS_MIN_VISIBLE_MS = 100, PRESS_MOVE_TOLERANCE_PX = 8, pressedInteraction, pressedClearTimer, pendingPress, clearPressedInteraction = () => {
    pressedClearTimer !== void 0 && (window.clearTimeout(pressedClearTimer), pressedClearTimer = void 0), pendingPress = void 0, pressedInteraction?.removeAttribute("data-ehpeek-pressed"), pressedInteraction = void 0;
  }, showPressedInteraction = (interaction) => {
    pressedInteraction = interaction, interaction.setAttribute("data-ehpeek-pressed", "true");
  }, releasePressedInteraction = () => {
    pressedClearTimer = window.setTimeout(clearPressedInteraction, PRESS_MIN_VISIBLE_MS);
  };
  document.addEventListener("pointerdown", (event) => {
    event.pointerType !== "mouse" && setUiPointer("touch"), clearPressedInteraction();
    let interaction = event.target instanceof Element ? event.target.closest("[data-ehpeek-pressable=true], a[href], button, input, select, textarea, label, [onclick], [role=button], [role=tab]") : null;
    interaction?.closest(".ehpeek-ui-root") && (pendingPress = {
      interaction,
      pointerId: event.pointerId,
      startX: event.clientX,
      startY: event.clientY
    });
  }, {
    capture: !0,
    passive: !0
  });
  document.addEventListener("pointerup", (event) => {
    pendingPress?.pointerId === event.pointerId && (showPressedInteraction(pendingPress.interaction), pendingPress = void 0, releasePressedInteraction());
  }, {
    capture: !0,
    passive: !0
  });
  document.addEventListener("pointercancel", clearPressedInteraction, {
    capture: !0,
    passive: !0
  });
  document.addEventListener("pointermove", (event) => {
    event.pointerType === "mouse" && setUiPointer("mouse"), pendingPress?.pointerId === event.pointerId && Math.hypot(event.clientX - pendingPress.startX, event.clientY - pendingPress.startY) > PRESS_MOVE_TOLERANCE_PX && clearPressedInteraction();
  }, {
    capture: !0,
    passive: !0
  });
  updateUiScale();
  registerGlobalStyle("ehpeek-uno-style", ehpeek_uno_default);
  registerGlobalStyle("ehpeek-theme-style", theme_default);
  registerGlobalStyle("ehpeek-dom-style", styles_default);
  function allowFeatureFailure(name, run) {
    try {
      run();
    } catch (error) {
      console.error(`[ehpeek] ${name} failed`, error);
    }
  }
  async function allowAsyncFeatureFailure(name, run) {
    try {
      await run();
    } catch (error) {
      console.error(`[ehpeek] ${name} failed`, error);
    }
  }
  function requirePageDependency(name, dependency) {
    if (dependency === null)
      throw new Error(`Cannot initialize ${name}.`);
    return dependency;
  }
  function readButtonLabel(progress) {
    return progress.hasHistory ? i18n_default.reader.continueReading : i18n_default.reader.startReading;
  }
  function readButtonProgress(progress) {
    return progress.totalPages ? `${progress.currentPage}/${progress.totalPages}` : String(progress.currentPage);
  }
  function GalleryReadButton(props) {
    return (() => {
      var _el$ = _tmpl$218();
      return _el$.$$click = (event) => {
        event.preventDefault(), event.stopPropagation(), props.onRead();
      }, insert(_el$, () => readButtonLabel(props.progress()), null), insert(_el$, createComponent(Show, {
        get when() {
          return props.progress().hasHistory;
        },
        get children() {
          var _el$2 = _tmpl$71();
          return insert(_el$2, () => readButtonProgress(props.progress())), _el$2;
        }
      }), null), createRenderEffect((_p$) => {
        var _v$ = readButtonLabel(props.progress()), _v$2 = readButtonLabel(props.progress());
        return _v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "title", _p$.t = _v$2), _p$;
      }, {
        e: void 0,
        t: void 0
      }), _el$;
    })();
  }
  function TouchGalleryReadButton(props) {
    return (() => {
      var _el$3 = _tmpl$413();
      return _el$3.$$click = (event) => {
        event.preventDefault(), event.stopPropagation(), props.onRead();
      }, insert(_el$3, () => readButtonLabel(props.progress()), null), insert(_el$3, createComponent(Show, {
        get when() {
          return props.progress().hasHistory;
        },
        get children() {
          var _el$4 = _tmpl$314();
          return insert(_el$4, () => readButtonProgress(props.progress())), _el$4;
        }
      }), null), createRenderEffect((_p$) => {
        var _v$3 = readButtonLabel(props.progress()), _v$4 = readButtonLabel(props.progress());
        return _v$3 !== _p$.e && setAttribute(_el$3, "aria-label", _p$.e = _v$3), _v$4 !== _p$.t && setAttribute(_el$3, "title", _p$.t = _v$4), _p$;
      }, {
        e: void 0,
        t: void 0
      }), _el$3;
    })();
  }
  function installSettingsMenu() {
    typeof GM_registerMenuCommand == "function" && GM_registerMenuCommand(i18n_default.settings.openSettings, () => {
      gState.setSettingsMenuOpen(!0);
    }), createAppMount("fixed inset-0 z-[1150] pointer-events-none", overlayHost.element).mount(() => createComponent(OverlayHostProvider, {
      host: overlayHost,
      get children() {
        return createComponent(SettingsMenu, {
          get historyHref() {
            return readHistoryUrl();
          },
          get leftHandedControls() {
            return gState.leftHandedControls;
          },
          get open() {
            return gState.settingsMenuOpen();
          },
          get defaultState() {
            return settingsMenuState(!0);
          },
          get initState() {
            return {
              ...gState.settings,
              uiScale: gState.uiScale()
            };
          },
          onApply: (next) => {
            applySettingsMenuState(next);
          },
          get onOpenChange() {
            return gState.setSettingsMenuOpen;
          }
        });
      }
    }));
  }
  function injectCommon(page2) {
    if (!gState.settings.touchUiEnabled) {
      allowFeatureFailure("Desktop settings entry", () => {
        let settingsMount = manageSettingsMenuMount();
        settingsMount && settingsMount.mount(() => (() => {
          var _el$5 = _tmpl$510();
          return _el$5.$$click = (event) => {
            event.preventDefault(), event.stopPropagation(), gState.setSettingsMenuOpen(!0);
          }, insert(_el$5, "EhPeek"), _el$5;
        })());
      });
      return;
    }
    allowFeatureFailure("Touch top bar", () => {
      let topBarDom = manageTopBar();
      if (!topBarDom)
        return;
      let columnsAvailable = page2.type === "gallery" || page2.type === "readHistory" || (page2.type === "search" || page2.type === "favorites") && state.search.grid.value !== null;
      topBarDom.elems.mount.mount(() => createComponent(TouchTopBar, {
        get historyHref() {
          return memo(() => !!gState.settings.readHistoryEnabled)() ? readHistoryUrl() : void 0;
        },
        get leftHandedControls() {
          return {
            enabled: gState.leftHandedControls,
            onChange: setLeftHandedControls
          };
        },
        get uiScale() {
          return {
            value: gState.uiScale,
            onChange: setCurrentUiScale
          };
        },
        get columns() {
          return columnsAvailable ? {
            enabled: gState.columnsEnabled,
            onChange: setCurrentColumnsEnabled
          } : void 0;
        },
        source: topBarDom,
        onSettingsMenuOpen: () => {
          gState.setSettingsMenuOpen(!0);
        }
      }));
    }), (page2.type === "gallery" || page2.type === "search" || page2.type === "favorites" || page2.type === "readHistory") && allowFeatureFailure("Back to top", () => {
      createAppMount().mount(() => createComponent(BackToTop, {
        get leftHanded() {
          return gState.leftHandedControls;
        }
      }));
    });
  }
  function injectGalleryDetails(previewCache, coordinator) {
    let preview = previewCache.current();
    allowFeatureFailure("Touch GalleryInfo", () => {
      mutateGalleryTouchLayout();
      let galleryInfoDom = requirePageDependency("Touch GalleryInfo", manageGalleryInfo(preview.data));
      galleryInfoDom.handle.installGalleryInfoPanel(), galleryInfoDom.elems.mount.mount(() => createComponent(OverlayHostProvider, {
        host: overlayHost,
        get children() {
          return createComponent(GalleryInfoPanel, {
            get leftHandedControls() {
              return gState.leftHandedControls;
            },
            source: galleryInfoDom,
            get primaryAction() {
              return createComponent(TouchGalleryReadButton, {
                get onRead() {
                  return coordinator.openFromReadButton;
                },
                get progress() {
                  return coordinator.progress;
                }
              });
            }
          });
        }
      }));
      let wideLayout = requirePageDependency("Touch Gallery layout", mutateGalleryWideLayout(galleryInfoDom, preview, gState.columnsEnabled(), gState.settings.replacePreviewWithScroll));
      createEffect(() => wideLayout.updateEnabled(gState.columnsEnabled()));
    }), allowFeatureFailure("Touch Gallery comments", () => {
      manageGalleryCommentsTouch(reportReaderOpenError);
    });
  }
  function injectGalleryPreview(previewCache, coordinator) {
    let preview = previewCache.current(), previewMount = preview.elems.mount;
    gState.settings.readerEnabled && allowFeatureFailure("Reader thumbnail links", () => {
      preview.handle.interceptPreviewImageOpen((pageUrl) => {
        coordinator.openGalleryPage(pageUrl);
      });
    }), gState.settings.touchUiEnabled || allowFeatureFailure("Desktop Read button", () => {
      manageGalleryContinueReadingButtonMount().mount(() => createComponent(GalleryReadButton, {
        get onRead() {
          return coordinator.openFromReadButton;
        },
        get progress() {
          return coordinator.progress;
        }
      }));
    }), previewMount && allowFeatureFailure("Gallery Preview enhancements", () => {
      gState.settings.replacePreviewWithScroll && preview.handle.removeOriginalPreview(), previewMount.mount(() => createComponent(OverlayHostProvider, {
        host: overlayHost,
        get children() {
          var _el$6 = _tmpl$610();
          return insert(_el$6, createComponent(ScrollPreview, {
            coordinator,
            get embeddedDirection() {
              return memo(() => !!gState.columnsEnabled())() ? state.gallery.embeddedScrollPreviewColumnsDirection.value : state.gallery.embeddedScrollPreviewSingleDirection.value;
            },
            get fillEmbeddedContainer() {
              return gState.columnsEnabled;
            },
            get leftHandedControls() {
              return gState.leftHandedControls;
            },
            onLoadError: reportReaderOpenError,
            onEmbeddedDirectionChange: (direction) => {
              gState.columnsEnabled() ? state.gallery.embeddedScrollPreviewColumnsDirection.set(direction) : state.gallery.embeddedScrollPreviewSingleDirection.set(direction);
            },
            onReadDirectionChange: (direction) => {
              state.gallery.scrollPreviewDirection.set(direction);
            },
            previewCache,
            get readDirection() {
              return state.gallery.scrollPreviewDirection.value;
            },
            get replaceOriginalPreview() {
              return gState.settings.replacePreviewWithScroll;
            }
          }), null), insert(_el$6, (() => {
            var _c$ = memo(() => !!(gState.settings.enhanceThumbsGridsEnabled && !gState.settings.replacePreviewWithScroll));
            return () => _c$() ? createComponent(ThumbsGrids, {
              coordinator,
              onLoadError: reportReaderOpenError,
              previewCache
            }) : null;
          })(), null), createRenderEffect((_$p) => classList(_el$6, {
            contents: !gState.settings.replacePreviewWithScroll,
            "relative h-full w-full [--scroll-preview-height:100%]": gState.settings.replacePreviewWithScroll && gState.settings.touchUiEnabled && gState.columnsEnabled(),
            "relative [--scroll-preview-height:55lvh] [width:min(calc(100%-(var(--touch-gallery-gutter)*2)),90lvh)] mx-auto": gState.settings.replacePreviewWithScroll && gState.settings.touchUiEnabled && !gState.columnsEnabled(),
            "relative [--scroll-preview-height:70svh] w-[min(calc(100%-32px),1212px)] mx-auto": gState.settings.replacePreviewWithScroll && !gState.settings.touchUiEnabled
          }, _$p)), _el$6;
        }
      }));
    });
  }
  function injectGalleryPage(page2) {
    let preview = manageGalleryPreview(), previewCache = createGalleryPreviewCache(preview), coordinator = createGalleryCoordinator({
      enhanceThumbsGridsEnabled: gState.settings.enhanceThumbsGridsEnabled,
      exitReaderOnFullscreenExit: gState.settings.exitReaderOnFullscreenExit,
      includeUnreadHistoryEnabled: gState.settings.includeUnreadHistoryEnabled,
      overlayHost,
      previewCache,
      readHistoryEnabled: gState.settings.readHistoryEnabled,
      readerEnabled: gState.settings.readerEnabled,
      readerFullscreenEnabled: gState.settings.readerFullscreenEnabled,
      replacePreviewWithScroll: gState.settings.replacePreviewWithScroll
    });
    gState.settings.myTagsEnabled && allowFeatureFailure("Gallery My Tags appearance", () => {
      let myTagAppearances = loadMyTagAppearances();
      if (myTagAppearances) {
        mutateGalleryMyTags(myTagAppearances);
        return;
      }
      allowAsyncFeatureFailure("My Tags appearance", async () => {
        let appearances = await refreshMyTags();
        appearances && mutateGalleryMyTags(appearances);
      });
    }), gState.settings.touchUiEnabled && injectGalleryDetails(previewCache, coordinator), injectGalleryPreview(previewCache, coordinator), state.reader.enabled.value && page2.peekPage !== null && allowAsyncFeatureFailure("Reader deep link", async () => {
      await coordinator.openReaderFromHash();
    });
  }
  function injectSearchControls(page2) {
    let touchResultsDom = manageTouchResultsPage(page2);
    return allowFeatureFailure("Touch Search panel", () => {
      let searchPanelDom = manageSearchPanel();
      searchPanelDom && (markUiRoot(searchPanelDom.elems.form.Component()), searchPanelDom.elems.mount.mount(() => createComponent(TouchSearchPanel, {
        source: searchPanelDom,
        get after() {
          return memo(() => !!touchResultsDom.data.favoritesCategory)() ? createComponent(FavoritesCategorySelect, {
            source: touchResultsDom
          }) : void 0;
        }
      })), searchPanelDom.elems.categoryToggleMount?.mount(() => createComponent(TouchSearchCategoryToggle, {
        source: searchPanelDom
      })), searchPanelDom.elems.advancedToggleMount?.mount(() => createComponent(TouchSearchOptionToggle, {
        option: "advancedOptions",
        source: searchPanelDom
      })), searchPanelDom.elems.fileSearchToggleMount?.mount(() => createComponent(TouchSearchOptionToggle, {
        option: "fileSearch",
        source: searchPanelDom
      })), searchPanelDom.elems.searchActionMount.mount(() => createComponent(TouchSearchAction, {
        action: "search",
        source: searchPanelDom
      })), searchPanelDom.elems.clearActionMount?.mount(() => createComponent(TouchSearchAction, {
        action: "clear",
        source: searchPanelDom
      })));
    }), touchResultsDom;
  }
  function injectSearchPage(page2) {
    let initialResultsDom = requirePageDependency("Search results", manageSearchResults()), [resultsDom, setResultsDom] = createSignal(initialResultsDom);
    markUiRoot(initialResultsDom.elems.resultList.Component());
    let updateSearchGridModeSelector = () => {
      mutateSearchGridModeSelect(state.search.grid.value, (mode) => {
        state.search.grid.set(mode), window.location.assign(new URL("/?inline_set=dm_e", window.location.href).href);
      }, () => {
        state.search.grid.set(null);
      });
    };
    allowFeatureFailure("Search grid mode selector", updateSearchGridModeSelector);
    let searchGridMode = state.search.grid.value;
    searchGridMode && allowFeatureFailure("Search grid", () => manageSearchGrids(searchGridMode));
    let updateSearchReadHistoryAppearance = () => {
      gState.settings.readHistoryEnabled && mutateSearchReadHistoryAppearance(loadReadHistory);
    };
    allowFeatureFailure("Search Read History appearance", updateSearchReadHistoryAppearance), gState.settings.openGalleryInNewTab && allowFeatureFailure("Gallery links in new tabs", () => {
      initialResultsDom.handle.listenGalleryLinksOpenInNewTab();
    });
    let updateSearchPage = (source) => {
      setResultsDom(source), updateSearchGridModeSelector(), searchGridMode && manageSearchGrids(searchGridMode), updateSearchReadHistoryAppearance();
    }, mountSearchPagination = (onPageChange) => {
      gState.settings.enhanceSearchGridsEnabled && allowFeatureFailure("Enhanced Search pagination", () => {
        createAppMount().mount(() => createComponent(EnhanceSearchGrids, {
          source: initialResultsDom,
          onPageChange: (source) => allowFeatureFailure("Changed Search page", () => onPageChange(source))
        }));
      });
    };
    if (gState.settings.touchUiEnabled) {
      let touchResultsDom = injectSearchControls(page2);
      createEffect(() => {
        resultsDom().handle.updateResultColumns(gState.columnsEnabled());
      }), mountSearchPagination((source) => {
        markUiRoot(source.elems.resultList.Component()), updateSearchPage(source), touchResultsDom.handle.updateTouchResultsLayout();
      });
    } else
      mountSearchPagination(updateSearchPage);
    gState.settings.searchHistoryEnabled && allowFeatureFailure("Search history", () => {
      let searchTextInput = manageSearchTextInput();
      if (!searchTextInput)
        return;
      createAppMount().mount(() => createComponent(SearchHistory, {
        source: searchTextInput
      }));
    });
  }
  function injectReadHistoryPage(page2) {
    let records = loadDisplayReadHistoryRecords(), pageCount = Math.max(1, Math.ceil(records.length / 25)), pageIndex = Math.min(page2.pageIndex, pageCount - 1), items = records.map((record) => ({
      currentPage: record.pageNum,
      galleryId: record.galleryId,
      info: record.gallery,
      token: record.token,
      totalPages: record.totalPages,
      updatedAt: record.updatedAt
    })), historyDom = requirePageDependency("Read History page", manageReadHistoryPage(items.slice(pageIndex * 25, (pageIndex + 1) * 25), state.gallery.titlePreference.reload(), state.search.grid.value ?? "ehpeek-lite"));
    markUiRoot(historyDom.elems.resultList.Component()), gState.settings.touchUiEnabled && (createEffect(() => {
      historyDom.handle.updateResultColumns(gState.columnsEnabled());
    }), allowFeatureFailure("Touch Read History layout", () => {
      manageTouchResultsPage(page2);
    })), historyDom.elems.navigationTopMount.mount(() => createComponent(ReadHistoryPage, {
      initialPageIndex: pageIndex,
      items,
      pageSize: 25,
      source: historyDom
    }));
  }
  function injectImagePage(page2) {
    if (!gState.settings.readHistoryEnabled)
      return;
    let gallery2 = requirePageDependency("Image Gallery data", extractImageGalleryPage());
    if (gallery2.galleryId !== page2.galleryId)
      return;
    let previous = loadReadHistory(gallery2.galleryId, gallery2.token);
    new ReadingProgressSession({
      gallery: previous?.gallery,
      galleryId: gallery2.galleryId,
      token: gallery2.token,
      totalPages: previous?.totalPages
    }, {
      currentPage: previous?.pageNum && previous.pageNum > 0 ? previous.pageNum : 1,
      hasHistory: !!(previous && previous.pageNum > 0),
      totalPages: previous?.totalPages ?? null
    }).update(page2.pageNum, previous?.totalPages);
  }
  function injectPage(page2) {
    switch (updateUiScale(), injectCommon(page2), page2.type) {
      case "gallery":
        allowFeatureFailure("Gallery page", () => injectGalleryPage(page2));
        break;
      case "favorites":
      case "search":
        allowFeatureFailure("Search page", () => injectSearchPage(page2));
        break;
      case "readHistory":
        allowFeatureFailure("Read History page", () => injectReadHistoryPage(page2));
        break;
      case "image":
        allowFeatureFailure("Image page", () => injectImagePage(page2));
        break;
      case "myTags":
        gState.settings.myTagsEnabled && allowAsyncFeatureFailure("My Tags refresh", async () => {
          await refreshMyTags(extractMyTagsPageData());
        });
        break;
      case "settings": {
        let titlePreference = extractGalleryTitlePreference();
        titlePreference && state.gallery.titlePreference.set(titlePreference);
        break;
      }
      case "other":
        break;
    }
  }
  ehSyringe_exports.initialize();
  var historyRouteActive = extractPageType().type === "readHistory";
  window.addEventListener("hashchange", () => {
    let nextHistoryRouteActive = extractPageType().type === "readHistory";
    historyRouteActive !== nextHistoryRouteActive && window.location.reload(), historyRouteActive = nextHistoryRouteActive;
  });
  async function startApp() {
    document.readyState === "loading" && await new Promise((resolve) => {
      document.addEventListener("DOMContentLoaded", () => resolve(), {
        once: !0
      });
    }), overlayHost = createOverlayHost(document.body, currentUiScale());
    let page2 = extractPageType(), onViewportResize = () => {
      updateUiScale(), updateColumnsLayout();
    };
    window.addEventListener("resize", onViewportResize, {
      passive: !0
    }), createRoot(() => {
      installSettingsMenu(), injectPage(page2);
    }), dispatchReady();
  }
  startApp().catch((error) => {
    console.error("[ehpeek] App startup failed", error);
  });
  delegateEvents(["click"]);
})();
/*! Bundled license information:

lucide-solid/dist/esm/defaultAttributes.mjs:
lucide-solid/dist/esm/context.mjs:
lucide-solid/dist/esm/shared/src/utils/hasA11yProp.mjs:
lucide-solid/dist/esm/shared/src/utils/mergeClasses.mjs:
lucide-solid/dist/esm/shared/src/utils/toKebabCase.mjs:
lucide-solid/dist/esm/shared/src/utils/toCamelCase.mjs:
lucide-solid/dist/esm/shared/src/utils/toPascalCase.mjs:
lucide-solid/dist/esm/Icon.mjs:
lucide-solid/dist/esm/icons/arrow-down.mjs:
lucide-solid/dist/esm/icons/arrow-left.mjs:
lucide-solid/dist/esm/icons/arrow-right.mjs:
lucide-solid/dist/esm/icons/arrow-up.mjs:
lucide-solid/dist/esm/icons/book-open.mjs:
lucide-solid/dist/esm/icons/check.mjs:
lucide-solid/dist/esm/icons/chevron-left.mjs:
lucide-solid/dist/esm/icons/chevron-right.mjs:
lucide-solid/dist/esm/icons/columns-2.mjs:
lucide-solid/dist/esm/icons/download.mjs:
lucide-solid/dist/esm/icons/ellipsis-vertical.mjs:
lucide-solid/dist/esm/icons/external-link.mjs:
lucide-solid/dist/esm/icons/file.mjs:
lucide-solid/dist/esm/icons/grid-2x2.mjs:
lucide-solid/dist/esm/icons/heart.mjs:
lucide-solid/dist/esm/icons/history.mjs:
lucide-solid/dist/esm/icons/house.mjs:
lucide-solid/dist/esm/icons/hand.mjs:
lucide-solid/dist/esm/icons/info.mjs:
lucide-solid/dist/esm/icons/locate-fixed.mjs:
lucide-solid/dist/esm/icons/maximize.mjs:
lucide-solid/dist/esm/icons/minimize.mjs:
lucide-solid/dist/esm/icons/move-horizontal.mjs:
lucide-solid/dist/esm/icons/move-vertical.mjs:
lucide-solid/dist/esm/icons/palette.mjs:
lucide-solid/dist/esm/icons/pencil.mjs:
lucide-solid/dist/esm/icons/play.mjs:
lucide-solid/dist/esm/icons/refresh-cw.mjs:
lucide-solid/dist/esm/icons/rows-3.mjs:
lucide-solid/dist/esm/icons/scan-line.mjs:
lucide-solid/dist/esm/icons/search.mjs:
lucide-solid/dist/esm/icons/settings.mjs:
lucide-solid/dist/esm/icons/sparkles.mjs:
lucide-solid/dist/esm/icons/star.mjs:
lucide-solid/dist/esm/icons/x.mjs:
lucide-solid/dist/esm/icons/zoom-in.mjs:
lucide-solid/dist/esm/icons/zoom-out.mjs:
  (**
   * @license lucide-solid v1.26.0 - ISC
   *
   * This source code is licensed under the ISC license.
   * See the LICENSE file in the root directory of this source tree.
   *)
*/