diff --git a/.agents/skills/source-command-flutter-marionette/SKILL.md b/.agents/skills/source-command-flutter-marionette/SKILL.md deleted file mode 100644 index f2c1083f..00000000 --- a/.agents/skills/source-command-flutter-marionette/SKILL.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -name: "source-command-flutter-marionette" -description: "Inspect a running Flutter app — take screenshots, read logs, tap elements, hot-reload. Requires the app to be running in debug mode with a VM service URI." ---- - -# source-command-flutter-marionette - -Use this skill when the user asks to run the migrated source command `flutter-marionette`. - -## Command Template - -Interact with a running Flutter app using the `marionette` CLI. - -> First time? See the setup guide in `.github/skills/flutter-marionette/README.md` -> to instrument your app and install the MCP servers. - -## Setup - -The app must be running in debug mode. The VM service URI is printed in the -console when you run `flutter run` (e.g. `ws://127.0.0.1:XXXXX/ws`). - -**Option A — Named instance (reuse across commands):** - -```sh -marionette register my-app ws://127.0.0.1:XXXXX/ws -marionette -i my-app -marionette unregister my-app # cleanup when done -``` - -**Option B — Direct URI (one-off):** - -```sh -marionette --uri ws://127.0.0.1:XXXXX/ws -``` - -Check registered instances and connectivity: - -```sh -marionette list -marionette doctor -``` - -## Common tasks - -### Take a screenshot - -```sh -marionette -i my-app take-screenshots --output ./screenshot.png -``` - -Multi-window apps produce numbered files: `screenshot.png`, `screenshot_1.png`, … - -### Get logs - -```sh -marionette -i my-app get-logs -``` - -### Discover UI elements - -```sh -marionette -i my-app get-interactive-elements -``` - -### Tap / interact - -```sh -marionette -i my-app tap --key submit_button # by ValueKey (most reliable) -marionette -i my-app tap --text "Open Book" # by visible text -marionette -i my-app tap --x 100 --y 200 # by coordinates -marionette -i my-app enter-text --key field --input "value" -marionette -i my-app scroll-to --text "Item" -marionette -i my-app press-back-button -``` - -### Hot reload - -```sh -marionette -i my-app hot-reload -``` - -## Error recovery - -If a command fails with a connection error, run `marionette doctor` to check -all instances, then `marionette unregister ` to clean up stale entries. -Re-run `flutter run` if needed and register the new URI. diff --git a/.codex/config.toml b/.codex/config.toml deleted file mode 100644 index a52f6264..00000000 --- a/.codex/config.toml +++ /dev/null @@ -1,10 +0,0 @@ -[mcp_servers.dart] -command = "dart" -args = ["mcp-server"] - -[mcp_servers.marionette] -command = "dart" -args = [ - "run", - "marionette_mcp", -] diff --git a/.github/instructions/ci.instructions.md b/.github/instructions/ci.instructions.md index 42191ee6..a83db031 100644 --- a/.github/instructions/ci.instructions.md +++ b/.github/instructions/ci.instructions.md @@ -37,6 +37,30 @@ Use `bin/prepare-release ` before tagging. It: Do not automate this in the CI pipeline — the changelog rewrite should be in the tagged commit itself, not a commit pushed by the workflow after tagging. +## `dart format` and `pub get` ordering + +`analysis_options.base.yaml` sets `formatter: page_width: 120`. `dart format` only reads this setting if it can resolve the `flutter_lints` include — which requires `pub get` to have been run first. Without `pub get`, the formatter silently falls back to 80-char page width and produces different (narrower) output. + +**Always run `flutter pub get` before `dart format`**, both locally and in CI. `bin/format` does this automatically. In CI workflows, the existing `Install dependencies` step runs `flutter pub get` before the `Check formatting` step — preserve that ordering. + +## Flutter version pinning + +All workflows pin Flutter via `.flutter-version` (the fvm version file). **Do not use `flutter-version-file:` in `subosito/flutter-action`** — that input treats the version as a semver constraint and resolves to the latest matching stable, not an exact pin. Instead, read the file in a dedicated step and pass the result as `flutter-version:`: + +```yaml +- name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + +- uses: subosito/flutter-action@ # v2.x + with: + flutter-version: ${{ steps.flutter_version.outputs.version }} + cache: true + pub-cache: true +``` + +Omit `channel:` when an exact version is passed — it's inferred and `channel: stable` in combination with `flutter-version-file:` was observed to override the pinned version with latest stable. + ## Integration vs build workflows `flutter test integration_test` performs its own build internally (targeting the emulator/simulator) and cannot consume a pre-built APK/app from the build workflows. Don't couple the integration-test workflow to the build workflows — they serve different purposes. Share only caching patterns. diff --git a/.github/instructions/typescript.instructions.md b/.github/instructions/typescript.instructions.md index 9e63bd11..6e8cb75a 100644 --- a/.github/instructions/typescript.instructions.md +++ b/.github/instructions/typescript.instructions.md @@ -16,7 +16,7 @@ applyTo: 'flutter_readium/web/**/*.ts' ## Built JS -Do **not** hand-edit the compiled JS in `example/web/`. Edit TS sources in `flutter_readium/web/_scripts/`, then run `bin/update_web_example` from the repo root to rebuild and copy the bundle. +Do **not** hand-edit the compiled JS in `example/web/`. Edit TS sources in `flutter_readium/web/src/`, then run `bin/update_web_example` from the repo root to rebuild and copy the bundle. ## Linting diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index d46a40b4..ec225490 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -27,10 +27,13 @@ jobs: distribution: jetbrains java-version: '21' + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml index bc9629a2..d160ba19 100644 --- a/.github/workflows/build-ios.yml +++ b/.github/workflows/build-ios.yml @@ -13,10 +13,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 2070b705..b9bb6612 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -11,10 +11,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/integration-test-android.yml b/.github/workflows/integration-test-android.yml index 53c33d6d..b5bf7174 100644 --- a/.github/workflows/integration-test-android.yml +++ b/.github/workflows/integration-test-android.yml @@ -40,10 +40,13 @@ jobs: distribution: jetbrains java-version: '21' + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/integration-test-ios.yml b/.github/workflows/integration-test-ios.yml index a930c5c2..a0d5766d 100644 --- a/.github/workflows/integration-test-ios.yml +++ b/.github/workflows/integration-test-ios.yml @@ -23,10 +23,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true - name: Cache CocoaPods diff --git a/.github/workflows/integration-test-web.yml b/.github/workflows/integration-test-web.yml index 325b4f7f..b11a8719 100644 --- a/.github/workflows/integration-test-web.yml +++ b/.github/workflows/integration-test-web.yml @@ -14,10 +14,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index b19ac582..9b81e958 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -29,10 +29,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true @@ -60,10 +63,13 @@ jobs: steps: - uses: actions/checkout@v5 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c79aad96..52a32eb7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,10 +18,13 @@ jobs: with: fetch-depth: 0 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c67c953c..3d4f46e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,10 +23,13 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Read Flutter version + id: flutter_version + run: echo "version=$(cat .flutter-version)" >> "$GITHUB_OUTPUT" + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - channel: stable - flutter-version-file: .flutter-version + flutter-version: ${{ steps.flutter_version.outputs.version }} cache: true pub-cache: true diff --git a/.vscode/settings.json b/.vscode/settings.json index 3b830c8a..f41194f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -95,6 +95,5 @@ "videoref" ], "java.configuration.updateBuildConfiguration": "interactive", - "dart.mcpServer": true, - "dart.flutterSdkPath": ".fvm/versions/3.41.9" + "dart.mcpServer": true } diff --git a/CLAUDE.md b/CLAUDE.md index abebffbd..357eb206 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,7 +37,7 @@ Key scripts: - `bin/install` — bootstrap everything: `pub get` in both packages, `pod update && pod install` for the example, build helper scripts, build web JS, copy JS into example. Run after a fresh clone or when dependencies change. - `bin/format` — check Dart formatting across all three packages (platform interface, plugin, example). Fails if any file needs reformatting. - `bin/analyze` — run `dart analyze --fatal-infos --fatal-warnings` across all three packages. -- `bin/typecheck` — type-check the web TypeScript (sources + Jest tests) via `tsc --noEmit` against `web/_scripts/tsconfig.json`. Run after editing any TS in `flutter_readium/web/`. Exits non-zero on a type error. +- `bin/typecheck` — type-check the web TypeScript (sources + Jest tests) via `tsc --noEmit` against `web/src/tsconfig.json`. Run after editing any TS in `flutter_readium/web/`. Exits non-zero on a type error. - `bin/build_js` — build the web bundle (currently `build_dev`; production build is commented out). - `bin/update_web_example` — `build_js` + copy the bundle into `flutter_readium/example/web/`. Run after editing TS in `flutter_readium/web/`. - `bin/update_readium_voice_data` — refresh `flutter_readium/assets/voice_data/voices.json` from the upstream `readium/speech` repo (requires `jq`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0b63d60d..42d8847e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,7 +96,7 @@ The same suite runs in CI on every push/PR via [.github/workflows/integration-te ## Building the web bundle -After editing TypeScript files in `flutter_readium/web/_scripts/` or `flutter_readium/assets/_helper_scripts/src/`: +After editing TypeScript files in `flutter_readium/web/src/` or `flutter_readium/assets/_helper_scripts/src/`: ```bash bin/update_web_example # build + copy into example/web/ diff --git a/bin/format b/bin/format index 983aedef..af92fef9 100755 --- a/bin/format +++ b/bin/format @@ -2,11 +2,19 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh" # Format all Dart code across all packages in the repo. +# pub get must run first so the formatter can resolve analysis_options.yaml +# (which includes flutter_lints/flutter.yaml for the page_width: 120 setting). +# Without it, the formatter falls back to 80-char page width and produces +# different output than CI (which always runs pub get before dart format). + echo "Formatting flutter_readium_platform_interface..." +flutter pub get --directory "$REPO_ROOT/flutter_readium_platform_interface" > /dev/null dart format --set-exit-if-changed "$REPO_ROOT/flutter_readium_platform_interface" echo "Formatting flutter_readium..." +flutter pub get --directory "$REPO_ROOT/flutter_readium" > /dev/null dart format --set-exit-if-changed "$REPO_ROOT/flutter_readium" echo "Formatting example app..." +flutter pub get --directory "$REPO_ROOT/flutter_readium/example" > /dev/null dart format --set-exit-if-changed "$REPO_ROOT/flutter_readium/example" diff --git a/bin/install b/bin/install index 1b027fc6..e523d87a 100755 --- a/bin/install +++ b/bin/install @@ -7,8 +7,8 @@ if [ "$(uname)" = "Darwin" ]; then ( cd "$REPO_ROOT/flutter_readium/example/ios" && pod update && pod install --repo-update ) fi -# Make sure web dependencies are installed -cd "$REPO_ROOT/flutter_readium/web/_scripts" && npm install --ignore-scripts +# Make sure web dependencies are installed (package.json lives at the plugin root) +cd "$REPO_ROOT/flutter_readium" && npm install --ignore-scripts "$REPO_ROOT/flutter_readium/bin/build_helper_scripts.sh" "$REPO_ROOT/bin/build_js" diff --git a/bin/typecheck b/bin/typecheck index 370722c2..2b7af89a 100755 --- a/bin/typecheck +++ b/bin/typecheck @@ -2,8 +2,8 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh" # Type-check the flutter_readium web TypeScript (sources + Jest tests) without -# emitting any output. Uses web/_scripts/tsconfig.test.json so test files are -# included too. Run after editing any TS under flutter_readium/web/_scripts. +# emitting any output. Uses web/src/tsconfig.test.json so test files are +# included too. Run after editing any TS under flutter_readium/web/src. echo "Type-checking flutter_readium web TypeScript" cd "$REPO_ROOT/flutter_readium" diff --git a/docs/architecture.md b/docs/architecture.md index 44ac925a..55c55aa7 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -40,7 +40,7 @@ All models in `flutter_readium_platform_interface` define hand-written `toJson` ## Web implementation -The web plugin is a TypeScript/webpack bundle (`flutter_readium/web/_scripts/`) compiled to `flutter_readium/lib/helpers/readiumReader.js`. It is loaded inside a webview and communicates with Dart via `postMessage` / JS interop. +The web plugin is a TypeScript/webpack bundle (`flutter_readium/web/src/`) compiled to `flutter_readium/lib/helpers/readiumReader.js`. It is loaded inside a webview and communicates with Dart via `postMessage` / JS interop. After any TypeScript change run `bin/update_web_example` to rebuild and deploy to the example app. diff --git a/docs/parity/README.md b/docs/parity/README.md index 07e362ff..05e8431d 100644 --- a/docs/parity/README.md +++ b/docs/parity/README.md @@ -32,9 +32,9 @@ These plans have been implemented on the `feat/web-feature-parity` branch and ar ## Considered and deferred -- **Web TTS audit** — The original audit produced a `web-tts.md` plan claiming web TTS was entirely unimplemented. That premise is incorrect: `WebTTSEngine` lives at [flutter_readium/web/_scripts/TTS/ttsNavigator.ts](../../flutter_readium/web/_scripts/TTS/ttsNavigator.ts) and the full `ttsEnable` / `play` / `pause` / `stop` / `next` / `previous` / voice-selection surface is wired through `ReadiumReader.ts`. A genuine TTS parity audit (word-level highlighting, decoration sync, missing-voice fallback) is still worthwhile but needs a fresh investigation against the current code. +- **Web TTS audit** — The original audit produced a `web-tts.md` plan claiming web TTS was entirely unimplemented. That premise is incorrect: `WebTTSEngine` lives at [flutter_readium/web/src/TTS/ttsNavigator.ts](../../flutter_readium/web/src/TTS/ttsNavigator.ts) and the full `ttsEnable` / `play` / `pause` / `stop` / `next` / `previous` / voice-selection surface is wired through `ReadiumReader.ts`. A genuine TTS parity audit (word-level highlighting, decoration sync, missing-voice fallback) is still worthwhile but needs a fresh investigation against the current code. -- **Media overlay on web audit** — Same staleness: the original `media-overlay-missing-on-web.md` plan was written against an outdated snapshot. Media Overlay (`application/vnd.readium.narration+json`) and Guided Navigation (`application/guided-navigation+json`) both play through `audioEnable` on web today via [Audio/mediaOverlayNavigator.ts](../../flutter_readium/web/_scripts/Audio/mediaOverlayNavigator.ts) and [Audio/guidedNavigation.ts](../../flutter_readium/web/_scripts/Audio/guidedNavigation.ts). Any follow-up parity work in this area should start from a fresh audit. +- **Media overlay on web audit** — Same staleness: the original `media-overlay-missing-on-web.md` plan was written against an outdated snapshot. Media Overlay (`application/vnd.readium.narration+json`) and Guided Navigation (`application/guided-navigation+json`) both play through `audioEnable` on web today via [Audio/mediaOverlayNavigator.ts](../../flutter_readium/web/src/Audio/mediaOverlayNavigator.ts) and [Audio/guidedNavigation.ts](../../flutter_readium/web/src/Audio/guidedNavigation.ts). Any follow-up parity work in this area should start from a fresh audit. - **Positions list API** — Both upstream toolkits compute a `positionsByReadingOrder` list internally but do not expose it as a public API on their navigators. The Dart `PositionsList` model exists, but surfacing it would require either polling the publication-level service or adding a dedicated method-channel call. Consumer demand is low compared to the maintenance cost; deferred. diff --git a/docs/parity/web-comic-support-plan.md b/docs/parity/web-comic-support-plan.md index 6248b56b..12d71569 100644 --- a/docs/parity/web-comic-support-plan.md +++ b/docs/parity/web-comic-support-plan.md @@ -87,10 +87,10 @@ In `ReadiumReader._syncVisualToMediaOverlayLocator`: - Add a `## Unreleased` `fix(web):` entry to `CHANGELOG.md`. ## Key files -- `flutter_readium/web/_scripts/Epub/epubNavigator.ts` — inject helper in `frameLoaded`. -- `flutter_readium/web/_scripts/helpers.ts` — `injectComicBookHelper` util. -- `flutter_readium/web/_scripts/ReadiumReader.ts` — comic special-case + duration plumbing. -- `flutter_readium/web/_scripts/Audio/mediaOverlayNavigator.ts` — pass cue duration to callback (if needed). +- `flutter_readium/web/src/Epub/epubNavigator.ts` — inject helper in `frameLoaded`. +- `flutter_readium/web/src/helpers.ts` — `injectComicBookHelper` util. +- `flutter_readium/web/src/ReadiumReader.ts` — comic special-case + duration plumbing. +- `flutter_readium/web/src/Audio/mediaOverlayNavigator.ts` — pass cue duration to callback (if needed). - `CHANGELOG.md`. ## Decision (confirmed) diff --git a/docs/parity/web-decorations.md b/docs/parity/web-decorations.md index 1fe43d81..2a3c6b3e 100644 --- a/docs/parity/web-decorations.md +++ b/docs/parity/web-decorations.md @@ -10,7 +10,7 @@ `applyDecorations` is the primary way consumers persist user highlights and annotations across a session. On iOS and Android, calling `applyDecorations(id, decorations)` renders coloured highlight / underline overlays on the text and fires `onDecorationInteraction` when the user taps one. On Web, the method is a no-op — decorations are silently dropped. A consumer writing a cross-platform app cannot restore saved highlights on the web reader without this, which is a user-visible regression whenever the web target is used. -The ts-toolkit EpubNavigator internally uses a `decorate` message via its frame-comms protocol (visible in `flutter_readium/web/_scripts/helpers.ts` at `highlightSelection()`) — so the underlying machinery exists in the npm package; it just isn't wired to the Dart `applyDecorations` call. +The ts-toolkit EpubNavigator internally uses a `decorate` message via its frame-comms protocol (visible in `flutter_readium/web/src/helpers.ts` at `highlightSelection()`) — so the underlying machinery exists in the npm package; it just isn't wired to the Dart `applyDecorations` call. ## Current state @@ -21,7 +21,7 @@ The ts-toolkit EpubNavigator internally uses a `decorate` message via its frame- ## Proposed approach -1. **JS side** (`flutter_readium/web/_scripts/ReadiumReader.ts`): Add a public `applyDecorations(groupId: string, decorationsJson: string): void` method that deserialises the array and calls the navigator's frame-comms `decorate` message (following the pattern already used in `helpers.ts`'s `highlightSelection()`). Add a matching method to the `ReadiumReader` JS interop extension type in `js_publication_channel.dart`. +1. **JS side** (`flutter_readium/web/src/ReadiumReader.ts`): Add a public `applyDecorations(groupId: string, decorationsJson: string): void` method that deserialises the array and calls the navigator's frame-comms `decorate` message (following the pattern already used in `helpers.ts`'s `highlightSelection()`). Add a matching method to the `ReadiumReader` JS interop extension type in `js_publication_channel.dart`. 2. **Decoration interactions**: Wire the navigator's `decorationActivated` (or equivalent listener) to call back into Dart via `onDecorationInteractionCallback`. The `onDecorationInteractionCallback` setter and `onDecorationInteractionHandler` are already plumbed in `readium_webview.dart`. 3. **Dart web plugin** (`flutter_readium_web.dart`): Replace the no-op with a real call to the new `JsPublicationChannel.applyDecorations(id, encodedList)`. 4. **Widget** (`reader_widget_web.dart`): Replace the no-op similarly. diff --git a/docs/web-ts-refactor-plan.md b/docs/web-ts-refactor-plan.md new file mode 100644 index 00000000..aed26d92 --- /dev/null +++ b/docs/web-ts-refactor-plan.md @@ -0,0 +1,170 @@ +# Web Platform (TypeScript) Structural Refactor + +## Context + +The web implementation lives in `flutter_readium/flutter_readium/web/_scripts/` and is built by webpack into `lib/helpers/readiumReader.js`. Today it centers on **`ReadiumReader.ts` — a 991-line god class** (`_ReadiumReader`, exported to `globalThis.ReadiumReader`) with ~30 public methods that mix publication lifecycle, visual navigation, EPUB preferences, decorations, audio playback, TTS, and media-overlay sync, and which holds *all* state. Navigators are created by free `initialize*()` functions returning bare upstream `@readium/navigator` objects, and `helpers.ts` (502 lines) is a grab-bag of manifest fetching, color conversion, decoration frame-comms, and iframe injection. Naming is inconsistent (`webPubPrefences.ts` typo; `Epub` vs `EPUB`). + +By contrast the **native iOS/Android sides** use clean OO abstractions: a `ReadiumReaderView` protocol (visual nav), a `FlutterTimebasedNavigator` protocol with TTS/Audio/MediaOverlay strategy implementations, `Flutter*`-prefixed wrapper classes (prefix dodges upstream-Readium name collisions), dedicated `model/`/`preferences/`/`events/` dirs, and factory dispatch on publication type. + +**Goal:** restructure the web TS to mirror the native architecture — better directory organization, consistent naming, and OO classes/interfaces — so the three platforms read alike and the web layer is maintainable. This is a structural refactor: logic moves largely verbatim; deep per-class cleanup is a later pass. + +**Decisions (confirmed with user):** +- Source dir: rename **`web/_scripts/` → `web/src/`** (conventional name; also disambiguates from the separate `assets/_helper_scripts/` webview-helper bundle). +- Wrapper class naming: **`Flutter*` prefix** (mirrors native; renames `WebTTSEngine` → `FlutterTTSNavigator`). +- Scope: **full restructure** — including collapsing `_ReadiumReader` into a thin facade. +- Delivery: **single PR, composed of small atomic commits** (one per migration step below), build + tests green at each commit. + +**Hard invariant:** the Dart↔JS contract must not change. The `globalThis.ReadiumReader` method names/signatures (`openPublication`, `goTo`, `setEPUBPreferences`, `ttsEnable`, …) and the `window.*` callback names/JSON shapes (`updateTextLocator`, `updateReaderStatus`, `updateTimebasedPlayerState`, `onTextSelectedCallback`, `onErrorCallback`) stay byte-identical. No changes to Dart `js_interop` (`lib/src/js_publication_channel.dart`) are required. + +## Target directory tree (`web/src/`) + +``` +index.ts # NEW webpack entry: import style.css, build facade, assign globalThis.ReadiumReader, install bridge +ReadiumReader.ts # SHRUNKEN facade/dispatcher (~150-200 lines) +style.css # unchanged + +bridge/ + ReadiumBridge.ts # ONLY code allowed to touch window.* emit callbacks + window.d.ts # was flutter.d.ts + +publication/ + PublicationManager.ts # publication lifecycle + static _publications cache + fetchManifest glue + +navigators/ + VisualNavigator.ts # INTERFACE (mirrors ReadiumReaderView) + TimebasedNavigator.ts # INTERFACE (mirrors FlutterTimebasedNavigator) + locatorEnrich.ts # shared enrichWithTotalProgression/tocHref/flattenToc (EPUB+WebPub both use) + FlutterEpubNavigator.ts # was Epub/epubNavigator.ts (free fn -> class impl VisualNavigator) + FlutterWebPubNavigator.ts # was WebPub/webpubNavigator.ts + FlutterAudioNavigator.ts # was Audio/audioNavigator.ts (impl TimebasedNavigator) + FlutterTTSNavigator.ts # was TTS/ttsNavigator.ts (WebTTSEngine renamed, impl TimebasedNavigator) + FlutterMediaOverlayNavigator.ts # was Audio/mediaOverlayNavigator.ts (owns sync + comic cue logic) + +mediaoverlay/ + syncNarration.ts # was Audio/syncNarration.ts + guidedNavigation.ts # was Audio/guidedNavigation.ts + +decorations/ + DecorationController.ts # applyDecorations/setDecorationStyle/_subgroupFor + style/group state (from god class) + decorationOverrides.ts # from helpers.ts: sendDecorate, navIframeWindows, registerPendingDecorationGroup, + # injectDecorationOverrides, UNDERLINE_GROUP_SUFFIX, highlightSelection + +preferences/ + FlutterEpubPreferences.ts # was Epub/epubPreferences.ts (+ convertVerticalScroll/textAlignFromJson/normalizeTypes) + FlutterWebPubPreferences.ts # was WebPub/webPubPrefences.ts <- TYPO FIXED + FlutterAudioPreferences.ts # NEW: extracted setAudioPreferences mapping (from god class) + preferencesFromString (from audioNav) + FlutterTTSPreferences.ts # was TTS/ttsPreferences.ts + +model/ + ReadiumReaderStatus.ts # was enums.ts (room for typed ReadiumTimebasedState later) + +utils/ + ReadiumPluginLogger.ts # was logger.ts + ReadiumExtensions.ts # was extensions/ReadiumPublication.ts + helpers' mediaTypes + findLinkByHref + colors.ts # was helpers' dartColorToCss + manifest.ts # was helpers' fetchManifest + iframeInjection.ts # was helpers' injectFlutterReadiumHelperScripts + asset cache + Peripherals.ts # was peripherals.ts + +__tests__/ # import paths updated to final locations (re-export shims bridge the transition) +``` + +`helpers.ts` is fully dissolved across the above. + +## Interfaces to introduce + +**`VisualNavigator`** (mirrors iOS `ReadiumReaderView`) — implemented by `FlutterEpubNavigator`, `FlutterWebPubNavigator`: +- `underlying` (escape hatch for decoration frame-comms), `currentLocator`, `positions` (EPUB has them; WebPub `[]`) +- `goRight/goLeft/goForward/goBackward`, `goToLink(link, animated)`, `goToLocator(locator, animated)`, `goToProgression(p)`, `destroy()` +- The `initialize*AndPeripherals` free functions become static `create(...)` factories returning the wrapper (the `setNav`/`setPositions` callbacks disappear). + +**`TimebasedNavigator`** (mirrors iOS `FlutterTimebasedNavigator`) — implemented by `FlutterTTSNavigator`, `FlutterAudioNavigator`, `FlutterMediaOverlayNavigator` (strategy pattern): +- `play(locator?)`, `pause()`, `resume()`, `stop()`, `next()`, `previous()`, `seekBy(s)`, `goToProgression(p)`, `goToLocator(locator)`, `destroy()` +- Collapses the facade's repeated `if (this._ttsEngine) … else if (this._audioNav) …` branching into "dispatch to the single active `timebasedNav`." + +## Facade shape after collapse + +``` +class _ReadiumReader { + private bridge: ReadiumBridge; + private pubManager: PublicationManager; + private visualNav?: VisualNavigator; + private timebasedNav?: TimebasedNavigator; // TTS | Audio | MediaOverlay (the active one) + private decorations: DecorationController; +} +``` +Public method names/signatures unchanged. Method → new home (representative; full map in commits): +- `getPublication` → `pubManager`; `openPublication`/`closePublication` → facade orchestrates collaborators +- `goRight/Left/Forward/Backward`, `goToProgression(visual)` → `visualNav` +- `goTo` → facade keeps the route decision (TTS vs MediaOverlay vs audiobook vs visual), delegates each branch; text↔audio mapping moves into `FlutterMediaOverlayNavigator.goToLocator` +- `applyDecorations/setDecorationStyle/_subgroupFor` → `DecorationController` +- `play/pause/resume/stop/next/previous/seekBy`, `audioEnable`, `ttsEnable`, `ttsSetVoice/ttsSetPreferences` → `timebasedNav` +- `setAudioPreferences`/`setEPUBPreferences` → `preferences/*` modules applied to the relevant nav +- `_syncVisualToMediaOverlayLocator`/`_callGotoComicFrame` + `_isComicBook`/`_lastMediaOverlayLocatorKey` → `FlutterMediaOverlayNavigator` +- `disableSynchronization` stays facade-side (cross-cutting plugin state, passed at enable-time) + +## Bridge (centralized `window.*`) + +`bridge/ReadiumBridge.ts` is the only module touching `window.*`. Typed methods wrap each callback with **identical names/JSON shapes**: `emitReaderStatus`, `emitTextLocator` (uses `JSON.stringify(locator.serialize())` per project convention), `emitTimebasedState`, `emitTextSelected`, `emitError`. Navigators receive the bridge (or the specific emit callbacks) by injection rather than reaching `window` directly. The 200ms EPUB text-locator debounce is preserved (stays in `FlutterEpubNavigator` calling `bridge.emitTextLocator`). + +## Migration ordering (each = one atomic commit; build + jest + tsc green at every step) + +Principle: **move/rename first behind re-export shims, refactor internals last.** + +**Phase 0 — rename source dir (`git mv`, no code change)** +0. `git mv web/_scripts web/src`. Update path references: `flutter_readium/package.json` (4 script paths: `build_dev`, `build`, `typecheck`, `test`), `web/src/webpack.config.js` (entry comment — output is `__dirname`-relative so unchanged), `.vscode/{launch,settings,tasks}.json`, `.github/instructions/typescript.instructions.md`, `CLAUDE.md`, `CONTRIBUTING.md`, `docs/architecture.md`, `docs/parity/*`, and the `bin/typecheck` comment. `bin/` scripts invoke `npm run`, so no functional change there. Verify with `bin/typecheck` + `npx jest` + `bin/build_js` (bundle still emits to `lib/helpers/readiumReader.js`). All subsequent steps operate under `web/src/`. + +**Phase A — non-behavioral moves** +1. Create `utils/`, `model/`; move logger→`ReadiumPluginLogger.ts`, peripherals→`Peripherals.ts`, `extensions/ReadiumPublication.ts`→`ReadiumExtensions.ts`, enums→`model/ReadiumReaderStatus.ts`. Re-export shims at old paths. +2. Split `helpers.ts` → `decorations/decorationOverrides.ts`, `utils/colors.ts`, `utils/manifest.ts`, `utils/iframeInjection.ts`, fold `mediaTypes`/`findLinkByHref` into `ReadiumExtensions.ts`. Keep `helpers.ts` as a re-export barrel. +3. Fix typo/casing: preferences files → `preferences/FlutterEpubPreferences.ts`, `FlutterWebPubPreferences.ts`, `FlutterTTSPreferences.ts`. Shims at old paths. + +**Phase B — navigators to classes (verbatim logic)** +4. `FlutterEpubNavigator` + shared `navigators/locatorEnrich.ts` (move `enrichWithTotalProgression`). Old free fn becomes thin wrapper. +5. `FlutterWebPubNavigator` (imports enrich from shared module — removes the cross-`Epub` import). +6. `FlutterAudioNavigator` (preserve `export const __testing__`; re-export for tests). +7. `FlutterTTSNavigator` (rename `WebTTSEngine`). +8. `FlutterMediaOverlayNavigator` (preserve `__testing__`; move comic + cue-sync logic in from god class). + +**Phase C — extract facade collaborators** +9. `bridge/ReadiumBridge.ts` + `window.d.ts`; route all `window.*` through it. +10. `publication/PublicationManager.ts`. +11. `decorations/DecorationController.ts`. +12. `preferences/FlutterAudioPreferences.ts`. + +**Phase D — collapse + re-point entry** +13. Rewrite `_ReadiumReader` as the thin dispatcher delegating to collaborators + active navigators. Diff its public-method list against the original to confirm the contract is intact. +14. Add `index.ts` entry; update `webpack.config.js` `entry: ReadiumReader.ts → index.ts`. Output path `../../lib/helpers/readiumReader.js` unchanged. +15. Delete all re-export shims; update remaining `__tests__` imports to final paths; remove `helpers.ts` barrel. + +**Imports/paths that must be touched (only these):** dir-rename path references in step 0 (package.json, .vscode, docs, instructions); `__tests__/*.test.ts` import paths (deferred via shims until each phase; preserve `__testing__` and named exports `enrichWithTotalProgression`/`dartColorToCss`); `webpack.config.js` entry (step 14). **Dart `js_interop`: no changes.** + +## Critical files (paths shown post-rename, i.e. under `web/src/`) + +- `web/src/ReadiumReader.ts` — the god class to dissolve +- `web/src/helpers.ts` — the grab-bag to split +- `web/src/Audio/{audioNavigator,mediaOverlayNavigator,syncNarration,guidedNavigation}.ts` +- `web/src/{Epub,WebPub,TTS}/*` — navigators + preferences to reclass/rename +- `web/src/webpack.config.js` — entry path (step 14 only) +- `web/src/__tests__/*.test.ts` — import-path updates +- `flutter_readium/package.json`, `.vscode/*` — dir-rename path references (step 0) + +## Verification (per commit + final) + +Run from repo root unless noted: +- `bin/typecheck` — `tsc --noEmit` over web TS (run after any TS edit). +- **Unit tests (Jest):** `npm test` — the **7** existing suites (`audioNavigator`, `epubNavigator`, `guidedNavigation`, `mediaOverlayNavigator`, `syncNarration`, `closePublication`, `helpers`) must stay green at **every** commit. As files move, update each test's import paths (e.g. `helpers.test.ts` imports `dartColorToCss` from `../helpers`; `closePublication.test.ts` and the navigator tests import the modules/`__testing__` exports directly). Re-export shims keep them green until their owning step; final step re-points them to canonical paths. **Do not weaken or skip a test to make it pass** — a failing unit test signals a real regression. +- **Integration tests (Dart):** `example/integration_test/` (`plugin_integration_test.dart` with `test_fixtures_web.dart`) exercise the web platform end-to-end and are the strongest contract-regression gate. Because the Dart↔JS contract is preserved, **these must pass with their source unchanged** — if a fixture or assertion needs editing to pass, treat it as evidence the contract drifted and fix the TS, not the test. Run them on the web target (`flutter test integration_test` / driver) after the facade collapse (step 13) and again at the end (step 15). +- `bin/build_js` then `bin/update_web_example` — confirm `lib/helpers/readiumReader.js` regenerates and is copied into `example/web/`. +- `bin/format` && `bin/analyze` — Dart side unchanged but required pre-PR (checks all packages). +- **End-to-end smoke (final, mandatory for this behavioral refactor):** run the example app on web/Chrome, then exercise each affected path — open an EPUB (paginated + scroll), navigate (arrows/goTo/progression), apply a highlight/underline decoration, enable TTS and play/pause/next, play a media-overlay/sync-narration title and confirm visual sync + comic-frame handling, open a plain audiobook and seek. Confirm via the reader UI and logs that `updateTextLocator`/`updateTimebasedPlayerState`/`updateReaderStatus` still fire with unchanged shapes. (Per project memory: do not delegate Flutter-web in-browser verification to a sub-agent — verify manually.) +- **Contract check:** diff the final facade's public method names against the original `_ReadiumReader` and the `window.*` callback names to prove the Dart↔JS contract is byte-identical. + +## Execution + +- **Plan persisted in repo** at `docs/web-ts-refactor-plan.md` (committed as the first commit on the feature branch) so it travels with the PR and reviewers can follow the step map. +- Implementation proceeds **sequentially**, one atomic commit per numbered step (0 → 15); each step runs only after the previous step's verification gate passes. Steps are dependent — re-export shims/barrels are removed only in step 15, so steps must not be reordered or parallelized. + +## CHANGELOG + +This is an internal restructure with no consumer-visible behavior change, so no CHANGELOG entry is warranted (Keep-a-Changelog test fails). Note the rationale in the PR description instead. diff --git a/flutter_readium/bin/copy_js_file.dart b/flutter_readium/bin/copy_js_file.dart index 0061093e..6d76902b 100644 --- a/flutter_readium/bin/copy_js_file.dart +++ b/flutter_readium/bin/copy_js_file.dart @@ -5,12 +5,16 @@ import 'dart:isolate'; void main(List args) async { if (args.isEmpty) { - print('Usage: dart run flutter_readium:copy_js_file [dev|prod]'); + print( + 'Usage: dart run flutter_readium:copy_js_file [dev|prod]', + ); return; } final destinationDir = args[0]; - final packageUri = Uri.parse('package:flutter_readium/helpers/readiumReader.js'); + final packageUri = Uri.parse( + 'package:flutter_readium/helpers/readiumReader.js', + ); final resolvedUri = await Isolate.resolvePackageUri(packageUri); if (resolvedUri == null) { diff --git a/flutter_readium/example/integration_test/test_fixtures.dart b/flutter_readium/example/integration_test/test_fixtures.dart index 48bccea5..d5554c9c 100644 --- a/flutter_readium/example/integration_test/test_fixtures.dart +++ b/flutter_readium/example/integration_test/test_fixtures.dart @@ -30,7 +30,14 @@ abstract final class FixtureKeys { static const comic = 'comic.webpub'; /// All fixture keys that should be available on web. - static const web = {mobyDickEpub, overlayWebpub, audiobook, fixedLayout, guidedNav, comic}; + static const web = { + mobyDickEpub, + overlayWebpub, + audiobook, + fixedLayout, + guidedNav, + comic, + }; /// True when [key] is not expected to be available on web. static bool isUnavailableOnWeb(String key) => kIsWeb && !web.contains(key); diff --git a/flutter_readium/example/lib/extensions/text_settings_theme.dart b/flutter_readium/example/lib/extensions/text_settings_theme.dart index d117ebef..7dcf8127 100644 --- a/flutter_readium/example/lib/extensions/text_settings_theme.dart +++ b/flutter_readium/example/lib/extensions/text_settings_theme.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; @immutable class TextSettingsTheme { - const TextSettingsTheme({required this.textColor, required this.backgroundColor}); + const TextSettingsTheme({ + required this.textColor, + required this.backgroundColor, + }); final Color textColor; final Color backgroundColor; @@ -11,21 +14,63 @@ class TextSettingsTheme { } const List themes = [ - TextSettingsTheme(textColor: Color(0xffeeeeee), backgroundColor: Color(0xff000000)), - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xffffffff)), - TextSettingsTheme(textColor: Color(0xffffbb00), backgroundColor: Color(0xff000000)), - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xffffbb00)), - TextSettingsTheme(textColor: Color(0xff116666), backgroundColor: Color(0xffffeeee)), - TextSettingsTheme(textColor: Color(0xffffeeee), backgroundColor: Color(0xff116666)), - TextSettingsTheme(textColor: Color(0XFF015298), backgroundColor: Color(0xffffffff)), - TextSettingsTheme(textColor: Color(0xffffffff), backgroundColor: Color(0XFF015298)), - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xff88bbbb)), - TextSettingsTheme(textColor: Color(0xff88bbbb), backgroundColor: Color(0xff000000)), + TextSettingsTheme( + textColor: Color(0xffeeeeee), + backgroundColor: Color(0xff000000), + ), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xffffffff), + ), + TextSettingsTheme( + textColor: Color(0xffffbb00), + backgroundColor: Color(0xff000000), + ), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xffffbb00), + ), + TextSettingsTheme( + textColor: Color(0xff116666), + backgroundColor: Color(0xffffeeee), + ), + TextSettingsTheme( + textColor: Color(0xffffeeee), + backgroundColor: Color(0xff116666), + ), + TextSettingsTheme( + textColor: Color(0XFF015298), + backgroundColor: Color(0xffffffff), + ), + TextSettingsTheme( + textColor: Color(0xffffffff), + backgroundColor: Color(0XFF015298), + ), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xff88bbbb), + ), + TextSettingsTheme( + textColor: Color(0xff88bbbb), + backgroundColor: Color(0xff000000), + ), ]; const List highlights = [ - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xccfdff00)), - TextSettingsTheme(textColor: Color(0xffffffff), backgroundColor: Color(0xccff00a7)), - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xcc00c5ff)), - TextSettingsTheme(textColor: Color(0xff000000), backgroundColor: Color(0xcc00ff04)), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xccfdff00), + ), + TextSettingsTheme( + textColor: Color(0xffffffff), + backgroundColor: Color(0xccff00a7), + ), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xcc00c5ff), + ), + TextSettingsTheme( + textColor: Color(0xff000000), + backgroundColor: Color(0xcc00ff04), + ), ]; diff --git a/flutter_readium/example/lib/main.dart b/flutter_readium/example/lib/main.dart index 7d32df38..cc5ed6ed 100644 --- a/flutter_readium/example/lib/main.dart +++ b/flutter_readium/example/lib/main.dart @@ -14,7 +14,9 @@ import 'state/index.dart'; Future main() async { // Initialize Marionette only in debug mode if (kDebugMode) { - MarionetteBinding.ensureInitialized(MarionetteConfiguration(logCollector: LoggingLogCollector())); + MarionetteBinding.ensureInitialized( + MarionetteConfiguration(logCollector: LoggingLogCollector()), + ); } else { WidgetsFlutterBinding.ensureInitialized(); } diff --git a/flutter_readium/example/lib/pages/bookshelf.page.dart b/flutter_readium/example/lib/pages/bookshelf.page.dart index ee8edbb1..e2068f00 100644 --- a/flutter_readium/example/lib/pages/bookshelf.page.dart +++ b/flutter_readium/example/lib/pages/bookshelf.page.dart @@ -42,7 +42,9 @@ class BookshelfPageState extends State { if (kIsWeb) { // Web: Load publications from JSON asset - final String response = await rootBundle.loadString('assets/webManifestList.json'); + final String response = await rootBundle.loadString( + 'assets/webManifestList.json', + ); final List manifestHrefs = json.decode(response); for (final href in manifestHrefs) { try { @@ -135,7 +137,11 @@ class BookshelfPageState extends State { itemBuilder: (final context, final index) { final publication = _testPublications[index]; final publicationUrl = _testPublicationURLs[index]; - return _buildPubCard(publication, publicationUrl, context); + return _buildPubCard( + publication, + publicationUrl, + context, + ); }, ), ), @@ -148,8 +154,13 @@ class BookshelfPageState extends State { ); // ignore: unused_element - void _toast(final String text, {final Duration duration = const Duration(milliseconds: 4000)}) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text), duration: duration)); + void _toast( + final String text, { + final Duration duration = const Duration(milliseconds: 4000), + }) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(text), duration: duration)); } String _listAuthors(final Publication pub) { @@ -193,7 +204,11 @@ class BookshelfPageState extends State { } } - Widget _buildPubCard(final Publication publication, String publicationUrl, final BuildContext context) => Container( + Widget _buildPubCard( + final Publication publication, + String publicationUrl, + final BuildContext context, + ) => Container( width: double.infinity, padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0), child: InkWell( @@ -207,7 +222,10 @@ class BookshelfPageState extends State { try { context.read().add( - OpenPublication(publicationUrl: publicationUrl, initialLocator: savedInitialLocator), + OpenPublication( + publicationUrl: publicationUrl, + initialLocator: savedInitialLocator, + ), ); Navigator.restorablePushNamed(context, '/player'); @@ -225,7 +243,10 @@ class BookshelfPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(publication.metadata.title, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), + Text( + publication.metadata.title, + style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + ), Text(_listAuthors(publication)), Text(_bookFormatFromConformsTo(publication)), Text(publicationUrl.split('/').last), @@ -237,7 +258,9 @@ class BookshelfPageState extends State { icon: Icon(Icons.delete, color: Colors.red), onPressed: () async { try { - PublicationUtils.removePublicationFromReadiumStorage(publication.identifier); + PublicationUtils.removePublicationFromReadiumStorage( + publication.identifier, + ); setState(() { _testPublications.remove(publication); }); diff --git a/flutter_readium/example/lib/pages/pageList.page.dart b/flutter_readium/example/lib/pages/pageList.page.dart index 4d3f8b6a..609decc1 100644 --- a/flutter_readium/example/lib/pages/pageList.page.dart +++ b/flutter_readium/example/lib/pages/pageList.page.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_readium/flutter_readium.dart' show Link, PublicationLists; diff --git a/flutter_readium/example/lib/pages/player.page.dart b/flutter_readium/example/lib/pages/player.page.dart index 1a979a59..a920992f 100644 --- a/flutter_readium/example/lib/pages/player.page.dart +++ b/flutter_readium/example/lib/pages/player.page.dart @@ -34,7 +34,9 @@ class _PlayerPageState extends State with RestorationMixin { } @override - Widget build(final BuildContext context) => BlocBuilder( + Widget build( + final BuildContext context, + ) => BlocBuilder( builder: (final context, final pubState) { final isAudioBook = pubState.publication?.conformsToReadiumAudiobook ?? false; @@ -55,7 +57,9 @@ class _PlayerPageState extends State with RestorationMixin { backgroundColor: _appBarColor, title: Semantics( header: true, - child: Text(pubState.error != null ? 'Error' : pubState.publication?.metadata.title ?? 'Unknown'), + child: Text( + pubState.error != null ? 'Error' : pubState.publication?.metadata.title ?? 'Unknown', + ), ), actions: _buildActionButtons(), ), @@ -63,11 +67,19 @@ class _PlayerPageState extends State with RestorationMixin { children: [ Positioned.fill( child: isAudioBook - ? Container(padding: EdgeInsets.all(12.0), child: TimebasedStateWidget()) + ? Container( + padding: EdgeInsets.all(12.0), + child: TimebasedStateWidget(), + ) : ReaderWidget(shouldShowControls: _shouldShowControls), ), if (pubState.publication != null) - Positioned(left: 0, right: 0, bottom: 0, child: _controls(pubState.publication!)), + Positioned( + left: 0, + right: 0, + bottom: 0, + child: _controls(pubState.publication!), + ), ], ), ), @@ -103,8 +115,9 @@ class _PlayerPageState extends State with RestorationMixin { showModalBottomSheet( context: context, isScrollControlled: true, - builder: (final context) => - PointerInterceptor(child: isPDF ? const PDFSettingsWidget() : const TextSettingsWidget()), + builder: (final context) => PointerInterceptor( + child: isPDF ? const PDFSettingsWidget() : const TextSettingsWidget(), + ), ); }, tooltip: 'Open reader settings', @@ -112,12 +125,17 @@ class _PlayerPageState extends State with RestorationMixin { IconButton( icon: const Icon(Icons.search), onPressed: () async { - final tappedSearchResult = await Navigator.pushNamed(context, '/search'); + final tappedSearchResult = await Navigator.pushNamed( + context, + '/search', + ); if (!context.mounted) return; final publication = context.read().state.publication; if (publication != null && tappedSearchResult != null && tappedSearchResult is TextSearchResult) { if (context.mounted) { - context.read().add(GoToLocator(tappedSearchResult.locator)); + context.read().add( + GoToLocator(tappedSearchResult.locator), + ); } } }, @@ -152,7 +170,12 @@ class _PlayerPageState extends State with RestorationMixin { duration: _slideDuration, child: Container( color: _playerControlsColor, - child: SafeArea(top: false, left: false, right: false, child: PlayerControls(publication: publication)), + child: SafeArea( + top: false, + left: false, + right: false, + child: PlayerControls(publication: publication), + ), ), ); } diff --git a/flutter_readium/example/lib/pages/search.page.dart b/flutter_readium/example/lib/pages/search.page.dart index 683e7d10..8424b57d 100644 --- a/flutter_readium/example/lib/pages/search.page.dart +++ b/flutter_readium/example/lib/pages/search.page.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_readium/flutter_readium.dart' show FlutterReadium, TextSearchResult; import 'package:flutter_readium_example/state/index.dart'; @@ -70,7 +70,9 @@ class _SearchPageState extends State { } void doSearchInPublication(final String searchQuery) async { - final searchResults = await FlutterReadium().searchInPublication(searchQuery); + final searchResults = await FlutterReadium().searchInPublication( + searchQuery, + ); setState(() { results.clear(); results.addAll(searchResults); diff --git a/flutter_readium/example/lib/pages/toc.page.dart b/flutter_readium/example/lib/pages/toc.page.dart index e7e36398..9a7e1c8a 100644 --- a/flutter_readium/example/lib/pages/toc.page.dart +++ b/flutter_readium/example/lib/pages/toc.page.dart @@ -1,4 +1,4 @@ -import 'dart:math' show min, max; +import 'dart:math' show min, max; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -28,7 +28,10 @@ class TableOfContentsPage extends StatelessWidget { icon: const Icon(Icons.menu_book), onPressed: () async { // Replace ToC page with Page List page, if page is clicked, pop it back to Player page. - final result = await Navigator.pushNamed(context, '/pagelist'); + final result = await Navigator.pushNamed( + context, + '/pagelist', + ); if (!context.mounted) return; final publication = context.read().state.publication; if (publication != null && result != null && result is Link) { diff --git a/flutter_readium/example/lib/state/player_controls_bloc.dart b/flutter_readium/example/lib/state/player_controls_bloc.dart index 6ade1c86..4562995b 100644 --- a/flutter_readium/example/lib/state/player_controls_bloc.dart +++ b/flutter_readium/example/lib/state/player_controls_bloc.dart @@ -111,26 +111,46 @@ class PlayerControlsState { final bool audioEnabled; final String? currentTocHref; - PlayerControlsState copyWith({bool? playing, bool? ttsEnabled, bool? audioEnabled, String? currentTocHref}) => - PlayerControlsState( - playing: playing ?? this.playing, - ttsEnabled: ttsEnabled ?? this.ttsEnabled, - audioEnabled: audioEnabled ?? this.audioEnabled, - currentTocHref: currentTocHref ?? this.currentTocHref, - ); + PlayerControlsState copyWith({ + bool? playing, + bool? ttsEnabled, + bool? audioEnabled, + String? currentTocHref, + }) => PlayerControlsState( + playing: playing ?? this.playing, + ttsEnabled: ttsEnabled ?? this.ttsEnabled, + audioEnabled: audioEnabled ?? this.audioEnabled, + currentTocHref: currentTocHref ?? this.currentTocHref, + ); PlayerControlsState togglePlay(final bool playing) => copyWith(playing: playing); - PlayerControlsState toggleTTSEnabled(final bool ttsEnabled, final String? tocHref) => - copyWith(playing: ttsEnabled && playing, ttsEnabled: ttsEnabled, currentTocHref: tocHref ?? currentTocHref); - - PlayerControlsState toggleAudioEnabled(final bool audioEnabled, final String? tocHref) => - copyWith(playing: audioEnabled && playing, audioEnabled: audioEnabled, currentTocHref: tocHref ?? currentTocHref); + PlayerControlsState toggleTTSEnabled( + final bool ttsEnabled, + final String? tocHref, + ) => copyWith( + playing: ttsEnabled && playing, + ttsEnabled: ttsEnabled, + currentTocHref: tocHref ?? currentTocHref, + ); + + PlayerControlsState toggleAudioEnabled( + final bool audioEnabled, + final String? tocHref, + ) => copyWith( + playing: audioEnabled && playing, + audioEnabled: audioEnabled, + currentTocHref: tocHref ?? currentTocHref, + ); PlayerControlsState setTocHref(final String tocHref) => copyWith(currentTocHref: tocHref); - PlayerControlsState stop() => - PlayerControlsState(playing: false, ttsEnabled: false, audioEnabled: false, currentTocHref: null); + PlayerControlsState stop() => PlayerControlsState( + playing: false, + ttsEnabled: false, + audioEnabled: false, + currentTocHref: null, + ); } class PlayerControlsBloc extends Bloc { @@ -142,7 +162,14 @@ class PlayerControlsBloc extends Bloc /// `BlocBuilder`) immediately receive the current progression. final BehaviorSubject _currentLocatorSubject = BehaviorSubject(); - PlayerControlsBloc() : super(PlayerControlsState(playing: false, ttsEnabled: false, audioEnabled: false)) { + PlayerControlsBloc() + : super( + PlayerControlsState( + playing: false, + ttsEnabled: false, + audioEnabled: false, + ), + ) { subscriptions.add( Rx.merge([ instance.onTextLocatorChanged, @@ -191,7 +218,9 @@ class PlayerControlsBloc extends Bloc // NOTE: This does not include the tocHref for the initial locator. subscriptions.add( Rx.merge([ - instance.onTimebasedPlayerStateChanged.map((s) => s.currentLocator?.locations?.tocHref), + instance.onTimebasedPlayerStateChanged.map( + (s) => s.currentLocator?.locations?.tocHref, + ), instance.onTextLocatorChanged.map((l) => l.locations?.tocHref), ]).whereNotNull().distinct().debounceTime(const Duration(milliseconds: 50)).listen((tocHref) { if (tocHref != state.currentTocHref) { @@ -215,7 +244,9 @@ class PlayerControlsBloc extends Bloc if (!state.ttsEnabled) { await instance.ttsEnable(TTSPreferences(speed: 1.2)); await instance.play(event.fromLocator); - emit(state.toggleTTSEnabled(true, event.fromLocator?.locations?.tocHref)); + emit( + state.toggleTTSEnabled(true, event.fromLocator?.locations?.tocHref), + ); } else { await instance.resume(); } @@ -224,11 +255,17 @@ class PlayerControlsBloc extends Bloc on((final event, final emit) async { if (!state.audioEnabled) { await instance.audioEnable( - prefs: AudioPreferences(speed: 1.5, seekInterval: 10, continuousSeeking: true), + prefs: AudioPreferences( + speed: 1.5, + seekInterval: 10, + continuousSeeking: true, + ), fromLocator: event.fromLocator, ); await instance.play(event.fromLocator); - emit(state.toggleAudioEnabled(true, event.fromLocator?.locations?.tocHref)); + emit( + state.toggleAudioEnabled(true, event.fromLocator?.locations?.tocHref), + ); } else { await instance.resume(); } @@ -257,27 +294,45 @@ class PlayerControlsBloc extends Bloc on((final event, final emit) { if (state.currentTocHref == null) { - ReadiumLog.e("No currentTocHref in state, cannot skip to next TOC chapter"); + ReadiumLog.e( + "No currentTocHref in state, cannot skip to next TOC chapter", + ); return null; } - return instance.skipToNextTOC(publication: event.publication, currentTocHref: state.currentTocHref!); + return instance.skipToNextTOC( + publication: event.publication, + currentTocHref: state.currentTocHref!, + ); }); on((final event, final emit) { if (state.currentTocHref == null) { - ReadiumLog.e("No currentTocHref in state, cannot skip to previous TOC chapter"); + ReadiumLog.e( + "No currentTocHref in state, cannot skip to previous TOC chapter", + ); return null; } - return instance.skipToPreviousTOC(publication: event.publication, currentTocHref: state.currentTocHref!); + return instance.skipToPreviousTOC( + publication: event.publication, + currentTocHref: state.currentTocHref!, + ); }); - on((final event, final emit) async => await instance.goForward()); + on( + (final event, final emit) async => await instance.goForward(), + ); - on((final event, final emit) async => await instance.goBackward()); + on( + (final event, final emit) async => await instance.goBackward(), + ); - on((event, emit) async => await instance.goToLocator(event.locator)); + on( + (event, emit) async => await instance.goToLocator(event.locator), + ); - on((event, emit) async => await instance.goToProgression(event.progression)); + on( + (event, emit) async => await instance.goToProgression(event.progression), + ); on( (event, emit) async => await instance.audioSeekBy( diff --git a/flutter_readium/example/lib/state/publication_bloc.dart b/flutter_readium/example/lib/state/publication_bloc.dart index 11f73637..47e1e87d 100644 --- a/flutter_readium/example/lib/state/publication_bloc.dart +++ b/flutter_readium/example/lib/state/publication_bloc.dart @@ -24,7 +24,11 @@ class AddHighlight extends PublicationEvent { @immutable class OpenPublication extends PublicationEvent { - OpenPublication({required this.publicationUrl, this.initialLocator, this.autoPlay}); + OpenPublication({ + required this.publicationUrl, + this.initialLocator, + this.autoPlay, + }); final String publicationUrl; final Locator? initialLocator; final bool? autoPlay; @@ -61,8 +65,15 @@ class PublicationState { highlights: highlights ?? this.highlights, ); - PublicationState openPublicationSuccess(final Publication publication, Locator? initialLocator) => - PublicationState(publication: publication, initialLocator: initialLocator, isLoading: false, error: null); + PublicationState openPublicationSuccess( + final Publication publication, + Locator? initialLocator, + ) => PublicationState( + publication: publication, + initialLocator: initialLocator, + isLoading: false, + error: null, + ); PublicationState openPublicationFail(final dynamic error) => copyWith(publication: publication, error: error, isLoading: false); @@ -101,10 +112,18 @@ class PublicationState { final jsonObject = Map.of(json); - final publication = Publication.fromJson(jsonObject.optNullableMap('publication', remove: true)); - final initialLocator = Locator.fromJson(jsonObject.optNullableMap('initialLocator', remove: true)); + final publication = Publication.fromJson( + jsonObject.optNullableMap('publication', remove: true), + ); + final initialLocator = Locator.fromJson( + jsonObject.optNullableMap('initialLocator', remove: true), + ); final error = jsonObject.opt('error', remove: true); - final isLoading = jsonObject.optBoolean('isLoading', fallback: false, remove: true); + final isLoading = jsonObject.optBoolean( + 'isLoading', + fallback: false, + remove: true, + ); return PublicationState( publication: publication, @@ -126,7 +145,9 @@ class PublicationBloc extends HydratedBloc { on((final event, final emit) async { emit(state.loading(event.initialLocator)); try { - final publication = await instance.openPublication(event.publicationUrl); + final publication = await instance.openPublication( + event.publicationUrl, + ); final pubUrlHashCode = event.publicationUrl.hashCode.toString(); bool timebasedLocatorReceived = false; @@ -136,7 +157,11 @@ class PublicationBloc extends HydratedBloc { timebasedStateSub = instance.onTimebasedPlayerStateChanged .map((state) => state.currentLocator) .whereNotNull() - .throttleTime(const Duration(milliseconds: 1000), leading: false, trailing: true) + .throttleTime( + const Duration(milliseconds: 1000), + leading: false, + trailing: true, + ) .listen((locator) { _log.fine('onTimebasedPlayerState.currentLocator: $locator'); savedLocators[pubUrlHashCode] = locator; @@ -156,9 +181,13 @@ class PublicationBloc extends HydratedBloc { }); } on Exception catch (error) { if (error is ReadiumException) { - _log.severe('ReadiumException on opening publication: ${error.type} - ${error.message}'); + _log.severe( + 'ReadiumException on opening publication: ${error.type} - ${error.message}', + ); } else { - _log.severe('Unknown exception on opening publication: ${error.toString()}'); + _log.severe( + 'Unknown exception on opening publication: ${error.toString()}', + ); } emit(state.openPublicationFail(error)); } @@ -177,7 +206,9 @@ class PublicationBloc extends HydratedBloc { textLocatorSub?.cancel(); errorEventSub?.cancel(); } on Exception catch (error) { - _log.warning('Exception while closing publication: ${error.toString()}'); + _log.warning( + 'Exception while closing publication: ${error.toString()}', + ); } emit(PublicationState()); }); diff --git a/flutter_readium/example/lib/state/text_settings_bloc.dart b/flutter_readium/example/lib/state/text_settings_bloc.dart index 0dfe4859..ec9464f4 100644 --- a/flutter_readium/example/lib/state/text_settings_bloc.dart +++ b/flutter_readium/example/lib/state/text_settings_bloc.dart @@ -316,10 +316,16 @@ class TextSettingsBloc extends Bloc { // settings panel. instance.setDecorationStyle( state.utteranceStyle != null - ? ReaderDecorationStyle(style: state.utteranceStyle!, tint: state.highlight.backgroundColor) + ? ReaderDecorationStyle( + style: state.utteranceStyle!, + tint: state.highlight.backgroundColor, + ) : null, state.rangeStyle != null - ? ReaderDecorationStyle(style: state.rangeStyle!, tint: state.highlight.textColor) + ? ReaderDecorationStyle( + style: state.rangeStyle!, + tint: state.highlight.textColor, + ) : null, ); } @@ -350,12 +356,16 @@ class TextSettingsBloc extends Bloc { }); on((final event, final emit) { - emit(state.copyWith(blackAndWhiteComicMode: !state.blackAndWhiteComicMode)); + emit( + state.copyWith(blackAndWhiteComicMode: !state.blackAndWhiteComicMode), + ); submitPreferenceUpdate(); }); on((final event, final emit) { - emit(state.copyWith(disableSynchronization: !state.disableSynchronization)); + emit( + state.copyWith(disableSynchronization: !state.disableSynchronization), + ); submitPreferenceUpdate(); }); @@ -384,10 +394,16 @@ class TextSettingsBloc extends Bloc { await FlutterReadium().setDecorationStyle( state.utteranceStyle != null - ? ReaderDecorationStyle(style: state.utteranceStyle!, tint: event.highlight.backgroundColor) + ? ReaderDecorationStyle( + style: state.utteranceStyle!, + tint: event.highlight.backgroundColor, + ) : null, state.rangeStyle != null - ? ReaderDecorationStyle(style: state.rangeStyle!, tint: event.highlight.textColor) + ? ReaderDecorationStyle( + style: state.rangeStyle!, + tint: event.highlight.textColor, + ) : null, ); }); @@ -395,9 +411,17 @@ class TextSettingsBloc extends Bloc { on((final event, final emit) async { emit(state.copyWith(utteranceStyle: event.value)); await FlutterReadium().setDecorationStyle( - event.value != null ? ReaderDecorationStyle(style: event.value!, tint: state.highlight.backgroundColor) : null, + event.value != null + ? ReaderDecorationStyle( + style: event.value!, + tint: state.highlight.backgroundColor, + ) + : null, state.rangeStyle != null - ? ReaderDecorationStyle(style: state.rangeStyle!, tint: state.highlight.textColor) + ? ReaderDecorationStyle( + style: state.rangeStyle!, + tint: state.highlight.textColor, + ) : null, ); }); @@ -406,9 +430,17 @@ class TextSettingsBloc extends Bloc { emit(state.copyWith(rangeStyle: event.value)); await FlutterReadium().setDecorationStyle( state.utteranceStyle != null - ? ReaderDecorationStyle(style: state.utteranceStyle!, tint: state.highlight.backgroundColor) + ? ReaderDecorationStyle( + style: state.utteranceStyle!, + tint: state.highlight.backgroundColor, + ) + : null, + event.value != null + ? ReaderDecorationStyle( + style: event.value!, + tint: state.highlight.textColor, + ) : null, - event.value != null ? ReaderDecorationStyle(style: event.value!, tint: state.highlight.textColor) : null, ); }); @@ -457,7 +489,9 @@ class TextSettingsBloc extends Bloc { }); on((event, emit) { - emit(state.copyWith(paragraphIndent: event.value, publisherStyles: false)); + emit( + state.copyWith(paragraphIndent: event.value, publisherStyles: false), + ); submitPreferenceUpdate(); }); @@ -467,17 +501,29 @@ class TextSettingsBloc extends Bloc { }); on((event, emit) { - emit(state.copyWith(hyphens: !(state.hyphens ?? false), publisherStyles: false)); + emit( + state.copyWith( + hyphens: !(state.hyphens ?? false), + publisherStyles: false, + ), + ); submitPreferenceUpdate(); }); on((event, emit) { - emit(state.copyWith(ligatures: !(state.ligatures ?? false), publisherStyles: false)); + emit( + state.copyWith( + ligatures: !(state.ligatures ?? false), + publisherStyles: false, + ), + ); submitPreferenceUpdate(); }); on((event, emit) { - emit(state.copyWith(textNormalization: !(state.textNormalization ?? false))); + emit( + state.copyWith(textNormalization: !(state.textNormalization ?? false)), + ); submitPreferenceUpdate(); }); diff --git a/flutter_readium/example/lib/utils/publication_utils.dart b/flutter_readium/example/lib/utils/publication_utils.dart index 15bfe454..9f10cce9 100644 --- a/flutter_readium/example/lib/utils/publication_utils.dart +++ b/flutter_readium/example/lib/utils/publication_utils.dart @@ -11,7 +11,9 @@ final _log = Logger('PublicationUtils'); class PublicationUtils { static Future> getAssetPubFiles() async { final assetManifest = await AssetManifest.loadFromAssetBundle(rootBundle); - final assets = assetManifest.listAssets().where((asset) => asset.startsWith('assets/pubs/')); + final assets = assetManifest.listAssets().where( + (asset) => asset.startsWith('assets/pubs/'), + ); return assets; } @@ -27,7 +29,14 @@ class PublicationUtils { final pubAssets = await getAssetPubFiles(); final pubs = []; - final allowedExts = ['.webpub', '.epub', '.audiobook', '.pdf', '.zip', '.json']; + final allowedExts = [ + '.webpub', + '.epub', + '.audiobook', + '.pdf', + '.zip', + '.json', + ]; // Loop through the filtered assets for (final assetPath in pubAssets) { @@ -44,7 +53,10 @@ class PublicationUtils { if (!exists) { final data = await rootBundle.load(assetPath); - final bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + final bytes = data.buffer.asUint8List( + data.offsetInBytes, + data.lengthInBytes, + ); await file.writeAsBytes(bytes); _log.info('saved ${file.path} size=${await file.length()}'); } else { @@ -64,11 +76,15 @@ class PublicationUtils { final publicationsDirPath = await ReadiumStorage.publicationsDirPath; String newPath = path.join(publicationsDirPath, file.uri.path); await file.copy(newPath); - _log.info('copied file ${file.path} size=${await file.length()} to=$newPath'); + _log.info( + 'copied file ${file.path} size=${await file.length()} to=$newPath', + ); return newPath; } - static Future removePublicationFromReadiumStorage(String pubPath) async { + static Future removePublicationFromReadiumStorage( + String pubPath, + ) async { final publicationsDirPath = await ReadiumStorage.publicationsDirPath; final publicationPath = path.join(publicationsDirPath, pubPath); await File(publicationPath).delete(); diff --git a/flutter_readium/example/lib/widgets/animated_slide_out_widget.dart b/flutter_readium/example/lib/widgets/animated_slide_out_widget.dart index 399e93e1..cc379ea3 100644 --- a/flutter_readium/example/lib/widgets/animated_slide_out_widget.dart +++ b/flutter_readium/example/lib/widgets/animated_slide_out_widget.dart @@ -17,8 +17,13 @@ class AnimatedSlideOutWidget extends AnimatedWidget { ValueListenable get visible => listenable as ValueListenable; @override - Widget build(final BuildContext context) => - _AnimatedSlideOut(visible: visible.value, hiddenOffset: hiddenOffset, duration: duration, key: key, child: child); + Widget build(final BuildContext context) => _AnimatedSlideOut( + visible: visible.value, + hiddenOffset: hiddenOffset, + duration: duration, + key: key, + child: child, + ); } class _AnimatedSlideOut extends StatefulWidget { @@ -40,9 +45,19 @@ class _AnimatedSlideOut extends StatefulWidget { } class _AnimatedSlideOutState extends State<_AnimatedSlideOut> with SingleTickerProviderStateMixin { - late final _controller = AnimationController(value: widget.visible ? 0 : 1, duration: widget.duration, vsync: this); - late final _easeIn = CurvedAnimation(parent: _controller, curve: Curves.easeIn); - late final _offset = Tween(begin: Offset.zero, end: widget.hiddenOffset); + late final _controller = AnimationController( + value: widget.visible ? 0 : 1, + duration: widget.duration, + vsync: this, + ); + late final _easeIn = CurvedAnimation( + parent: _controller, + curve: Curves.easeIn, + ); + late final _offset = Tween( + begin: Offset.zero, + end: widget.hiddenOffset, + ); @override void initState() { @@ -73,5 +88,8 @@ class _AnimatedSlideOutState extends State<_AnimatedSlideOut> with SingleTickerP @override Widget build(final BuildContext context) => _controller.value == 1 ? const SizedBox.shrink() - : FractionalTranslation(translation: _offset.evaluate(_easeIn), child: widget.child); + : FractionalTranslation( + translation: _offset.evaluate(_easeIn), + child: widget.child, + ); } diff --git a/flutter_readium/example/lib/widgets/list_item.widget.dart b/flutter_readium/example/lib/widgets/list_item.widget.dart index dfe64409..80c3c958 100644 --- a/flutter_readium/example/lib/widgets/list_item.widget.dart +++ b/flutter_readium/example/lib/widgets/list_item.widget.dart @@ -19,7 +19,12 @@ class ListItemWidget extends StatelessWidget { @override Widget build(final BuildContext context) => Padding( - padding: EdgeInsets.fromLTRB(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding), + padding: EdgeInsets.fromLTRB( + horizontalPadding, + verticalPadding, + horizontalPadding, + verticalPadding, + ), child: isVerticalAlignment ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/flutter_readium/example/lib/widgets/pdf_settings.widget.dart b/flutter_readium/example/lib/widgets/pdf_settings.widget.dart index fdb29c39..fa18d002 100644 --- a/flutter_readium/example/lib/widgets/pdf_settings.widget.dart +++ b/flutter_readium/example/lib/widgets/pdf_settings.widget.dart @@ -38,9 +38,18 @@ class PDFSettingsWidget extends StatelessWidget { child: SegmentedButton( key: const ValueKey('pdf_layout_selector'), segments: const [ - ButtonSegment(value: PDFLayout.paginated, label: Text('Paginated')), - ButtonSegment(value: PDFLayout.scrollVertical, label: Text('Scroll V')), - ButtonSegment(value: PDFLayout.scrollHorizontal, label: Text('Scroll H')), + ButtonSegment( + value: PDFLayout.paginated, + label: Text('Paginated'), + ), + ButtonSegment( + value: PDFLayout.scrollVertical, + label: Text('Scroll V'), + ), + ButtonSegment( + value: PDFLayout.scrollHorizontal, + label: Text('Scroll H'), + ), ], selected: {state.layout}, onSelectionChanged: (values) { @@ -70,8 +79,14 @@ class PDFSettingsWidget extends StatelessWidget { child: SegmentedButton( key: const ValueKey('pdf_reading_progression_selector'), segments: const [ - ButtonSegment(value: PDFReadingProgression.ltr, label: Text('LTR')), - ButtonSegment(value: PDFReadingProgression.rtl, label: Text('RTL')), + ButtonSegment( + value: PDFReadingProgression.ltr, + label: Text('LTR'), + ), + ButtonSegment( + value: PDFReadingProgression.rtl, + label: Text('RTL'), + ), ], selected: {state.readingProgression}, onSelectionChanged: (values) { @@ -99,9 +114,13 @@ class PDFSettingsWidget extends StatelessWidget { key: const ValueKey('pdf_settings_close_button'), onPressed: () => Navigator.of(context).pop(), style: ButtonStyle( - padding: WidgetStateProperty.all(const EdgeInsets.symmetric(vertical: 16.0)), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(vertical: 16.0), + ), shape: WidgetStateProperty.all( - RoundedRectangleBorder(borderRadius: BorderRadius.circular(0.0)), + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0.0), + ), ), ), child: Row( diff --git a/flutter_readium/example/lib/widgets/player_controls.widget.dart b/flutter_readium/example/lib/widgets/player_controls.widget.dart index a5545764..1cfa4ae4 100644 --- a/flutter_readium/example/lib/widgets/player_controls.widget.dart +++ b/flutter_readium/example/lib/widgets/player_controls.widget.dart @@ -10,7 +10,9 @@ class PlayerControls extends StatelessWidget { final Publication publication; @override - Widget build(final BuildContext context) => BlocBuilder( + Widget build( + final BuildContext context, + ) => BlocBuilder( builder: (final context, final state) { final isAudioBook = publication.isAudioBook; final audioActive = state.audioEnabled; @@ -24,8 +26,9 @@ class PlayerControls extends StatelessWidget { children: [ IconButton( icon: const Icon(Icons.skip_previous), - onPressed: () => - context.read().add(SkipToPreviousChapter(publication: publication)), + onPressed: () => context.read().add( + SkipToPreviousChapter(publication: publication), + ), tooltip: 'Skip to previous chapter', ), IconButton( @@ -53,7 +56,9 @@ class PlayerControls extends StatelessWidget { // fakeInitialLocator = pub?.locatorFromLink(fakeInitialLink!); isAudioBook ? playerControls.add(Play(fromLocator: fromLocator)) - : playerControls.add(PlayTTS(fromLocator: fromLocator)); + : playerControls.add( + PlayTTS(fromLocator: fromLocator), + ); }, tooltip: state.playing ? 'Pause' : 'Play', ), @@ -73,7 +78,9 @@ class PlayerControls extends StatelessWidget { ), IconButton( icon: const Icon(Icons.skip_next), - onPressed: () => context.read().add(SkipToNextChapter(publication: publication)), + onPressed: () => context.read().add( + SkipToNextChapter(publication: publication), + ), tooltip: 'Skip to next chapter', ), if (audioActive) ...[ @@ -92,7 +99,9 @@ class PlayerControls extends StatelessWidget { ], IconButton( icon: const Icon(Icons.settings_voice), - onPressed: () => context.read().add(GetAvailableVoices()), + onPressed: () => context.read().add( + GetAvailableVoices(), + ), tooltip: 'Change voice', ), ], diff --git a/flutter_readium/example/lib/widgets/reader.widget.dart b/flutter_readium/example/lib/widgets/reader.widget.dart index 6919732f..878eb9ed 100644 --- a/flutter_readium/example/lib/widgets/reader.widget.dart +++ b/flutter_readium/example/lib/widgets/reader.widget.dart @@ -10,7 +10,9 @@ class ReaderWidget extends StatelessWidget { final ValueNotifier? shouldShowControls; @override - Widget build(final BuildContext context) => BlocBuilder( + Widget build( + final BuildContext context, + ) => BlocBuilder( buildWhen: (prev, next) => prev.hasNonHighlightChanges(next), builder: (final context, final state) { if (state.isLoading) { @@ -24,7 +26,10 @@ class ReaderWidget extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('Loading publication failed.', style: TextStyle(fontWeight: FontWeight.bold)), + Text( + 'Loading publication failed.', + style: TextStyle(fontWeight: FontWeight.bold), + ), SizedBox(height: 10), Text(state.errorDebugDescription()), ], @@ -53,7 +58,9 @@ class ReaderWidget extends StatelessWidget { debugPrint('[Selection] text="${event.selectedText}"'); }, onSelectionAction: (event) { - debugPrint('[SelectionAction] action=${event.actionId} text="${event.selectedText}"'); + debugPrint( + '[SelectionAction] action=${event.actionId} text="${event.selectedText}"', + ); if (event.actionId == 'highlight') { _applyHighlight(context, event); } else if (event.actionId == 'note') { @@ -61,7 +68,9 @@ class ReaderWidget extends StatelessWidget { } }, onDecorationInteraction: (event) { - debugPrint('[DecorationInteraction] id=${event.decorationId} group=${event.group}'); + debugPrint( + '[DecorationInteraction] id=${event.decorationId} group=${event.group}', + ); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Tapped highlight: ${event.decorationId}'), @@ -84,7 +93,10 @@ class ReaderWidget extends StatelessWidget { final decoration = ReaderDecoration( id: 'highlight_${DateTime.now().millisecondsSinceEpoch}', locator: event.locator, - style: const ReaderDecorationStyle(style: DecorationStyle.highlight, tint: Color(0x80FFFF00)), + style: const ReaderDecorationStyle( + style: DecorationStyle.highlight, + tint: Color(0x80FFFF00), + ), ); context.read().add(AddHighlight(decoration)); debugPrint('[Highlight] Applied highlight decoration'); @@ -97,7 +109,10 @@ class ReaderWidget extends StatelessWidget { title: const Text('Add Note'), content: Text('Selected: "${event.selectedText ?? '(no text)'}"'), actions: [ - TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Cancel')), + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('Cancel'), + ), TextButton( onPressed: () { Navigator.pop(ctx); diff --git a/flutter_readium/example/lib/widgets/text_settings.widget.dart b/flutter_readium/example/lib/widgets/text_settings.widget.dart index 1b7cfb3d..207b5596 100644 --- a/flutter_readium/example/lib/widgets/text_settings.widget.dart +++ b/flutter_readium/example/lib/widgets/text_settings.widget.dart @@ -175,7 +175,7 @@ class TextSettingsWidget extends StatelessWidget { // `scroll` field, so the web mapper silently drops it. Only // EPUB-profile publications (`Profile.EPUB` in `metadata.conformsTo`) // honor it on web. See `flutter_readium/CLAUDE.md` "Gotchas" and - // `flutter_readium/web/_scripts/WebPub/webPubPrefences.ts` + // `flutter_readium/web/src/preferences/FlutterWebPubPreferences.ts` // (`WEBPUB_UNSUPPORTED_KEYS`). We disable the toggle on web for // non-EPUB publications and surface the reason via a tooltip. ListItemWidget( diff --git a/flutter_readium/example/lib/widgets/theme_selector.widget.dart b/flutter_readium/example/lib/widgets/theme_selector.widget.dart index b9497271..c67eba4f 100644 --- a/flutter_readium/example/lib/widgets/theme_selector.widget.dart +++ b/flutter_readium/example/lib/widgets/theme_selector.widget.dart @@ -6,13 +6,19 @@ import '../extensions/index.dart'; import '../state/index.dart'; class ThemeSelectorWidget extends StatelessWidget { - const ThemeSelectorWidget({required this.themes, required this.isHighlight, super.key}); + const ThemeSelectorWidget({ + required this.themes, + required this.isHighlight, + super.key, + }); final List themes; final bool isHighlight; @override - Widget build(final BuildContext context) => BlocBuilder( + Widget build( + final BuildContext context, + ) => BlocBuilder( builder: (final context, final state) => ScrollConfiguration( behavior: const MaterialScrollBehavior().copyWith( dragDevices: { @@ -25,14 +31,18 @@ class ThemeSelectorWidget extends StatelessWidget { child: ToggleButtons( key: ValueKey(isHighlight ? 'highlight_toggle' : 'theme_toggle'), isSelected: themes - .map((final itemTheme) => itemTheme == (isHighlight ? state.highlight : state.theme)) + .map( + (final itemTheme) => itemTheme == (isHighlight ? state.highlight : state.theme), + ) .toList(), selectedBorderColor: (isHighlight ? state.highlight : state.theme).textColor, borderWidth: 4.0, borderColor: Colors.transparent, onPressed: (final index) { if (isHighlight) { - context.read().add(ChangeHighlight(themes[index])); + context.read().add( + ChangeHighlight(themes[index]), + ); } else { context.read().add(ChangeTheme(themes[index])); } @@ -44,7 +54,13 @@ class ThemeSelectorWidget extends StatelessWidget { height: 80, color: itemTheme.backgroundColor, child: Center( - child: Text('Aa', style: TextStyle(color: itemTheme.textColor, fontSize: 20)), + child: Text( + 'Aa', + style: TextStyle( + color: itemTheme.textColor, + fontSize: 20, + ), + ), ), ), ) diff --git a/flutter_readium/example/lib/widgets/timebased.state.widget.dart b/flutter_readium/example/lib/widgets/timebased.state.widget.dart index 770f6855..041a89e1 100644 --- a/flutter_readium/example/lib/widgets/timebased.state.widget.dart +++ b/flutter_readium/example/lib/widgets/timebased.state.widget.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../state/index.dart'; @@ -33,9 +33,13 @@ class _TimebasedStateWidgetState extends State { // Text('TotalProgression: ${snapshot.data?.currentLocator?.locations?.totalProgression}'), SizedBox(height: 22), Text('Chapter progress:'), - LinearProgressIndicator(value: snapshot.data?.currentLocator?.locations?.progression ?? 0.0), + LinearProgressIndicator( + value: snapshot.data?.currentLocator?.locations?.progression ?? 0.0, + ), Text('Total book progress:'), - LinearProgressIndicator(value: snapshot.data?.currentLocator?.locations?.totalProgression ?? 0), + LinearProgressIndicator( + value: snapshot.data?.currentLocator?.locations?.totalProgression ?? 0, + ), ], ); } else { diff --git a/flutter_readium/example/test/widget_test.dart b/flutter_readium/example/test/widget_test.dart index 76f978d4..3623b82d 100644 --- a/flutter_readium/example/test/widget_test.dart +++ b/flutter_readium/example/test/widget_test.dart @@ -16,7 +16,9 @@ void main() { // Verify that platform version is retrieved. expect( - find.byWidgetPredicate((Widget widget) => widget is Text && widget.data!.startsWith('Bookshelf')), + find.byWidgetPredicate( + (Widget widget) => widget is Text && widget.data!.startsWith('Bookshelf'), + ), findsOneWidget, ); }); diff --git a/flutter_readium/example/web/readiumReader.js b/flutter_readium/example/web/readiumReader.js index f6a39e21..b7620cad 100644 --- a/flutter_readium/example/web/readiumReader.js +++ b/flutter_readium/example/web/readiumReader.js @@ -1 +1 @@ -(()=>{"use strict";var __webpack_modules__={"./node_modules/css-loader/dist/cjs.js!./web/_scripts/style.css"(module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ "./node_modules/css-loader/dist/runtime/noSourceMaps.js");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `:root {\n /* Material UI */\n font-family: \'Roboto\', system-ui, sans-serif;\n}\n\nhtml,\nbody {\n min-height: 100%;\n overflow: hidden;\n touch-action: pan-x pan-y;\n overscroll-behavior-x: none;\n overscroll-behavior-y: none;\n}\n\nbody {\n margin: 0;\n background: #eee;\n}\n\n#bottom-bar,\n#top-bar {\n height: 48px;\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 2px;\n touch-action: manipulation;\n}\n\n#top-bar {\n justify-content: space-between;\n padding: 0 1em;\n}\n\n#wrapper {\n height: calc(100vh - 96px) !important;\n height: calc(100dvh - 96px) !important; /* New browsers */\n display: flex;\n margin: 0;\n}\n\n#container {\n contain: content;\n width: 100% !important;\n height: 100% !important;\n}\n\n.readium-navigator-iframe {\n width: 100%;\n height: 100%;\n border-width: 0;\n}\n\n/* Loading spinner for resources */\n@keyframes loading {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\ndiv:has(> .readium-navigator-iframe.blank)::after {\n content: \'\';\n position: absolute;\n top: 50%;\n left: 50%;\n margin-top: -30px;\n margin-left: -30px;\n width: 50px;\n height: 50px;\n border-radius: 50px;\n border: 5px solid grey;\n border-top-color: black;\n animation: loading 2s linear infinite;\n}\n\n[type=\'pagebreak\'] {\n border-top: 1px solid !important;\n display: block !important;\n width: 100% !important;\n line-height: 100% !important;\n padding-top: 8px !important;\n margin-top: 40px !important;\n margin-bottom: 20px !important;\n text-align: right !important;\n font-size: 98% !important;\n}\nspan#activeLocation {\n border-radius: 4px;\n background-color: var(--USER__highlightBackgroundColor) !important;\n color: var(--USER__highlightForegroundColor) !important;\n}\nbody > *:first-child {\n margin-top: 50px !important;\n}\n* {\n word-wrap: break-word;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n margin: 15px 0;\n width: calc(100% - var(--RS__pageGutter) / 2);\n word-break: break-word;\n}\ntable h1,\ntable h2,\ntable h3,\ntable h4,\ntable h5,\ntable h6 {\n margin: 0;\n}\ntable * {\n font-size: 1rem;\n}\ntable td,\ntable th {\n border-collapse: collapse;\n border: 1px solid #ccc;\n margin: 0;\n padding: 16px;\n vertical-align: top;\n}\ntable caption {\n margin-bottom: 16px;\n}\ntable.transparent-table,\ntable.docx-table,\ntable.plain-table {\n table-layout: fixed;\n width: 100%;\n}\ntable.transparent-table th,\ntable.transparent-table td,\ntable.docx-table th,\ntable.docx-table td,\ntable.plain-table th,\ntable.plain-table td {\n width: auto;\n max-width: 100%;\n}\ntable.transparent-table {\n border-width: 0;\n}\ntable.transparent-table td,\ntable.transparent-table th {\n border-width: 0;\n}\ntable.has-first-row-headers tr:first-child {\n display: none;\n}\ntable.has-header {\n border: none !important;\n}\ntable.has-header tr {\n display: block;\n margin-bottom: 25px;\n}\ntable.has-header tr td {\n border-top-width: 0;\n display: block;\n width: 100% !important;\n box-sizing: border-box;\n}\ntable.has-header tr td:first-child {\n border-top-width: 1px;\n}\ntable.has-header tr td:not(.mobile-header):before {\n background-color: #7c7c7c;\n color: #fff;\n content: attr(data-th);\n display: block;\n margin: -16px -16px 5px;\n padding: 8px 16px;\n}\ntable.has-header tr td.mobile-header {\n text-transform: uppercase;\n background-color: #241f20 !important;\n}\ntable.has-header tr td.mobile-header h6 {\n color: #fff;\n}\ntable.has-header thead tr:first-child {\n display: none;\n}\n`, ""]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack:///./web/_scripts/style.css?./node_modules/css-loader/dist/cjs.js\n}')},"./node_modules/css-loader/dist/runtime/api.js"(module){eval('{\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = "";\n var needLayer = typeof item[5] !== "undefined";\n if (item[4]) {\n content += "@supports (".concat(item[4], ") {");\n }\n if (item[2]) {\n content += "@media ".concat(item[2], " {");\n }\n if (needLayer) {\n content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += "}";\n }\n if (item[2]) {\n content += "}";\n }\n if (item[4]) {\n content += "}";\n }\n return content;\n }).join("");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === "string") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== "undefined") {\n if (typeof item[5] === "undefined") {\n item[5] = layer;\n } else {\n item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = "".concat(supports);\n } else {\n item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};\n\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/api.js?\n}')},"./node_modules/css-loader/dist/runtime/noSourceMaps.js"(module){eval("{\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/noSourceMaps.js?\n}")},"./web/_scripts/style.css"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ "./node_modules/style-loader/dist/runtime/styleDomAPI.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ "./node_modules/style-loader/dist/runtime/insertBySelector.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ "./node_modules/style-loader/dist/runtime/insertStyleElement.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ "./node_modules/style-loader/dist/runtime/styleTagTransform.js");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!./style.css */ "./node_modules/css-loader/dist/cjs.js!./web/_scripts/style.css");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\noptions.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, "head");\noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"], options);\n\n\n\n\n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"] && _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals ? _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals : undefined);\n\n\n//# sourceURL=webpack:///./web/_scripts/style.css?\n}')},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"(module){eval('{\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = "".concat(id, " ").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?\n}')},"./node_modules/style-loader/dist/runtime/insertBySelector.js"(module){eval('{\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === "undefined") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error("Couldn\'t find a style target. This probably means that the value for the \'insert\' parameter is invalid.");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/insertBySelector.js?\n}')},"./node_modules/style-loader/dist/runtime/insertStyleElement.js"(module){eval('{\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement("style");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/insertStyleElement.js?\n}')},"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"(module,__unused_webpack_exports,__webpack_require__){eval('{\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n if (nonce) {\n styleElement.setAttribute("nonce", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?\n}')},"./node_modules/style-loader/dist/runtime/styleDomAPI.js"(module){eval('{\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = "";\n if (obj.supports) {\n css += "@supports (".concat(obj.supports, ") {");\n }\n if (obj.media) {\n css += "@media ".concat(obj.media, " {");\n }\n var needLayer = typeof obj.layer !== "undefined";\n if (needLayer) {\n css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");\n }\n css += obj.css;\n if (needLayer) {\n css += "}";\n }\n if (obj.media) {\n css += "}";\n }\n if (obj.supports) {\n css += "}";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== "undefined") {\n css += "\\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === "undefined") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/styleDomAPI.js?\n}')},"./node_modules/style-loader/dist/runtime/styleTagTransform.js"(module){eval("{\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack:///./node_modules/style-loader/dist/runtime/styleTagTransform.js?\n}")},"./web/_scripts/Audio/audioNavigator.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ __testing__: () => (/* binding */ __testing__),\n/* harmony export */ buildStatePayload: () => (/* binding */ buildStatePayload),\n/* harmony export */ initializeAudioNavigator: () => (/* binding */ initializeAudioNavigator),\n/* harmony export */ seekAudioAndResume: () => (/* binding */ seekAudioAndResume),\n/* harmony export */ setAudioEmissionsEnabled: () => (/* binding */ setAudioEmissionsEnabled)\n/* harmony export */ });\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_3__.createLogger)("AudioNav");\nfunction makeAudioTotalProgressionFn(publication) {\n const items = publication.readingOrder.items;\n const missing = items.some((i) => i.duration === undefined || i.duration <= 0);\n if (missing) {\n log.warn("Cannot compute audio totalProgression: one or more readingOrder items missing duration");\n return () => undefined;\n }\n const cumulative = [];\n let total = 0;\n for (const item of items) {\n cumulative.push(total);\n total += item.duration;\n }\n return (locator) => {\n if (total <= 0)\n return undefined;\n const bareHref = locator.href.split("#")[0];\n const idx = items.findIndex((i) => i.href === bareHref);\n if (idx < 0)\n return undefined;\n const time = locator.locations?.time?.() ?? 0;\n const value = (cumulative[idx] + time) / total;\n return Math.min(1, Math.max(0, value));\n };\n}\nfunction withTotalProgression(locator, totalProgression) {\n if (totalProgression === undefined)\n return locator;\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Locator({\n href: locator.href,\n type: locator.type,\n title: locator.title,\n text: locator.text,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.LocatorLocations({\n fragments: locator.locations?.fragments,\n progression: locator.locations?.progression,\n position: locator.locations?.position,\n totalProgression,\n otherLocations: locator.locations?.otherLocations,\n }),\n });\n}\nfunction withTocHref(locator, tocHref) {\n if (!tocHref)\n return locator;\n const merged = new Map(locator.locations?.otherLocations ?? []);\n merged.set("tocHref", tocHref);\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Locator({\n href: locator.href,\n type: locator.type,\n title: locator.title,\n text: locator.text,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.LocatorLocations({\n fragments: locator.locations?.fragments,\n progression: locator.locations?.progression,\n position: locator.locations?.position,\n totalProgression: locator.locations?.totalProgression,\n otherLocations: merged,\n }),\n });\n}\nfunction buildStatePayload(state, nav, locator) {\n const currentLocator = locator ?? nav.currentLocator;\n return JSON.stringify({\n state,\n currentOffset: Math.round(nav.currentTime * 1000),\n currentDuration: nav.duration > 0 ? Math.round(nav.duration * 1000) : null,\n currentLocator: currentLocator?.serialize(),\n });\n}\nfunction preferencesFromString(preferencesString) {\n const prefs = (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.normalizeTypes)(JSON.parse(preferencesString));\n log.debug("Parsed AudioPreferences", prefs);\n return {\n volume: prefs.volume ?? null,\n playbackRate: prefs.speed ?? null,\n skipBackwardInterval: prefs.seekInterval ?? null,\n skipForwardInterval: prefs.seekInterval ?? null,\n pollInterval: prefs.updateIntervalSecs != null\n ? prefs.updateIntervalSecs * 1000\n : null,\n autoPlay: true,\n };\n}\nconst SAME_POSITION_EPSILON_S = 0.1;\nfunction isAlreadyAtPosition(nav, audioLocator) {\n const targetHref = audioLocator.href.split("#")[0];\n const currentHref = nav.currentLocator.href.split("#")[0];\n if (targetHref !== currentHref)\n return false;\n const targetTime = audioLocator.locations?.time();\n if (targetTime === undefined)\n return false;\n return Math.abs(targetTime - nav.currentTime) <= SAME_POSITION_EPSILON_S;\n}\nfunction seekAudioAndResume(nav, audioLocator, resumePlaying) {\n if (isAlreadyAtPosition(nav, audioLocator)) {\n if (resumePlaying) {\n if (nav.isPlaying)\n nav.pause();\n nav.play();\n }\n return Promise.resolve();\n }\n if (nav.isPlaying)\n nav.pause();\n return nav.go(audioLocator, false, (ok) => {\n if (!ok) {\n log.warn("seekAudioAndResume: audio seek failed for", audioLocator.href);\n return;\n }\n if (resumePlaying)\n nav.play();\n });\n}\nlet _emissionsEnabled = true;\nfunction setAudioEmissionsEnabled(enabled) {\n _emissionsEnabled = enabled;\n}\nfunction _emitState(state, nav, rawLocator, mapper, alsoText, computeTotalProgression, onTextLocatorChanged, getTocHref) {\n if (!_emissionsEnabled)\n return;\n const locator = rawLocator ?? nav.currentLocator;\n if (mapper) {\n const { stateLocator, textLocator } = mapper(nav, locator);\n const enrichedStateLocator = withTotalProgression(stateLocator, computeTotalProgression(locator));\n window.updateTimebasedPlayerState?.(buildStatePayload(state, nav, enrichedStateLocator));\n if (textLocator) {\n window.updateTextLocator?.(JSON.stringify(textLocator.serialize()));\n onTextLocatorChanged?.(textLocator, undefined);\n }\n }\n else {\n const enriched = withTocHref(withTotalProgression(locator, computeTotalProgression(locator)), getTocHref?.());\n window.updateTimebasedPlayerState?.(buildStatePayload(state, nav, enriched));\n if (alsoText) {\n window.updateTextLocator?.(JSON.stringify(enriched.serialize()));\n }\n }\n}\nasync function initializeAudioNavigator(publication, initialPosition, preferencesJsonString, setNav, locatorMapper, onTextLocatorChanged, pollIntervalOverrideMs) {\n const tracks = publication.readingOrder.items.length;\n log.info(`Initializing AudioNavigator with ${tracks} track(s)`, initialPosition\n ? `from ${initialPosition.href} ${initialPosition.locations?.fragments?.[0] ?? ""}`\n : "(no initial position — starting at first track)", locatorMapper ? "[Media Overlay mapper attached]" : "", pollIntervalOverrideMs != null ? `[pollInterval override: ${pollIntervalOverrideMs}ms]` : "");\n _emissionsEnabled = true;\n const basePrefs = preferencesFromString(preferencesJsonString);\n if (pollIntervalOverrideMs != null) {\n basePrefs.pollInterval = pollIntervalOverrideMs;\n }\n const configuration = {\n preferences: basePrefs,\n defaults: {\n volume: 1.0,\n playbackRate: 1.0,\n preservePitch: true,\n skipBackwardInterval: 10,\n skipForwardInterval: 30,\n pollInterval: 1000,\n autoPlay: true,\n enableMediaSession: true,\n },\n };\n const computeTotalProgression = makeAudioTotalProgressionFn(publication);\n const timeline = locatorMapper ? undefined : _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Timeline.build(publication);\n let currentTocHref;\n const getTocHref = timeline ? () => currentTocHref : undefined;\n let nav;\n const ready = new Promise((resolve) => {\n let resolved = false;\n const listeners = {\n trackLoaded: (_media) => {\n if (!resolved) {\n resolved = true;\n log.info("AudioNavigator ready (first track loaded)");\n setNav(nav);\n resolve();\n }\n },\n positionChanged: (locator) => {\n _emitState(nav.isPlaying ? "playing" : "paused", nav, locator, locatorMapper, true, computeTotalProgression, onTextLocatorChanged, getTocHref);\n },\n timelineItemChanged: (item) => {\n if (timeline && item) {\n const link = timeline.linkFor(item);\n currentTocHref = link?.href;\n log.debug("timelineItemChanged", item.title, "→ tocHref:", currentTocHref ?? "(none)");\n }\n },\n play: (locator) => {\n log.info("play event", locator?.href, locator?.locations?.fragments?.[0] ?? "");\n _emitState("playing", nav, locator, locatorMapper, false, computeTotalProgression, onTextLocatorChanged, getTocHref);\n },\n pause: (locator) => {\n log.info("pause event", locator?.href, locator?.locations?.fragments?.[0] ?? "");\n _emitState("paused", nav, locator, locatorMapper, false, computeTotalProgression, onTextLocatorChanged, getTocHref);\n },\n trackEnded: (locator) => {\n if (!nav.canGoForward) {\n log.info("Publication ended (last track)");\n _emitState("ended", nav, locator, locatorMapper, false, computeTotalProgression, onTextLocatorChanged, getTocHref);\n }\n else {\n log.debug("Track ended, auto-advancing to next track");\n }\n },\n stalled: (isStalled) => {\n log.debug(isStalled ? "Playback stalled (buffering)" : "Stall resolved");\n _emitState(isStalled ? "loading" : nav.isPlaying ? "playing" : "paused", nav, undefined, locatorMapper, false, computeTotalProgression, onTextLocatorChanged, getTocHref);\n },\n error: (_error, locator) => {\n log.error("AudioNavigator error:", _error, "locator:", locator?.href);\n _emitState("failure", nav, locator, locatorMapper, false, computeTotalProgression, onTextLocatorChanged, getTocHref);\n },\n metadataLoaded: (_metadata) => { },\n seeking: (_isSeeking) => { },\n seekable: (_seekable) => { },\n contentProtection: (_type, _data) => { },\n peripheral: (_data) => { },\n contextMenu: (_data) => { },\n remotePlaybackStateChanged: (_state) => { },\n };\n nav = new _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.AudioNavigator(publication, listeners, initialPosition, configuration);\n });\n await ready;\n}\nconst __testing__ = {\n makeAudioTotalProgressionFn,\n withTocHref,\n};\n\n\n//# sourceURL=webpack:///./web/_scripts/Audio/audioNavigator.ts?\n}')},"./web/_scripts/Audio/guidedNavigation.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ GUIDED_NAVIGATION_MEDIA_TYPE: () => (/* binding */ GUIDED_NAVIGATION_MEDIA_TYPE),\n/* harmony export */ __testing__: () => (/* binding */ __testing__),\n/* harmony export */ detectGuidedNavigation: () => (/* binding */ detectGuidedNavigation),\n/* harmony export */ parseGuidedNavigation: () => (/* binding */ parseGuidedNavigation)\n/* harmony export */ });\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _syncNarration__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./syncNarration */ "./web/_scripts/Audio/syncNarration.ts");\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_0__.createLogger)("GuidedNavigation");\nconst GUIDED_NAVIGATION_MEDIA_TYPE = "application/guided-navigation+json";\nfunction detectGuidedNavigation(publication) {\n if (_publicationLevelLink(publication))\n return true;\n for (const link of publication.readingOrder.items) {\n const alternates = link.alternates;\n if (!alternates)\n continue;\n if (alternates.findWithMediaType(GUIDED_NAVIGATION_MEDIA_TYPE))\n return true;\n }\n return false;\n}\nasync function parseGuidedNavigation(publication) {\n const singleDocLink = _publicationLevelLink(publication);\n const items = singleDocLink\n ? await _parsePublicationLevelDocument(publication, singleDocLink)\n : await _parseReadingOrderAlternates(publication);\n return (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.enrichItemsWithToc)(items, publication);\n}\nasync function _parsePublicationLevelDocument(publication, link) {\n let document = null;\n try {\n const resource = publication.get(link);\n const json = await resource.readAsJSON();\n document = _parseDocument(json);\n }\n catch (err) {\n log.warn("Strategy 1: failed to fetch/parse guided navigation document", err);\n return [];\n }\n if (!document) {\n log.warn("Strategy 1: guided navigation document had no usable \'guided\' entries");\n return [];\n }\n const items = [];\n for (const obj of document.guided) {\n _flattenWithReadingOrderLookup(obj, items, publication);\n }\n return items;\n}\nasync function _parseReadingOrderAlternates(publication) {\n const result = [];\n for (let i = 0; i < publication.readingOrder.items.length; i++) {\n const roLink = publication.readingOrder.items[i];\n const alternates = roLink.alternates;\n if (!alternates)\n continue;\n const gnLink = alternates.findWithMediaType(GUIDED_NAVIGATION_MEDIA_TYPE);\n if (!gnLink)\n continue;\n let document = null;\n try {\n const resource = publication.get(gnLink);\n const json = await resource.readAsJSON();\n document = _parseDocument(json);\n }\n catch (err) {\n log.warn("Strategy 2: failed to fetch/parse alternate for", roLink.href, err);\n continue;\n }\n if (!document) {\n log.warn("Strategy 2: alternate had no usable \'guided\' entries for", roLink.href);\n continue;\n }\n const position = i + 1;\n const readingOrderDuration = roLink.duration;\n for (const obj of document.guided) {\n _flattenWithFixedPosition(obj, position, readingOrderDuration, result);\n }\n }\n return result;\n}\nfunction _flattenWithReadingOrderLookup(obj, out, publication) {\n if (obj.audioref !== undefined && obj.textref !== undefined) {\n const { textHref } = (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.parseTextField)(obj.textref);\n const roIndex = publication.readingOrder.items.findIndex((link) => (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.normalizeHref)(link.href) === (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.normalizeHref)(textHref));\n const position = roIndex === -1 ? 0 : roIndex + 1;\n const readingOrderDuration = roIndex === -1 ? undefined : publication.readingOrder.items[roIndex].duration;\n out.push(_buildItem(obj.audioref, obj.textref, position, readingOrderDuration));\n }\n for (const child of obj.children) {\n _flattenWithReadingOrderLookup(child, out, publication);\n }\n}\nfunction _flattenWithFixedPosition(obj, position, readingOrderDuration, out) {\n if (obj.audioref !== undefined && obj.textref !== undefined) {\n out.push(_buildItem(obj.audioref, obj.textref, position, readingOrderDuration));\n }\n for (const child of obj.children) {\n _flattenWithFixedPosition(child, position, readingOrderDuration, out);\n }\n}\nfunction _buildItem(audioref, textref, position, readingOrderDuration) {\n const { audioHref, audioStart, audioEnd } = (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.parseAudioField)(audioref);\n const { textHref, textId } = (0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.parseTextField)(textref);\n return {\n audio: audioref,\n text: textref,\n position,\n audioHref,\n audioStart,\n audioEnd,\n textHref,\n textId,\n readingOrderDuration,\n };\n}\nfunction _parseDocument(json) {\n if (!(0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.isJsonObject)(json))\n return null;\n const guidedRaw = json["guided"];\n if (!Array.isArray(guidedRaw) || guidedRaw.length === 0)\n return null;\n const guided = [];\n for (const item of guidedRaw) {\n const parsed = _parseObject(item);\n if (parsed)\n guided.push(parsed);\n }\n if (guided.length === 0)\n return null;\n return { guided };\n}\nfunction _parseObject(json) {\n if (!(0,_syncNarration__WEBPACK_IMPORTED_MODULE_1__.isJsonObject)(json))\n return null;\n const audiorefRaw = json["audioref"];\n const textrefRaw = json["textref"];\n const audioref = typeof audiorefRaw === "string" ? audiorefRaw : undefined;\n const textref = typeof textrefRaw === "string" ? textrefRaw : undefined;\n const children = [];\n const childrenRaw = json["children"];\n if (Array.isArray(childrenRaw)) {\n for (const childJson of childrenRaw) {\n const parsedChild = _parseObject(childJson);\n if (parsedChild)\n children.push(parsedChild);\n }\n }\n if (audioref === undefined && textref === undefined && children.length === 0)\n return null;\n return { audioref, textref, children };\n}\nfunction _publicationLevelLink(publication) {\n const links = publication.manifest.links;\n if (!links)\n return undefined;\n return links.findWithMediaType(GUIDED_NAVIGATION_MEDIA_TYPE);\n}\nconst __testing__ = {\n parseDocument: _parseDocument,\n parseObject: _parseObject,\n};\n\n\n//# sourceURL=webpack:///./web/_scripts/Audio/guidedNavigation.ts?\n}')},"./web/_scripts/Audio/mediaOverlayNavigator.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ __testing__: () => (/* binding */ __testing__),\n/* harmony export */ initializeGuidedNavigationNavigator: () => (/* binding */ initializeGuidedNavigationNavigator),\n/* harmony export */ initializeMediaOverlayNavigator: () => (/* binding */ initializeMediaOverlayNavigator)\n/* harmony export */ });\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _extensions_ReadiumPublication__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../extensions/ReadiumPublication */ "./web/_scripts/extensions/ReadiumPublication.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _audioNavigator__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./audioNavigator */ "./web/_scripts/Audio/audioNavigator.ts");\n/* harmony import */ var _syncNarration__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./syncNarration */ "./web/_scripts/Audio/syncNarration.ts");\n/* harmony import */ var _guidedNavigation__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./guidedNavigation */ "./web/_scripts/Audio/guidedNavigation.ts");\n\n\n\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_2__.createLogger)("MediaOverlay");\nasync function initializeMediaOverlayNavigator(publication, initialLocator, prefsJson, setNav, onTextLocatorChanged) {\n const items = await (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.parseSyncNarration)(publication);\n return _initializeFromItems(publication, items, initialLocator, prefsJson, setNav, onTextLocatorChanged, "SyncNarration");\n}\nasync function initializeGuidedNavigationNavigator(publication, initialLocator, prefsJson, setNav, onTextLocatorChanged) {\n const items = await (0,_guidedNavigation__WEBPACK_IMPORTED_MODULE_5__.parseGuidedNavigation)(publication);\n return _initializeFromItems(publication, items, initialLocator, prefsJson, setNav, onTextLocatorChanged, "GuidedNavigation");\n}\nasync function _initializeFromItems(publication, items, initialLocator, prefsJson, setNav, onTextLocatorChanged, sourceLabel) {\n log.info(`Initializing MediaOverlayNavigator (source: ${sourceLabel})`, initialLocator ? `from text locator ${initialLocator.href}` : "(no initial locator)");\n if (items.length === 0) {\n log.warn(`No items found from ${sourceLabel}; aborting.`);\n return;\n }\n const uniqueAudioFiles = new Set(items.map((i) => i.audioHref)).size;\n log.info(`Parsed ${items.length} items across ${uniqueAudioFiles} audio file(s)`);\n const audioReadingOrder = _buildAudioReadingOrder(items, publication);\n log.info(`Built synthetic audio reading order with ${audioReadingOrder.length} entries`, audioReadingOrder.length > 0\n ? `(first=${audioReadingOrder[0].href}, last=${audioReadingOrder[audioReadingOrder.length - 1].href})`\n : "");\n const syntheticPub = _buildAudiobookPublication(publication, audioReadingOrder);\n const resolvedItems = _resolveItemHrefs(items, audioReadingOrder);\n const audioInitialLocator = initialLocator\n ? (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.textLocatorToAudioLocator)(resolvedItems, initialLocator)\n : undefined;\n if (initialLocator) {\n log.info(audioInitialLocator\n ? `Initial text locator mapped to audio ${audioInitialLocator.href} ${audioInitialLocator.locations?.fragments?.[0] ?? ""}`\n : `Initial text locator could not be mapped to an audio item — starting at beginning`);\n }\n const mapper = (_nav, audioLocator) => {\n const resolvedTime = audioLocator.locations?.time() ?? _nav.currentTime;\n const item = (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.findItemByAudioTime)(resolvedItems, audioLocator.href, resolvedTime);\n if (item) {\n return {\n stateLocator: (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.combinedLocatorForItem)(item, audioLocator),\n textLocator: (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.textLocatorForItem)(item),\n };\n }\n return { stateLocator: audioLocator };\n };\n const wrappedCallback = onTextLocatorChanged\n ? (locator, _ignored) => {\n const fragId = locator.locations?.fragments?.[0];\n const item = fragId\n ? resolvedItems.find((i) => i.textId === fragId)\n : undefined;\n const durationMs = item?.audioStart != null && item?.audioEnd != null\n ? (item.audioEnd - item.audioStart) * 1000\n : undefined;\n log.debug(`[mediaOverlay] cue fragment="${fragId ?? "(none)"}" ` +\n `item=${item ? `audioStart=${item.audioStart} audioEnd=${item.audioEnd}` : "NOT FOUND"} ` +\n `→ durationMs=${durationMs ?? "undefined"}`);\n onTextLocatorChanged(locator, durationMs);\n }\n : undefined;\n await (0,_audioNavigator__WEBPACK_IMPORTED_MODULE_3__.initializeAudioNavigator)(syntheticPub, audioInitialLocator, prefsJson, (nav) => setNav(nav, resolvedItems), mapper, wrappedCallback, 100);\n if (wrappedCallback) {\n const fragment = audioInitialLocator?.locations?.fragments?.[0];\n const initTime = fragment?.startsWith("t=") ? parseFloat(fragment.slice(2)) : 0;\n const initHref = audioInitialLocator?.href ?? resolvedItems[0]?.audioHref;\n const initItem = initHref\n ? (0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.findItemByAudioTime)(resolvedItems, initHref, initTime) ?? resolvedItems[0]\n : resolvedItems[0];\n if (initItem) {\n const initDurationMs = initItem.audioStart != null && initItem.audioEnd != null\n ? (initItem.audioEnd - initItem.audioStart) * 1000\n : undefined;\n wrappedCallback((0,_syncNarration__WEBPACK_IMPORTED_MODULE_4__.textLocatorForItem)(initItem), initDurationMs);\n }\n }\n}\nfunction _resolveItemHrefs(items, audioReadingOrder) {\n return items.map((item) => {\n const absLink = audioReadingOrder.find((l) => l.href === item.audioHref || l.href.endsWith("/" + item.audioHref));\n return absLink ? { ...item, audioHref: absLink.href } : item;\n });\n}\nfunction _buildAudioReadingOrder(items, publication) {\n const seen = new Map();\n for (const item of items) {\n const key = item.audioHref;\n if (!seen.has(key)) {\n seen.set(key, { cueSum: 0 });\n }\n const entry = seen.get(key);\n if (item.audioStart !== null && item.audioEnd !== null) {\n entry.cueSum += item.audioEnd - item.audioStart;\n }\n if (item.readingOrderDuration !== undefined) {\n entry.declaredDuration = Math.max(entry.declaredDuration ?? 0, item.readingOrderDuration);\n }\n if (!entry.title && item.tocTitle) {\n entry.title = item.tocTitle;\n }\n }\n const rawSelfHref = publication.manifest.linksWithRel("self")[0]?.href ?? "";\n const selfHref = rawSelfHref && typeof window !== "undefined"\n ? new URL(rawSelfHref, window.location.href).href\n : rawSelfHref;\n const baseUrl = selfHref.endsWith("/")\n ? selfHref\n : selfHref.slice(0, selfHref.lastIndexOf("/") + 1);\n return Array.from(seen.entries()).map(([href, meta]) => {\n const absoluteHref = href.startsWith("http") ? href : baseUrl + href;\n const duration = meta.declaredDuration ?? (meta.cueSum > 0 ? meta.cueSum : undefined);\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Link({\n href: absoluteHref,\n type: _audioMimeType(href),\n title: meta.title,\n duration,\n });\n });\n}\nfunction _audioMimeType(href) {\n if (href.endsWith(".mp3"))\n return "audio/mpeg";\n if (href.endsWith(".ogg") || href.endsWith(".oga"))\n return "audio/ogg";\n if (href.endsWith(".opus"))\n return "audio/ogg; codecs=opus";\n if (href.endsWith(".m4a") || href.endsWith(".aac"))\n return "audio/mp4";\n if (href.endsWith(".wav"))\n return "audio/wav";\n return "audio/mpeg";\n}\nfunction _buildAudiobookPublication(publication, audioReadingOrder) {\n const manifestJson = publication.manifest.serialize();\n manifestJson.readingOrder = audioReadingOrder.map((l) => l.serialize());\n if (!manifestJson.metadata)\n manifestJson.metadata = {};\n manifestJson.metadata.conformsTo = [_readium_shared__WEBPACK_IMPORTED_MODULE_0__.Profile.AUDIOBOOK];\n const manifest = _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Manifest.deserialize(manifestJson);\n if (manifest == undefined) {\n throw new Error("Failed to create new Audiobook manifest");\n }\n const selfLink = publication.manifest.linksWithRel("self")[0];\n if (selfLink?.href)\n manifest.setSelfLink(selfLink.href);\n return new _extensions_ReadiumPublication__WEBPACK_IMPORTED_MODULE_1__.ReadiumPublication({ manifest, fetcher: publication.fetcher });\n}\nconst __testing__ = {\n audioMimeType: _audioMimeType,\n resolveItemHrefs: _resolveItemHrefs,\n buildAudioReadingOrder: _buildAudioReadingOrder,\n};\n\n\n//# sourceURL=webpack:///./web/_scripts/Audio/mediaOverlayNavigator.ts?\n}')},"./web/_scripts/Audio/syncNarration.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ combinedLocatorForItem: () => (/* binding */ combinedLocatorForItem),\n/* harmony export */ detectSyncNarration: () => (/* binding */ detectSyncNarration),\n/* harmony export */ enrichItemsWithToc: () => (/* binding */ enrichItemsWithToc),\n/* harmony export */ findItemByAudioTime: () => (/* binding */ findItemByAudioTime),\n/* harmony export */ flattenToc: () => (/* binding */ flattenToc),\n/* harmony export */ isJsonObject: () => (/* binding */ isJsonObject),\n/* harmony export */ normalizeHref: () => (/* binding */ normalizeHref),\n/* harmony export */ parseAudioField: () => (/* binding */ parseAudioField),\n/* harmony export */ parseSyncNarration: () => (/* binding */ parseSyncNarration),\n/* harmony export */ parseTextField: () => (/* binding */ parseTextField),\n/* harmony export */ textLocatorForItem: () => (/* binding */ textLocatorForItem),\n/* harmony export */ textLocatorToAudioLocator: () => (/* binding */ textLocatorToAudioLocator)\n/* harmony export */ });\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_1__.createLogger)("SyncNarration");\nconst NARRATION_MEDIA_TYPE = "application/vnd.readium.narration+json";\nfunction detectSyncNarration(publication) {\n for (const link of publication.readingOrder.items) {\n if (_narrationAlternate(link) !== null)\n return true;\n }\n return false;\n}\nasync function parseSyncNarration(publication) {\n const result = [];\n for (let i = 0; i < publication.readingOrder.items.length; i++) {\n const link = publication.readingOrder.items[i];\n const narrationLink = _narrationAlternate(link);\n if (!narrationLink)\n continue;\n try {\n const resource = publication.get(narrationLink);\n const json = await resource.readAsJSON();\n const items = _parseNarrationJson(json, i, link.duration);\n result.push(...items);\n }\n catch (err) {\n log.warn("Failed to fetch/parse alternate for", link.href, err);\n }\n }\n return enrichItemsWithToc(result, publication);\n}\nfunction textLocatorForItem(item) {\n const otherLocationEntries = [];\n if (item.textId)\n otherLocationEntries.push(["cssSelector", `#${item.textId}`]);\n if (item.tocHref)\n otherLocationEntries.push(["tocHref", item.tocHref]);\n const otherLocations = otherLocationEntries.length > 0 ? new Map(otherLocationEntries) : undefined;\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Locator({\n href: item.textHref,\n type: "text/html",\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorLocations({\n fragments: item.textId ? [item.textId] : [],\n position: item.position + 1,\n otherLocations,\n }),\n title: item.tocTitle,\n text: item.highlight ? new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorText({ highlight: item.highlight }) : undefined,\n });\n}\nfunction combinedLocatorForItem(item, audioLocator) {\n const textLoc = textLocatorForItem(item);\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Locator({\n href: textLoc.href,\n type: textLoc.type,\n title: textLoc.title,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorLocations({\n fragments: textLoc.locations?.fragments ?? [],\n progression: audioLocator.locations?.progression,\n totalProgression: audioLocator.locations?.totalProgression,\n position: item.position + 1,\n otherLocations: textLoc.locations?.otherLocations,\n }),\n text: textLoc.text,\n });\n}\nfunction textLocatorToAudioLocator(items, textLocator) {\n log.debug("Mapping text locator to audio locator:", textLocator.href);\n log.debug("Available SyncNarrationItems:");\n for (const item of items) {\n log.debug(`- textHref: ${item.textHref}, textId: ${item.textId}, audioHref: ${item.audioHref}, audioStart: ${item.audioStart}, audioEnd: ${item.audioEnd}`);\n }\n const targetHref = textLocator.href;\n const targetHrefNormalized = normalizeHref(targetHref);\n const targetId = textLocator.locations?.fragments?.[0] ??\n textLocator.locations?.otherLocations?.get?.("cssSelector")?.replace(/^#/, "") ??\n "";\n const hrefMatches = items.filter((item) => normalizeHref(item.textHref) === targetHrefNormalized);\n let match;\n if (targetId) {\n match = hrefMatches.find((item) => item.textId === targetId);\n if (!match && hrefMatches.length > 0) {\n log.warn(`textLocatorToAudioLocator: no SyncNarrationItem matched textId "${targetId}" in ${targetHrefNormalized}; falling back to first item in resource.`);\n match = hrefMatches[0];\n }\n }\n else {\n match = hrefMatches[0];\n }\n if (!match || match.audioStart === null)\n return undefined;\n const tFragment = textLocator.locations?.fragments?.find((f) => f.startsWith("t="));\n let timeOffset = match.audioStart;\n if (tFragment) {\n const parsed = parseFloat(tFragment.slice(2));\n if (!isNaN(parsed))\n timeOffset = parsed;\n }\n else if (textLocator.locations?.progression != null &&\n match.audioEnd !== null) {\n timeOffset =\n match.audioStart +\n textLocator.locations.progression * (match.audioEnd - match.audioStart);\n }\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Locator({\n href: match.audioHref,\n type: "audio/mpeg",\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorLocations({\n fragments: [`t=${timeOffset}`],\n }),\n });\n}\nfunction findItemByAudioTime(items, audioHref, timeSecs) {\n const normHref = normalizeHref(audioHref);\n for (const item of items) {\n if (normalizeHref(item.audioHref) !== normHref)\n continue;\n const start = item.audioStart ?? 0;\n const end = item.audioEnd;\n if (timeSecs >= start && (end === null || timeSecs <= end)) {\n return item;\n }\n }\n return undefined;\n}\nfunction flattenToc(publication) {\n const toc = publication.manifest.toc?.items;\n if (!toc)\n return [];\n const out = [];\n const walk = (links) => {\n for (const link of links) {\n out.push(link);\n const children = link.children?.items;\n if (children && children.length > 0)\n walk(children);\n }\n };\n walk(toc);\n return out;\n}\nfunction enrichItemsWithToc(items, publication) {\n const toc = flattenToc(publication);\n if (toc.length === 0)\n return items;\n let lastMatch;\n return items.map((item) => {\n const exact = toc.find((link) => link.href === item.text);\n if (exact) {\n lastMatch = exact;\n return { ...item, tocTitle: exact.title, tocHref: exact.href };\n }\n if (lastMatch && normalizeHref(lastMatch.href) === normalizeHref(item.textHref)) {\n return { ...item, tocTitle: lastMatch.title, tocHref: lastMatch.href };\n }\n return item;\n });\n}\nfunction parseAudioField(audio) {\n const hashIdx = audio.indexOf("#");\n if (hashIdx === -1) {\n return { audioHref: audio, audioStart: null, audioEnd: null };\n }\n const audioHref = audio.slice(0, hashIdx);\n const fragment = audio.slice(hashIdx + 1);\n let audioStart = null;\n let audioEnd = null;\n const match = fragment.match(/^t=([^,]+)(?:,(.+))?$/);\n if (match) {\n const s = parseFloat(match[1]);\n audioStart = isNaN(s) ? null : s;\n const e = match[2] ? parseFloat(match[2]) : NaN;\n audioEnd = isNaN(e) ? null : e;\n }\n return { audioHref, audioStart, audioEnd };\n}\nfunction parseTextField(text) {\n const hashIdx = text.indexOf("#");\n if (hashIdx === -1) {\n return { textHref: text, textId: "" };\n }\n return {\n textHref: text.slice(0, hashIdx),\n textId: text.slice(hashIdx + 1),\n };\n}\nfunction normalizeHref(href) {\n return href.replace(/^\\//, "").split("?")[0].split("#")[0];\n}\nfunction isJsonObject(value) {\n return typeof value === "object" && value !== null && !Array.isArray(value);\n}\nfunction _narrationAlternate(link) {\n const alternates = link.alternates;\n if (!alternates)\n return null;\n const byType = alternates.findWithMediaType(NARRATION_MEDIA_TYPE);\n if (byType)\n return byType;\n return alternates.items.find((alt) => alt.href.endsWith(".json")) ?? null;\n}\nfunction _parseNarrationJson(json, position, readingOrderDuration) {\n const items = [];\n if (!isJsonObject(json) || !Array.isArray(json["narration"]))\n return items;\n for (const entry of json["narration"]) {\n if (!isJsonObject(entry))\n continue;\n const audio = entry["audio"];\n const text = entry["text"];\n if (typeof audio === "string" && typeof text === "string") {\n items.push(_parseEntry(audio, text, position, readingOrderDuration));\n }\n else if (Array.isArray(entry["narration"])) {\n items.push(..._parseNarrationJson(entry, position, readingOrderDuration));\n }\n }\n return items;\n}\nfunction _parseEntry(audio, text, position, readingOrderDuration) {\n const { audioHref, audioStart, audioEnd } = parseAudioField(audio);\n const { textHref, textId } = parseTextField(text);\n return {\n audio,\n text,\n position,\n audioHref,\n audioStart,\n audioEnd,\n textHref,\n textId,\n readingOrderDuration,\n };\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/Audio/syncNarration.ts?\n}')},"./web/_scripts/Epub/epubNavigator.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ enrichWithTotalProgression: () => (/* binding */ enrichWithTotalProgression),\n/* harmony export */ initializeEpubNavigatorAndPeripherals: () => (/* binding */ initializeEpubNavigatorAndPeripherals)\n/* harmony export */ });\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _peripherals__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../peripherals */ "./web/_scripts/peripherals.ts");\n/* harmony import */ var _epubPreferences__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./epubPreferences */ "./web/_scripts/Epub/epubPreferences.ts");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _helpers_tocHref__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../helpers/tocHref */ "./web/_scripts/helpers/tocHref.ts");\n\n\n\n\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_5__.createLogger)("EpubNav");\nasync function initializeEpubNavigatorAndPeripherals(container, publication, initialPosition = undefined, preferencesJsonString, setNav, setPositions) {\n log.info("Initializing EpubNavigator");\n let positions = await publication.positionsFromManifest();\n if (positions.length === 0) {\n log.warn("No positions from manifest, falling back to readingOrder");\n positions = publication.manifest.readingOrder.items.map((link, index) => {\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Locator({\n href: link.href,\n type: link.type ?? "text/html",\n title: link.title,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.LocatorLocations({\n position: index + 1,\n }),\n });\n });\n }\n let preferences = (0,_epubPreferences__WEBPACK_IMPORTED_MODULE_3__.initializeEpubPreferencesFromString)(preferencesJsonString);\n const TEXT_LOCATOR_DEBOUNCE_MS = 200;\n let textLocatorTimer;\n const emitTextLocatorDebounced = (locator) => {\n if (textLocatorTimer !== undefined)\n clearTimeout(textLocatorTimer);\n textLocatorTimer = setTimeout(() => {\n textLocatorTimer = undefined;\n window.updateTextLocator?.(JSON.stringify(locator.serialize()));\n }, TEXT_LOCATOR_DEBOUNCE_MS);\n };\n const totalPositions = positions.length;\n const flatToc = (0,_helpers_tocHref__WEBPACK_IMPORTED_MODULE_6__.flattenToc)(publication.manifest.toc?.items ?? []);\n log.debug(`TOC flattened: ${flatToc.length} entries, positions: ${positions.length}`);\n const configuration = {\n preferences,\n defaults: _epubPreferences__WEBPACK_IMPORTED_MODULE_3__.defaults,\n };\n const p = new _peripherals__WEBPACK_IMPORTED_MODULE_2__["default"]({\n moveTo: (direction) => {\n if (direction === "right") {\n nav.goRight(true, () => { });\n }\n else if (direction === "left") {\n nav.goLeft(true, () => { });\n }\n else if (direction === "up") {\n const iframes = document.querySelectorAll(".readium-navigator-iframe");\n iframes.forEach((iframe) => {\n if (iframe instanceof HTMLIFrameElement) {\n if (iframe.style.visibility !== "hidden") {\n iframe.contentWindow?.scrollBy(0, -100);\n }\n }\n });\n }\n else if (direction === "down") {\n const iframes = document.querySelectorAll(".readium-navigator-iframe");\n iframes.forEach((iframe) => {\n if (iframe instanceof HTMLIFrameElement) {\n if (iframe.style.visibility !== "hidden") {\n iframe.contentWindow?.scrollBy(0, 100);\n }\n }\n });\n }\n },\n menu: (_show) => {\n },\n goProgression: (_shiftKey) => {\n nav.goForward(true, () => { });\n },\n });\n const listeners = {\n scroll: function (_amount) { },\n frameLoaded: function (_wnd) {\n nav._cframes.forEach((frameManager) => {\n if (frameManager) {\n log.debug("Injecting helpers into FrameManager for:", frameManager.window.location.href);\n p.observe(frameManager.window);\n (0,_helpers__WEBPACK_IMPORTED_MODULE_4__.injectDecorationOverrides)(frameManager.window);\n const tocFragmentIds = flatToc\n .map((l) => {\n const hash = l.href.indexOf("#");\n return hash !== -1 ? l.href.slice(hash + 1) : "";\n })\n .filter((id) => id.length > 0);\n (0,_helpers__WEBPACK_IMPORTED_MODULE_4__.injectFlutterReadiumHelperScripts)(frameManager.window, tocFragmentIds);\n }\n });\n p.observe(window);\n },\n positionChanged: (_locator) => {\n emitTextLocatorDebounced((0,_helpers_tocHref__WEBPACK_IMPORTED_MODULE_6__.enrichLocatorWithTocHref)(enrichWithTotalProgression(_locator, totalPositions), flatToc));\n },\n tap: function (_e) {\n return false;\n },\n click: function (_e) {\n return false;\n },\n zoom: function (_scale) { },\n miscPointer: function (_amount) {\n },\n customEvent: function (_key, _data) { },\n handleLocator: function (locator) {\n const href = locator.href;\n if (href.startsWith("http://") ||\n href.startsWith("https://") ||\n href.startsWith("mailto:") ||\n href.startsWith("tel:")) {\n if (confirm(`Open "${href}" ?`))\n window.open(href, "_blank");\n }\n else {\n log.warn("Unhandled locator href:", href);\n }\n return false;\n },\n contentProtection: function (_type, _data) { },\n peripheral: function (_data) { },\n contextMenu: function (_data) { },\n textSelected: function (_selection) {\n const locatorJson = {\n ...nav.currentLocator.serialize(),\n text: { highlight: _selection.text },\n };\n window.onTextSelectedCallback?.(JSON.stringify({ locator: locatorJson, selectedText: _selection.text }));\n },\n };\n let resolvedInitialPosition = initialPosition;\n if (initialPosition && initialPosition.locations?.position == null) {\n const chapPos = positions.find((p) => p.href === initialPosition.href);\n if (chapPos) {\n resolvedInitialPosition = new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Locator({\n href: initialPosition.href,\n type: initialPosition.type,\n title: initialPosition.title ?? chapPos.title,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.LocatorLocations({\n position: chapPos.locations?.position,\n fragments: initialPosition.locations?.fragments,\n otherLocations: initialPosition.locations?.otherLocations,\n }),\n });\n log.debug(`Resolved position-less initial locator: ${initialPosition.href} → position ${chapPos.locations?.position}`);\n }\n else {\n log.warn(`Couldn\'t resolve position for initial locator: ${initialPosition.href}, falling back to href-only lookup (may be inaccurate)`);\n }\n }\n const nav = new _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.EpubNavigator(container, publication, listeners, positions, resolvedInitialPosition, configuration);\n try {\n await nav.load();\n log.info("EpubNavigator loaded");\n }\n catch (error) {\n log.error("Failed to load EpubNavigator:", error);\n throw error;\n }\n setNav(nav);\n setPositions?.(positions);\n p.observe(window);\n}\nfunction enrichWithTotalProgression(locator, totalPositions) {\n if (totalPositions <= 0)\n return locator;\n const position = locator.locations?.position;\n if (position === undefined || position <= 0)\n return locator;\n const progression = locator.locations?.progression ?? 0;\n const raw = (position - 1 + progression) / totalPositions;\n const totalProgression = Math.min(1, Math.max(0, raw));\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.Locator({\n href: locator.href,\n type: locator.type,\n title: locator.title,\n text: locator.text,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_1__.LocatorLocations({\n fragments: locator.locations?.fragments,\n progression: locator.locations?.progression,\n position: locator.locations?.position,\n totalProgression,\n otherLocations: locator.locations?.otherLocations,\n }),\n });\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/Epub/epubNavigator.ts?\n}')},"./web/_scripts/Epub/epubPreferences.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ defaults: () => (/* binding */ defaults),\n/* harmony export */ epubPreferencesFromJson: () => (/* binding */ epubPreferencesFromJson),\n/* harmony export */ initializeEpubPreferencesFromString: () => (/* binding */ initializeEpubPreferencesFromString),\n/* harmony export */ setEpubPreferencesFromString: () => (/* binding */ setEpubPreferencesFromString)\n/* harmony export */ });\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_1__.createLogger)("EpubPrefs");\nfunction epubPreferencesFromJson(rawPrefs) {\n const prefs = { ...rawPrefs };\n (0,_helpers__WEBPACK_IMPORTED_MODULE_0__.convertVerticalScroll)(prefs);\n const out = {};\n if (typeof prefs.backgroundColor === "string")\n out.backgroundColor = (0,_helpers__WEBPACK_IMPORTED_MODULE_0__.dartColorToCss)(prefs.backgroundColor);\n if (typeof prefs.fontFamily === "string")\n out.fontFamily = prefs.fontFamily;\n if (typeof prefs.fontWeight === "number")\n out.fontWeight = prefs.fontWeight;\n if (typeof prefs.hyphens === "boolean")\n out.hyphens = prefs.hyphens;\n if (typeof prefs.letterSpacing === "number")\n out.letterSpacing = prefs.letterSpacing;\n if (typeof prefs.ligatures === "boolean")\n out.ligatures = prefs.ligatures;\n if (typeof prefs.lineHeight === "number")\n out.lineHeight = prefs.lineHeight;\n if (typeof prefs.paragraphIndent === "number")\n out.paragraphIndent = prefs.paragraphIndent;\n if (typeof prefs.paragraphSpacing === "number")\n out.paragraphSpacing = prefs.paragraphSpacing;\n if (typeof prefs.scroll === "boolean")\n out.scroll = prefs.scroll;\n if (typeof prefs.textColor === "string")\n out.textColor = (0,_helpers__WEBPACK_IMPORTED_MODULE_0__.dartColorToCss)(prefs.textColor);\n if (typeof prefs.textNormalization === "boolean")\n out.textNormalization = prefs.textNormalization;\n if (typeof prefs.wordSpacing === "number")\n out.wordSpacing = prefs.wordSpacing;\n if (prefs.columnCount !== undefined)\n out.columnCount = mapColumnCount(prefs.columnCount);\n if (prefs.imageFilter !== undefined) {\n const { darkenFilter, invertFilter } = mapImageFilter(prefs.imageFilter);\n out.darkenFilter = darkenFilter;\n out.invertFilter = invertFilter;\n }\n if (typeof prefs.fontSize === "number")\n out.fontSize = prefs.fontSize / 100;\n if (typeof prefs.textAlign === "string")\n out.textAlign = (0,_helpers__WEBPACK_IMPORTED_MODULE_0__.textAlignFromJson)(prefs.textAlign);\n const gutter = prefs.pageGutter ?? prefs.pageMargins;\n if (typeof gutter === "number")\n out.pageGutter = gutter;\n return (0,_helpers__WEBPACK_IMPORTED_MODULE_0__.normalizeTypes)(out);\n}\nfunction initializeEpubPreferencesFromString(preferencesString) {\n const prefs = epubPreferencesFromJson(JSON.parse(preferencesString));\n log.debug("Parsed initial preferences", prefs);\n return prefs;\n}\nfunction setEpubPreferencesFromString(preferencesString, nav) {\n const preferences = epubPreferencesFromJson(JSON.parse(preferencesString));\n log.debug("Submitting preferences to navigator", preferences);\n nav.submitPreferences(preferences);\n}\nfunction mapFontSize(value) {\n if (typeof value === "number")\n return value / 100;\n return null;\n}\nfunction mapColumnCount(value) {\n switch (value) {\n case "one":\n return 1;\n case "two":\n return 2;\n case "auto":\n return null;\n default:\n return typeof value === "number" ? value : null;\n }\n}\nfunction mapImageFilter(value) {\n switch (value) {\n case "darken":\n return { darkenFilter: true, invertFilter: null };\n case "invert":\n return { darkenFilter: null, invertFilter: true };\n default:\n return { darkenFilter: null, invertFilter: null };\n }\n}\nconst defaults = {\n backgroundColor: null,\n blendFilter: true,\n columnCount: 2,\n fontFamily: "Arial",\n fontSize: 1,\n fontWeight: 400,\n hyphens: true,\n ligatures: true,\n lineHeight: 1.5,\n pageGutter: 10,\n scroll: false,\n selectionBackgroundColor: "#cccccc",\n selectionTextColor: "#000000",\n visitedColor: "#551a8b",\n wordSpacing: 0,\n};\n\n\n//# sourceURL=webpack:///./web/_scripts/Epub/epubPreferences.ts?\n}')},"./web/_scripts/ReadiumReader.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ __testing__: () => (/* binding */ __testing__)\n/* harmony export */ });\n/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./style.css */ "./web/_scripts/style.css");\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @readium/navigator-html-injectables */ "./node_modules/@readium/navigator-html-injectables/dist/index.js");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _enums__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./enums */ "./web/_scripts/enums.ts");\n/* harmony import */ var _extensions_ReadiumPublication__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./extensions/ReadiumPublication */ "./web/_scripts/extensions/ReadiumPublication.ts");\n/* harmony import */ var _Epub_epubNavigator__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./Epub/epubNavigator */ "./web/_scripts/Epub/epubNavigator.ts");\n/* harmony import */ var _Epub_epubPreferences__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./Epub/epubPreferences */ "./web/_scripts/Epub/epubPreferences.ts");\n/* harmony import */ var _WebPub_webpubNavigator__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./WebPub/webpubNavigator */ "./web/_scripts/WebPub/webpubNavigator.ts");\n/* harmony import */ var _Audio_audioNavigator__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./Audio/audioNavigator */ "./web/_scripts/Audio/audioNavigator.ts");\n/* harmony import */ var _Audio_syncNarration__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./Audio/syncNarration */ "./web/_scripts/Audio/syncNarration.ts");\n/* harmony import */ var _Audio_guidedNavigation__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./Audio/guidedNavigation */ "./web/_scripts/Audio/guidedNavigation.ts");\n/* harmony import */ var _Audio_mediaOverlayNavigator__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./Audio/mediaOverlayNavigator */ "./web/_scripts/Audio/mediaOverlayNavigator.ts");\n/* harmony import */ var _TTS_ttsNavigator__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./TTS/ttsNavigator */ "./web/_scripts/TTS/ttsNavigator.ts");\n/* harmony import */ var _TTS_ttsPreferences__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./TTS/ttsPreferences */ "./web/_scripts/TTS/ttsPreferences.ts");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_4__.createLogger)("Reader");\nfunction findLinkByHref(items, href) {\n if (!items || items.length === 0)\n return undefined;\n const exact = items.find((l) => l.href === href);\n if (exact)\n return exact;\n try {\n const hrefPath = new URL(href, "http://localhost").pathname;\n return items.find((l) => {\n try {\n return new URL(l.href, "http://localhost").pathname === hrefPath;\n }\n catch {\n return false;\n }\n });\n }\n catch {\n return undefined;\n }\n}\nclass _ReadiumReader {\n constructor() {\n log.info("ReadiumReader instance created");\n }\n setLogLevel(level) {\n const mapped = level >= 0 && level <= 4 ? level : _logger__WEBPACK_IMPORTED_MODULE_4__.LogLevel.info;\n (0,_logger__WEBPACK_IMPORTED_MODULE_4__.setLogLevel)(mapped);\n log.info("Log level set to", _logger__WEBPACK_IMPORTED_MODULE_4__.LogLevel[mapped]);\n }\n _publication;\n _nav;\n _audioNav;\n _ttsEngine;\n _positions = [];\n _hasSyncNarration = false;\n _hasGuidedNavigation = false;\n _syncItems = [];\n _disableSynchronization = false;\n _decorationsByGroup = new Map();\n _utteranceStyle = { style: "highlight", tint: "#ffffff00" };\n _rangeStyle = { style: "underline", tint: "#ff000000" };\n _lastMediaOverlayLocatorKey = null;\n _isComicBook = false;\n get isNavigatorReady() {\n return !!this._nav;\n }\n static _publications = new Map();\n async getPublication(publicationURL) {\n log.info("getPublication", publicationURL);\n try {\n const { manifest, fetcher } = await (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.fetchManifest)(publicationURL);\n this._publication = new _extensions_ReadiumPublication__WEBPACK_IMPORTED_MODULE_7__.ReadiumPublication({ manifest, fetcher });\n let pubId = this._publication.metadata.identifier ?? "unidentified";\n _ReadiumReader._publications.set(pubId, this._publication);\n log.info("Publication fetched:", pubId);\n return JSON.stringify(manifest.serialize());\n }\n catch (error) {\n log.error("Failed to get publication:", error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n window.onErrorCallback?.(JSON.stringify({ message: "Failed to get publication: " + errorMessage }));\n throw new Error("Error getting publication: " + error);\n }\n }\n goRight() {\n log.debug("goRight");\n this._nav?.goRight(true, () => { });\n }\n goLeft() {\n log.debug("goLeft");\n this._nav?.goLeft(true, () => { });\n }\n goForward() {\n log.debug("goForward");\n this._nav?.goForward(true, () => { });\n }\n goBackward() {\n log.debug("goBackward");\n this._nav?.goBackward(true, () => { });\n }\n async goTo(locatorJson) {\n log.info("goTo", locatorJson);\n const locator = _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(locatorJson));\n if (!locator) {\n log.error("goTo: failed to parse locator JSON");\n throw new Error("Failed to parse locator JSON");\n }\n log.info("goTo: routing decision", `tts=${!!this._ttsEngine}`, `audioNav=${!!this._audioNav}`, `syncItems=${this._syncItems.length}`, `hasSyncNarration=${this._hasSyncNarration}`);\n if (this._ttsEngine) {\n log.info("goTo: TTS — restarting narration at", locator.href, locator.locations?.fragments);\n await this._ttsEngine.play(locator);\n return;\n }\n if (this._audioNav && this._syncItems.length > 0) {\n const audioLocator = (0,_Audio_syncNarration__WEBPACK_IMPORTED_MODULE_12__.textLocatorToAudioLocator)(this._syncItems, locator);\n if (audioLocator) {\n const wasPlaying = this._audioNav.isPlaying;\n log.info("goTo: MediaOverlay — seeking audio to", audioLocator.href, audioLocator.locations?.fragments, `(wasPlaying=${wasPlaying})`);\n await this._seekAudioAndResume(audioLocator, wasPlaying);\n }\n else {\n log.warn("goTo: MediaOverlay — no SyncNarrationItem found for", locator.href, "; falling through to visual navigation");\n }\n const visualPub = this._nav?.publication;\n const visualLinks = [\n ...(visualPub?.readingOrder?.items ?? []),\n ...(visualPub?.resources?.items ?? []),\n ];\n const visualLink = findLinkByHref(visualLinks, locator.href);\n if (visualLink) {\n this._nav?.goLink(visualLink, true, (ok) => {\n if (!ok)\n log.warn("goTo: MediaOverlay — visual navigation failed for", locator.href);\n });\n }\n return;\n }\n if (this._audioNav) {\n const pub = this._publication;\n const allLinks = [\n ...(pub?.readingOrder?.items ?? []),\n ...(pub?.resources?.items ?? []),\n ];\n const link = findLinkByHref(allLinks, locator.href);\n if (!link) {\n log.error("goTo: audio link not found:", locator.href);\n throw new Error("Audio link not found " + locator.href);\n }\n const audioLocator = new _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator({\n href: link.href,\n type: link.type ?? "audio/mpeg",\n locations: locator.locations,\n });\n const wasPlaying = this._audioNav.isPlaying;\n await this._seekAudioAndResume(audioLocator, wasPlaying);\n return;\n }\n const pub = this._nav?.publication;\n const allLinks = [\n ...(pub?.readingOrder?.items ?? []),\n ...(pub?.resources?.items ?? []),\n ];\n const link = findLinkByHref(allLinks, locator.href);\n if (!link) {\n log.error("goTo: link not found:", locator.href);\n throw new Error("Link not found " + locator.href);\n }\n this._nav?.goLink(link, true, (ok) => {\n if (!ok) {\n log.error("goTo: failed to navigate to link:", locator.href);\n throw new Error("Failed to navigate to link " + locator.href);\n }\n });\n }\n async openPublication(publicationURL, pubId, initialPositionJson, preferencesJson) {\n log.info("openPublication", { pubId, hasInitialPosition: !!initialPositionJson });\n window.updateReaderStatus?.(_enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.loading);\n let initialPosition;\n if (initialPositionJson) {\n initialPosition = _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(initialPositionJson));\n }\n let preferencesJsonString = !preferencesJson || preferencesJson === "null" ? "{}" : preferencesJson;\n this._hasSyncNarration = false;\n this._hasGuidedNavigation = false;\n this._syncItems = [];\n this._positions = [];\n try {\n this._publication = _ReadiumReader._publications.get(pubId);\n if (!this._publication) {\n const { manifest, fetcher } = await (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.fetchManifest)(publicationURL);\n this._publication = new _extensions_ReadiumPublication__WEBPACK_IMPORTED_MODULE_7__.ReadiumPublication({ manifest, fetcher });\n _ReadiumReader._publications.set(pubId, this._publication);\n }\n if (this._publication.conformsToAudiobook) {\n log.info("Publication conforms to Audiobook profile");\n await (0,_Audio_audioNavigator__WEBPACK_IMPORTED_MODULE_11__.initializeAudioNavigator)(this._publication, initialPosition, preferencesJsonString, (nav) => {\n this._audioNav = nav;\n window.updateReaderStatus?.(_enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.ready);\n });\n }\n else {\n const container = document.body.querySelector("#container");\n if (!container) {\n log.error("Container element #container not found in DOM");\n window.updateReaderStatus?.(_enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.error);\n throw new Error("Container element not found");\n }\n if (this._publication.conformsToEpub) {\n log.info("Publication conforms to EPUB profile");\n this._hasSyncNarration = (0,_Audio_syncNarration__WEBPACK_IMPORTED_MODULE_12__.detectSyncNarration)(this._publication);\n if (this._hasSyncNarration)\n log.info("Sync Narration detected");\n this._hasGuidedNavigation = (0,_Audio_guidedNavigation__WEBPACK_IMPORTED_MODULE_13__.detectGuidedNavigation)(this._publication);\n if (this._hasGuidedNavigation)\n log.info("Guided Navigation detected");\n await (0,_Epub_epubNavigator__WEBPACK_IMPORTED_MODULE_8__.initializeEpubNavigatorAndPeripherals)(container, this._publication, initialPosition, preferencesJsonString, (nav) => {\n this._nav = nav;\n window.updateReaderStatus?.(_enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.ready);\n }, (positions) => { this._positions = positions; });\n }\n else {\n log.info("Publication conforms to WebPub profile");\n await (0,_WebPub_webpubNavigator__WEBPACK_IMPORTED_MODULE_10__.initializeWebPubNavigatorAndPeripherals)(container, this._publication, initialPosition, preferencesJsonString, (nav) => {\n this._nav = nav;\n window.updateReaderStatus?.(_enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.ready);\n });\n }\n }\n }\n catch (error) {\n log.error("Failed to open publication:", error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n window.onErrorCallback?.(JSON.stringify({ message: "Failed to open publication: " + errorMessage }));\n this.closePublication(error);\n throw new Error("Error opening publication: " + error);\n }\n }\n setEPUBPreferences(newPreferencesString) {\n if (!this._nav) {\n log.error("setEPUBPreferences: navigator is not initialized");\n throw new Error("Navigator is not initialized");\n }\n log.debug("setEPUBPreferences");\n try {\n const parsed = JSON.parse(newPreferencesString);\n this._disableSynchronization = parsed.disableSynchronization === true;\n this._ttsEngine?.setSyncEnabled(!this._disableSynchronization);\n }\n catch (_) {\n }\n (0,_Epub_epubPreferences__WEBPACK_IMPORTED_MODULE_9__.setEpubPreferencesFromString)(newPreferencesString, this._nav);\n }\n applyDecorations(group, decorationsJson) {\n if (!this._nav) {\n console.warn("applyDecorations: navigator not ready, skipping");\n return;\n }\n const underlineGroup = group + _helpers__WEBPACK_IMPORTED_MODULE_5__.UNDERLINE_GROUP_SUFFIX;\n const spotlightGroup = group + _helpers__WEBPACK_IMPORTED_MODULE_5__.SPOTLIGHT_GROUP_SUFFIX;\n for (const grp of [group, underlineGroup, spotlightGroup]) {\n (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.sendDecorate)(this._nav, grp, "clear", undefined);\n this._decorationsByGroup.set(grp, new Set());\n }\n const decorationsRaw = JSON.parse(decorationsJson);\n for (const item of decorationsRaw) {\n item.style.tint = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.dartColorToCss)(item.style.tint);\n }\n const iframes = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.navIframeWindows)(this._nav);\n const firstTintByGroup = new Map();\n for (const raw of decorationsRaw) {\n const grp = this._subgroupFor(group, raw.style.style);\n if (!firstTintByGroup.has(grp)) {\n firstTintByGroup.set(grp, { isUnderline: raw.style.style === "underline", tint: raw.style.tint });\n }\n }\n for (const [grp, meta] of firstTintByGroup) {\n (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.registerPendingDecorationGroup)(iframes, grp, meta.isUnderline, meta.tint);\n }\n for (const raw of decorationsRaw) {\n const targetGroup = this._subgroupFor(group, raw.style.style);\n const locator = _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(raw.locator);\n const decoration = {\n id: raw.id,\n locator,\n style: {\n tint: raw.style.tint,\n layout: _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_3__.Layout.Bounds,\n width: _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_3__.Width.Wrap,\n },\n };\n (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.sendDecorate)(this._nav, targetGroup, "add", decoration);\n this._decorationsByGroup.get(targetGroup).add(raw.id);\n }\n const hasSpotlight = (this._decorationsByGroup.get(spotlightGroup)?.size ?? 0) > 0;\n (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.setSpotlightGroupOnIframes)(iframes, spotlightGroup, hasSpotlight);\n }\n _subgroupFor(group, style) {\n switch (style) {\n case "underline": return group + _helpers__WEBPACK_IMPORTED_MODULE_5__.UNDERLINE_GROUP_SUFFIX;\n case "spotlight": return group + _helpers__WEBPACK_IMPORTED_MODULE_5__.SPOTLIGHT_GROUP_SUFFIX;\n default: return group;\n }\n }\n setDecorationStyle(utteranceStyleJson, rangeStyleJson) {\n this._utteranceStyle = utteranceStyleJson ? JSON.parse(utteranceStyleJson) : null;\n this._rangeStyle = rangeStyleJson ? JSON.parse(rangeStyleJson) : null;\n this._ttsEngine?.updateDecorationStyles(this._utteranceStyle, this._rangeStyle);\n }\n closePublication(error) {\n log.info("closePublication", error ? `(error: ${error})` : "");\n (0,_Audio_audioNavigator__WEBPACK_IMPORTED_MODULE_11__.setAudioEmissionsEnabled)(false);\n this._ttsEngine?.destroy();\n this._ttsEngine = undefined;\n this._audioNav?.stop();\n this._audioNav?.destroy();\n this._audioNav = undefined;\n this._hasSyncNarration = false;\n this._hasGuidedNavigation = false;\n this._syncItems = [];\n this._positions = [];\n this._publication = undefined;\n this._lastMediaOverlayLocatorKey = null;\n this._isComicBook = false;\n this._decorationsByGroup.clear();\n (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.clearSpotlightState)();\n const nav = this._nav;\n this._nav = undefined;\n const container = document.getElementById("container");\n if (container) {\n container.innerHTML = "";\n }\n window.updateReaderStatus?.(error ? _enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.error : _enums__WEBPACK_IMPORTED_MODULE_6__.ReadiumReaderStatus.closed);\n const navDestroy = nav?.destroy();\n if (navDestroy) {\n navDestroy\n .catch((err) => {\n log.error("Error destroying navigator:", err);\n })\n .finally(() => {\n const c = document.getElementById("container");\n if (c)\n c.innerHTML = "";\n });\n }\n }\n _seekAudioAndResume(audioLocator, resumePlaying) {\n const nav = this._audioNav;\n if (!nav)\n return Promise.resolve();\n return (0,_Audio_audioNavigator__WEBPACK_IMPORTED_MODULE_11__.seekAudioAndResume)(nav, audioLocator, resumePlaying);\n }\n play(locatorJson) {\n log.debug("play", locatorJson ? "(with locator)" : "");\n if (this._ttsEngine) {\n const locator = locatorJson\n ? _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(locatorJson)) ?? undefined\n : undefined;\n this._ttsEngine.play(locator);\n return;\n }\n if (!this._audioNav)\n return;\n if (locatorJson) {\n let locator = _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(locatorJson));\n if (locator) {\n if (this._syncItems.length > 0) {\n locator = (0,_Audio_syncNarration__WEBPACK_IMPORTED_MODULE_12__.textLocatorToAudioLocator)(this._syncItems, locator) ?? locator;\n }\n this._seekAudioAndResume(locator, true);\n return;\n }\n }\n this._audioNav.play();\n }\n pause() {\n log.debug("pause");\n if (this._ttsEngine) {\n this._ttsEngine.pause();\n return;\n }\n this._audioNav?.pause();\n }\n resume() {\n log.debug("resume");\n if (this._ttsEngine) {\n this._ttsEngine.resume();\n return;\n }\n this._audioNav?.play();\n }\n stop() {\n log.debug("stop");\n if (this._ttsEngine) {\n this._ttsEngine.stop();\n return;\n }\n this._audioNav?.stop();\n if ((this._hasSyncNarration || this._hasGuidedNavigation) && this._nav) {\n this._lastMediaOverlayLocatorKey = null;\n this.applyDecorations("media_overlay_utterance", "[]");\n }\n }\n next() {\n log.debug("next");\n if (this._ttsEngine) {\n this._ttsEngine.next();\n return;\n }\n this._audioNav?.goForward(false, () => { });\n }\n previous() {\n log.debug("previous");\n if (this._ttsEngine) {\n this._ttsEngine.previous();\n return;\n }\n this._audioNav?.goBackward(false, () => { });\n }\n seekBy(seconds) {\n log.debug("seekBy", seconds);\n this._audioNav?.jump(seconds);\n }\n goToProgression(progression) {\n log.debug("goToProgression", progression);\n if (progression < 0 || progression > 1) {\n log.warn("goToProgression: progression out of range [0, 1]:", progression);\n return false;\n }\n if (this._audioNav) {\n const duration = this._audioNav.duration;\n if (duration <= 0) {\n log.warn("goToProgression: audio duration not available");\n return false;\n }\n this._audioNav.seek(progression * duration);\n return true;\n }\n if (this._nav && this._positions.length > 0) {\n const index = Math.min(Math.floor(progression * this._positions.length), this._positions.length - 1);\n const locator = this._positions[index];\n this._nav.go(locator, true, (ok) => {\n if (!ok) {\n log.warn("goToProgression: navigation failed for position", index);\n }\n });\n return true;\n }\n log.warn("goToProgression: no active navigator or positions available");\n return false;\n }\n async ttsEnable(prefsJson, fromLocatorJson) {\n log.info("ttsEnable");\n if (!this._nav || !this._publication) {\n log.warn("ttsEnable: no visual navigator active");\n return;\n }\n this._ttsEngine?.destroy();\n const prefs = (0,_TTS_ttsPreferences__WEBPACK_IMPORTED_MODULE_16__.ttsPreferencesFromJson)(JSON.parse(prefsJson));\n this._ttsEngine = new _TTS_ttsNavigator__WEBPACK_IMPORTED_MODULE_15__.WebTTSEngine(this._nav, this._publication, prefs, !this._disableSynchronization, this._utteranceStyle, this._rangeStyle, (group, decorationsJson) => this.applyDecorations(group, decorationsJson));\n const fromLocator = fromLocatorJson\n ? _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(fromLocatorJson)) ?? undefined\n : undefined;\n await this._ttsEngine.play(fromLocator);\n }\n async ttsGetAvailableVoices() {\n return _TTS_ttsNavigator__WEBPACK_IMPORTED_MODULE_15__.WebTTSEngine.getAvailableVoices();\n }\n ttsSetVoice(identifier, lang) {\n this._ttsEngine?.setVoice(identifier, lang);\n }\n ttsSetPreferences(prefsJson) {\n if (!this._ttsEngine)\n return;\n const prefs = (0,_TTS_ttsPreferences__WEBPACK_IMPORTED_MODULE_16__.ttsPreferencesFromJson)(JSON.parse(prefsJson));\n this._ttsEngine.applyPreferences(prefs);\n }\n _callGotoComicFrame(wnd, fragmentId, durationMs, retriesLeft = 20) {\n const cw = wnd;\n if (cw.comicBookPage) {\n log.debug(`[comic] gotoComicFrame("${fragmentId}", ${durationMs}ms)`);\n cw.gotoComicFrame?.(fragmentId, durationMs);\n return;\n }\n if (retriesLeft <= 0) {\n log.warn(`[comic] comicBookPage never became available; giving up for fragment "${fragmentId}"`);\n return;\n }\n log.debug(`[comic] comicBookPage not ready yet, retrying (${retriesLeft} left)…`);\n wnd.requestAnimationFrame(() => this._callGotoComicFrame(wnd, fragmentId, durationMs, retriesLeft - 1));\n }\n _syncVisualToMediaOverlayLocator(textLocator, sourceLabel, durationMs) {\n const nav = this._nav;\n if (!nav)\n return;\n const key = textLocator.href + (textLocator.locations?.fragments?.[0] ?? "");\n if (key === this._lastMediaOverlayLocatorKey)\n return;\n this._lastMediaOverlayLocatorKey = key;\n const fragmentId = textLocator.locations?.fragments?.[0] ?? "";\n log.debug(`${sourceLabel}: sync locator href="${textLocator.href}" fragment="${fragmentId}" durationMs=${durationMs ?? "undefined"}`);\n if (!this._isComicBook) {\n const iframes = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.navIframeWindows)(nav);\n for (const wnd of iframes) {\n const isComic = wnd.isNotaComicBook;\n if (typeof isComic === "function" && isComic()) {\n log.info(`${sourceLabel}: comic-book publication detected; skipping nav.go() for all cues`);\n this._isComicBook = true;\n break;\n }\n }\n }\n if (this._isComicBook) {\n const iframes = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.navIframeWindows)(nav);\n const targetWnd = iframes.find((w) => {\n try {\n return (w.location?.href?.includes(textLocator.href) ||\n w.document?.URL?.includes(textLocator.href));\n }\n catch {\n return false;\n }\n });\n const frameDuration = durationMs ?? 3000;\n const doGotoFrame = (wnd) => this._callGotoComicFrame(wnd, fragmentId, frameDuration);\n if (!targetWnd) {\n log.debug(`${sourceLabel}: [comic] cross-resource nav to "${textLocator.href}", calling nav.go() then gotoComicFrame`);\n nav.go(textLocator, false, (ok) => {\n if (!ok) {\n log.warn(`${sourceLabel}: [comic] nav.go() failed for ${textLocator.href}`);\n return;\n }\n const newIframes = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.navIframeWindows)(nav);\n const newWnd = newIframes.find((w) => {\n try {\n return (w.location?.href?.includes(textLocator.href) ||\n w.document?.URL?.includes(textLocator.href));\n }\n catch {\n return false;\n }\n }) ?? newIframes[0];\n if (newWnd)\n doGotoFrame(newWnd);\n else\n log.warn(`${sourceLabel}: [comic] no iframe found after nav.go() for "${textLocator.href}"`);\n });\n }\n else {\n log.debug(`${sourceLabel}: [comic] same-resource frame, calling gotoComicFrame directly`);\n doGotoFrame(targetWnd);\n }\n return;\n }\n const applyUtteranceDecoration = () => {\n if (!this._utteranceStyle || !this._nav)\n return;\n try {\n const decoration = [\n {\n id: textLocator.href,\n locator: textLocator.serialize(),\n style: this._utteranceStyle,\n },\n ];\n this.applyDecorations("media_overlay_utterance", JSON.stringify(decoration));\n }\n catch (e) {\n log.warn(`${sourceLabel}: failed to apply decoration:`, e);\n }\n };\n if (this._disableSynchronization) {\n applyUtteranceDecoration();\n return;\n }\n nav.go(textLocator, false, (ok) => {\n if (!ok) {\n log.warn(`${sourceLabel}: visual navigation failed for ${textLocator.href}`);\n }\n applyUtteranceDecoration();\n });\n }\n async audioEnable(prefsJson, fromLocatorJson) {\n log.info("audioEnable");\n const resolvedFromLocator = fromLocatorJson\n ? _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator.deserialize(JSON.parse(fromLocatorJson)) ?? undefined\n : this._nav?.currentLocator;\n if (this._audioNav) {\n if (resolvedFromLocator) {\n let locator = resolvedFromLocator;\n if (this._syncItems.length > 0) {\n locator = (0,_Audio_syncNarration__WEBPACK_IMPORTED_MODULE_12__.textLocatorToAudioLocator)(this._syncItems, locator) ?? locator;\n }\n this._seekAudioAndResume(locator, true);\n return;\n }\n this._audioNav.play();\n return;\n }\n if (this._hasGuidedNavigation && this._publication) {\n const fromLocator = resolvedFromLocator;\n this._lastMediaOverlayLocatorKey = null;\n await (0,_Audio_mediaOverlayNavigator__WEBPACK_IMPORTED_MODULE_14__.initializeGuidedNavigationNavigator)(this._publication, fromLocator, prefsJson, (nav, items) => { this._audioNav = nav; this._syncItems = items; }, (textLocator, durationMs) => this._syncVisualToMediaOverlayLocator(textLocator, "GuidedNavigation", durationMs));\n this._audioNav?.play();\n return;\n }\n if (this._hasSyncNarration && this._publication) {\n const fromLocator = resolvedFromLocator;\n this._lastMediaOverlayLocatorKey = null;\n await (0,_Audio_mediaOverlayNavigator__WEBPACK_IMPORTED_MODULE_14__.initializeMediaOverlayNavigator)(this._publication, fromLocator, prefsJson, (nav, items) => { this._audioNav = nav; this._syncItems = items; }, (textLocator, durationMs) => this._syncVisualToMediaOverlayLocator(textLocator, "MediaOverlay", durationMs));\n this._audioNav?.play();\n return;\n }\n log.warn("audioEnable: no audiobook or Media Overlay content detected");\n }\n setAudioPreferences(preferencesJson) {\n log.debug("setAudioPreferences");\n if (!this._audioNav)\n return;\n const prefs = JSON.parse(preferencesJson);\n this._audioNav.submitPreferences(new _readium_navigator__WEBPACK_IMPORTED_MODULE_1__.AudioPreferences({\n volume: prefs.volume ?? null,\n playbackRate: prefs.speed ?? null,\n skipBackwardInterval: prefs.seekInterval ?? null,\n skipForwardInterval: prefs.seekInterval ?? null,\n pollInterval: prefs.updateIntervalSecs != null\n ? prefs.updateIntervalSecs * 1000\n : null,\n }));\n }\n}\nglobalThis.ReadiumReader = _ReadiumReader;\nconst __testing__ = { ReadiumReader: _ReadiumReader };\n\n\n//# sourceURL=webpack:///./web/_scripts/ReadiumReader.ts?\n}')},"./web/_scripts/TTS/ttsNavigator.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ WebTTSEngine: () => (/* binding */ WebTTSEngine)\n/* harmony export */ });\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _ttsPreferences__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ttsPreferences */ "./web/_scripts/TTS/ttsPreferences.ts");\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_1__.createLogger)("TTS");\nconst BOUNDARY_THROTTLE_MS = 100;\nconst WEDGE_WATCHDOG_MS = 1500;\nfunction normalizeWhitespace(s) {\n if (!s)\n return undefined;\n const trimmed = s.replace(/\\s+/g, " ").trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\nfunction normalizeLocatorJson(locator) {\n const clone = JSON.parse(JSON.stringify(locator.serialize()));\n if (clone?.text) {\n clone.text = {\n before: normalizeWhitespace(clone.text.before),\n highlight: normalizeWhitespace(clone.text.highlight),\n after: normalizeWhitespace(clone.text.after),\n };\n }\n return clone;\n}\nfunction buildTTSStatePayload(state, locator) {\n return JSON.stringify({\n state,\n currentOffset: null,\n currentDuration: null,\n currentLocator: locator ? normalizeLocatorJson(locator) : null,\n });\n}\nfunction emitState(state, locator) {\n window.updateTimebasedPlayerState?.(buildTTSStatePayload(state, locator));\n}\nfunction emitLocator(locator) {\n window.updateTextLocator?.(JSON.stringify(normalizeLocatorJson(locator)));\n}\nfunction flattenToc(items) {\n const out = [];\n for (const link of items) {\n out.push(link);\n const children = link.children?.items;\n if (children && children.length > 0) {\n out.push(...flattenToc(children));\n }\n }\n return out;\n}\nfunction enrichWithTocHref(locator, flatToc) {\n if (flatToc.length === 0)\n return locator;\n const tocHref = _findCurrentTocHref(locator.href, flatToc);\n if (!tocHref)\n return locator;\n const existing = locator.locations?.otherLocations ?? new Map();\n if (existing.get("tocHref") === tocHref)\n return locator;\n const merged = new Map(existing);\n merged.set("tocHref", tocHref);\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Locator({\n href: locator.href,\n type: locator.type,\n title: locator.title,\n text: locator.text,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorLocations({\n fragments: locator.locations?.fragments,\n progression: locator.locations?.progression,\n position: locator.locations?.position,\n totalProgression: locator.locations?.totalProgression,\n otherLocations: merged,\n }),\n });\n}\nfunction _findCurrentTocHref(resourceHref, flatToc) {\n const targetPath = _stripFragment(resourceHref);\n const match = flatToc.find((l) => _stripFragment(l.href) === targetPath);\n return match?.href;\n}\nfunction _stripFragment(href) {\n const i = href.indexOf("#");\n return i === -1 ? href : href.substring(0, i);\n}\nclass WebTTSEngine {\n _nav;\n _publication;\n _prefs;\n _syncEnabled;\n _iterator = null;\n _currentElement = null;\n _lastBoundaryEmitTime = 0;\n _destroyed = false;\n _selectedVoice = null;\n _langVoiceMap = new Map();\n _flatToc;\n _utteranceStyle;\n _rangeStyle;\n _onApplyDecorations;\n constructor(nav, publication, prefs, syncEnabled = true, utteranceStyle = null, rangeStyle = null, onApplyDecorations = null) {\n this._nav = nav;\n this._publication = publication;\n this._prefs = prefs;\n this._syncEnabled = syncEnabled;\n this._utteranceStyle = utteranceStyle;\n this._rangeStyle = rangeStyle;\n this._onApplyDecorations = onApplyDecorations;\n this._flatToc = flattenToc(publication.manifest.toc?.items ?? []);\n try {\n speechSynthesis.cancel();\n }\n catch {\n }\n }\n setSyncEnabled(enabled) {\n this._syncEnabled = enabled;\n }\n updateDecorationStyles(utteranceStyle, rangeStyle) {\n this._utteranceStyle = utteranceStyle;\n this._rangeStyle = rangeStyle;\n if (this._currentElement) {\n this._applyDecoration("tts_utterance", this._currentElement.locator, this._utteranceStyle);\n }\n }\n async play(fromLocator) {\n if (this._destroyed)\n return;\n log.info("play", fromLocator ? "(from locator)" : "", {\n speaking: speechSynthesis.speaking,\n pending: speechSynthesis.pending,\n paused: speechSynthesis.paused,\n voices: speechSynthesis.getVoices().length,\n });\n this._clearDecorations();\n log.debug("Priming speechSynthesis engine");\n speechSynthesis.speak(new SpeechSynthesisUtterance(""));\n const wasActive = speechSynthesis.speaking || speechSynthesis.pending;\n if (wasActive) {\n speechSynthesis.cancel();\n }\n this._iterator = new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.PublicationContentIterator(this._publication, fromLocator, [\n (resource, locator) => new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.HTMLResourceContentIterator(resource, locator),\n ]);\n if (wasActive) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n if (this._destroyed)\n return;\n }\n log.debug("Initialized - Speaking first element");\n await this._speakNext();\n }\n pause() {\n if (this._destroyed)\n return;\n log.debug("pause");\n speechSynthesis.pause();\n emitState("paused", this._currentElement?.locator ?? null);\n }\n resume() {\n if (this._destroyed)\n return;\n log.debug("resume");\n speechSynthesis.resume();\n emitState("playing", this._currentElement?.locator ?? null);\n }\n stop() {\n if (this._destroyed)\n return;\n log.info("stop");\n speechSynthesis.cancel();\n this._iterator = null;\n this._currentElement = null;\n this._clearDecorations();\n emitState("none", null);\n }\n async next() {\n if (this._destroyed || !this._iterator)\n return;\n speechSynthesis.cancel();\n await this._speakNext();\n }\n async previous() {\n if (this._destroyed || !this._iterator)\n return;\n speechSynthesis.cancel();\n await this._speakPrevious();\n }\n applyPreferences(prefs) {\n this._prefs = prefs;\n }\n setVoice(voiceURI, lang) {\n const voices = speechSynthesis.getVoices();\n const matched = voices.find((v) => v.voiceURI === voiceURI) ?? null;\n if (!matched && !lang) {\n log.warn("Voice not found:", voiceURI);\n }\n else {\n log.debug("Voice set:", voiceURI, lang ? `(lang: ${lang})` : "");\n }\n if (lang) {\n this._langVoiceMap.set(lang, voiceURI);\n }\n else {\n this._selectedVoice = matched;\n }\n }\n destroy() {\n log.info("destroy");\n this._destroyed = true;\n speechSynthesis.cancel();\n this._iterator = null;\n this._currentElement = null;\n this._clearDecorations();\n }\n static async getAvailableVoices() {\n return (0,_ttsPreferences__WEBPACK_IMPORTED_MODULE_2__.serializeVoices)();\n }\n async _speakNext() {\n if (!this._iterator || this._destroyed)\n return;\n log.debug("_speakNext: awaiting hasNext");\n const hasNext = await this._iterator.hasNext();\n log.debug("_speakNext: hasNext =", hasNext);\n if (!hasNext) {\n log.info("TTS reached end of publication");\n emitState("ended", this._currentElement?.locator ?? null);\n return;\n }\n const element = this._iterator.next();\n log.debug("_speakNext: next element", {\n kind: element.constructor.name,\n isText: element instanceof _readium_shared__WEBPACK_IMPORTED_MODULE_0__.TextElement,\n });\n if (!(element instanceof _readium_shared__WEBPACK_IMPORTED_MODULE_0__.TextElement)) {\n await this._speakNext();\n return;\n }\n this._currentElement = element;\n this._speakElement(element);\n }\n async _speakPrevious() {\n if (!this._iterator || this._destroyed)\n return;\n const hasPrev = await this._iterator.hasPrevious();\n if (!hasPrev) {\n if (this._currentElement) {\n this._speakElement(this._currentElement);\n }\n return;\n }\n const element = this._iterator.previous();\n if (!(element instanceof _readium_shared__WEBPACK_IMPORTED_MODULE_0__.TextElement)) {\n await this._speakPrevious();\n return;\n }\n this._currentElement = element;\n this._speakElement(element);\n }\n _speakElement(element) {\n if (this._destroyed)\n return;\n const text = element.text;\n log.debug("_speakElement", {\n textLen: text?.length ?? 0,\n textPreview: text?.slice(0, 60),\n });\n if (!text || text.trim().length === 0) {\n log.debug("_speakElement: empty text, skipping");\n this._speakNext();\n return;\n }\n const utterance = new SpeechSynthesisUtterance(text);\n utterance.rate = this._prefs.rate;\n utterance.pitch = this._prefs.pitch;\n const lang = this._resolveVoiceLang(element);\n const voice = lang\n ? (speechSynthesis.getVoices().find((v) => v.voiceURI === this._langVoiceMap.get(lang)) ?? this._selectedVoice ?? this._prefs.voice)\n : (this._selectedVoice ?? this._prefs.voice);\n if (voice) {\n utterance.voice = voice;\n }\n else if (this._prefs.lang) {\n utterance.lang = this._prefs.lang;\n }\n log.debug("_speakElement: utterance config", {\n voice: voice?.name ?? "(default)",\n lang: utterance.lang || "(none)",\n rate: utterance.rate,\n pitch: utterance.pitch,\n elementLang: lang ?? "(none)",\n });\n let started = false;\n let recovered = false;\n let watchdog = null;\n const clearWatchdog = () => {\n if (watchdog !== null) {\n clearTimeout(watchdog);\n watchdog = null;\n }\n };\n const armWatchdog = () => {\n watchdog = setTimeout(() => {\n watchdog = null;\n if (started || this._destroyed)\n return;\n if (!speechSynthesis.speaking)\n return;\n if (recovered) {\n log.warn("speechSynthesis wedge persisted after recovery — aborting utterance");\n emitState("failure", element.locator);\n return;\n }\n recovered = true;\n log.warn("speechSynthesis wedge detected — attempting recovery");\n try {\n speechSynthesis.cancel();\n }\n catch { }\n setTimeout(() => {\n if (this._destroyed || started)\n return;\n try {\n speechSynthesis.speak(new SpeechSynthesisUtterance(""));\n speechSynthesis.speak(utterance);\n armWatchdog();\n }\n catch (e) {\n log.warn("speechSynthesis recovery failed:", e);\n emitState("failure", element.locator);\n }\n }, 200);\n }, WEDGE_WATCHDOG_MS);\n };\n utterance.onstart = () => {\n log.debug("utterance.onstart");\n started = true;\n clearWatchdog();\n if (this._destroyed)\n return;\n const enrichedLocator = enrichWithTocHref(element.locator, this._flatToc);\n emitState("playing", enrichedLocator);\n emitLocator(enrichedLocator);\n this._applyDecoration("tts_utterance", element.locator, this._utteranceStyle);\n this._onApplyDecorations?.("tts_range", "[]");\n if (this._syncEnabled) {\n try {\n this._nav.go(element.locator, false, () => { });\n }\n catch (navError) {\n log.warn("TTS navigator sync failed:", navError);\n }\n }\n };\n utterance.onend = () => {\n log.debug("utterance.onend");\n clearWatchdog();\n if (this._destroyed)\n return;\n this._speakNext();\n };\n utterance.onerror = (ev) => {\n if (!recovered)\n clearWatchdog();\n if (this._destroyed)\n return;\n if (ev.error === "interrupted" || ev.error === "canceled") {\n log.debug("utterance.onerror (expected):", ev.error);\n return;\n }\n log.warn("utterance.onerror", ev.error);\n emitState("failure", element.locator);\n };\n utterance.onboundary = (ev) => {\n if (this._destroyed)\n return;\n if (ev.name !== "word" && ev.name !== "sentence")\n return;\n const now = Date.now();\n if (now - this._lastBoundaryEmitTime < BOUNDARY_THROTTLE_MS)\n return;\n this._lastBoundaryEmitTime = now;\n const segmentLocator = this._locatorForCharIndex(element, ev.charIndex, ev.charLength ?? 0);\n if (segmentLocator) {\n emitState("playing", enrichWithTocHref(segmentLocator, this._flatToc));\n if (!this._locatorHighlightsSameText(segmentLocator, element.locator)) {\n this._applyDecoration("tts_range", segmentLocator, this._rangeStyle);\n }\n }\n };\n log.debug("_speakElement: calling speechSynthesis.speak");\n speechSynthesis.speak(utterance);\n log.debug("_speakElement: after speak()", {\n speaking: speechSynthesis.speaking,\n pending: speechSynthesis.pending,\n paused: speechSynthesis.paused,\n });\n armWatchdog();\n }\n _locatorForCharIndex(element, charIndex, charLength) {\n if (!element.segments.length)\n return element.locator;\n let accumulated = 0;\n for (const seg of element.segments) {\n const start = accumulated;\n const end = accumulated + seg.text.length;\n if (charIndex >= start && charIndex < end) {\n return seg.locator;\n }\n accumulated = end + 1;\n }\n const last = element.segments[element.segments.length - 1];\n return last?.locator ?? element.locator;\n }\n _locatorHighlightsSameText(a, b) {\n return normalizeWhitespace(a.text?.highlight) === normalizeWhitespace(b.text?.highlight);\n }\n _resolveVoiceLang(element) {\n const elementLang = element.language;\n if (elementLang)\n return elementLang;\n return this._publication.metadata.languages?.[0];\n }\n _clearDecorations() {\n if (!this._onApplyDecorations)\n return;\n this._onApplyDecorations("tts_utterance", "[]");\n this._onApplyDecorations("tts_range", "[]");\n }\n _applyDecoration(group, locator, style) {\n if (!this._onApplyDecorations || !locator || !style)\n return;\n try {\n const decoration = [{ id: locator.href, locator: locator.serialize(), style }];\n this._onApplyDecorations(group, JSON.stringify(decoration));\n }\n catch (e) {\n log.warn("TTS: failed to apply decoration:", e);\n }\n }\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/TTS/ttsNavigator.ts?\n}')},"./web/_scripts/TTS/ttsPreferences.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ getAvailableVoicesAsync: () => (/* binding */ getAvailableVoicesAsync),\n/* harmony export */ serializeVoices: () => (/* binding */ serializeVoices),\n/* harmony export */ ttsPreferencesFromJson: () => (/* binding */ ttsPreferencesFromJson)\n/* harmony export */ });\nconst DEFAULT_RATE = 1.0;\nconst DEFAULT_PITCH = 1.0;\nfunction getAvailableVoicesAsync() {\n return new Promise((resolve) => {\n const voices = speechSynthesis.getVoices();\n if (voices.length > 0) {\n resolve(voices);\n return;\n }\n const handler = () => {\n speechSynthesis.removeEventListener("voiceschanged", handler);\n resolve(speechSynthesis.getVoices());\n };\n speechSynthesis.addEventListener("voiceschanged", handler);\n setTimeout(() => {\n speechSynthesis.removeEventListener("voiceschanged", handler);\n resolve(speechSynthesis.getVoices());\n }, 2000);\n });\n}\nfunction ttsPreferencesFromJson(json) {\n const rate = typeof json.speed === "number" ? json.speed : DEFAULT_RATE;\n const pitch = typeof json.pitch === "number" ? json.pitch : DEFAULT_PITCH;\n const voiceId = typeof json.voiceIdentifier === "string" ? json.voiceIdentifier : null;\n const langOverride = typeof json.languageOverride === "string" ? json.languageOverride : null;\n let voice = null;\n if (voiceId) {\n voice = speechSynthesis.getVoices().find((v) => v.voiceURI === voiceId) ?? null;\n }\n return { rate, pitch, voice, lang: langOverride };\n}\nasync function serializeVoices() {\n const voices = await getAvailableVoicesAsync();\n const result = voices.map((v) => ({\n identifier: v.voiceURI,\n name: v.name,\n language: v.lang,\n networkRequired: !v.localService,\n }));\n return JSON.stringify(result);\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/TTS/ttsPreferences.ts?\n}')},"./web/_scripts/WebPub/webPubPrefences.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ defaults: () => (/* binding */ defaults),\n/* harmony export */ initializeWebPubPreferencesFromString: () => (/* binding */ initializeWebPubPreferencesFromString),\n/* harmony export */ setWebPubPreferencesFromString: () => (/* binding */ setWebPubPreferencesFromString)\n/* harmony export */ });\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_2__.createLogger)("WebPubPrefs");\nfunction initializeWebPubPreferencesFromString(preferencesString) {\n const prefs = JSON.parse(preferencesString);\n (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.convertVerticalScroll)(prefs);\n warnIfUnsupportedKeys(prefs);\n if (prefs.textAlign != null) {\n prefs.textAlign = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.textAlignFromJson)(prefs.textAlign);\n }\n let preferences = {\n fontFamily: prefs.fontFamily ?? null,\n fontWeight: prefs.fontWeight ?? null,\n hyphens: prefs.hyphens ?? null,\n iOSPatch: prefs.iOSPatch ?? null,\n iPadOSPatch: prefs.iPadOSPatch ?? null,\n letterSpacing: prefs.letterSpacing ?? null,\n ligatures: prefs.ligatures ?? null,\n lineHeight: prefs.lineHeight ?? null,\n noRuby: prefs.noRuby ?? null,\n paragraphIndent: prefs.paragraphIndent ?? null,\n paragraphSpacing: prefs.paragraphSpacing ?? null,\n textAlign: prefs.textAlign ?? null,\n textNormalization: prefs.textNormalization ?? null,\n wordSpacing: prefs.wordSpacing ?? null,\n zoom: prefs.zoom ?? typeof prefs.fontSize === "number"\n ? prefs.fontSize / 100\n : null,\n };\n preferences = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.normalizeTypes)(preferences);\n return preferences;\n}\nfunction setWebPubPreferencesFromString(preferencesString, nav) {\n const prefs = initializeWebPubPreferencesFromString(preferencesString);\n log.debug("Submitting preferences to WebPubNavigator", prefs);\n nav.submitPreferences(new _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.WebPubPreferences(prefs));\n}\nconst WEBPUB_UNSUPPORTED_KEYS = [\n "backgroundColor",\n "textColor",\n "linkColor",\n "visitedColor",\n "selectionBackgroundColor",\n "selectionTextColor",\n "columnCount",\n "scroll",\n "pageGutter",\n "pageMargins",\n "imageFilter",\n "blendFilter",\n "darkenFilter",\n "invertFilter",\n "invertGaijiFilter",\n "constraint",\n "deprecatedFontSize",\n "fontSizeNormalize",\n "fontOpticalSizing",\n "fontWidth",\n "optimalLineLength",\n];\nfunction warnIfUnsupportedKeys(prefs) {\n const dropped = WEBPUB_UNSUPPORTED_KEYS.filter((k) => prefs[k] !== undefined && prefs[k] !== null);\n if (dropped.length > 0) {\n log.warn(`Ignoring WebPub-unsupported preferences: ${dropped.join(", ")}. ` +\n "Upstream WebPubPreferences has no equivalent field. Route via the " +\n "EPUB profile (manifest conformsTo) to get full preference support.");\n }\n}\nconst defaults = {\n fontFamily: "Arial",\n fontWeight: 400,\n hyphens: true,\n letterSpacing: 0,\n ligatures: true,\n lineHeight: 1.5,\n noRuby: false,\n paragraphIndent: 0,\n paragraphSpacing: 0,\n textAlign: _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.justify,\n textNormalization: true,\n wordSpacing: 0,\n zoom: 1,\n};\n\n\n//# sourceURL=webpack:///./web/_scripts/WebPub/webPubPrefences.ts?\n}')},"./web/_scripts/WebPub/webpubNavigator.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ initializeWebPubNavigatorAndPeripherals: () => (/* binding */ initializeWebPubNavigatorAndPeripherals)\n/* harmony export */ });\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _peripherals__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../peripherals */ "./web/_scripts/peripherals.ts");\n/* harmony import */ var _webPubPrefences__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./webPubPrefences */ "./web/_scripts/WebPub/webPubPrefences.ts");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../helpers */ "./web/_scripts/helpers.ts");\n/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../logger */ "./web/_scripts/logger.ts");\n/* harmony import */ var _Epub_epubNavigator__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../Epub/epubNavigator */ "./web/_scripts/Epub/epubNavigator.ts");\n\n\n\n\n\n\nconst log = (0,_logger__WEBPACK_IMPORTED_MODULE_4__.createLogger)("WebPubNav");\nasync function initializeWebPubNavigatorAndPeripherals(container, publication, initialPosition = undefined, preferencesJsonString, setNav) {\n log.info("Initializing WebPubNavigator");\n let preferences = (0,_webPubPrefences__WEBPACK_IMPORTED_MODULE_2__.initializeWebPubPreferencesFromString)(preferencesJsonString);\n log.debug("WebPub preferences", preferences);\n const totalPositions = publication.readingOrder.items.length;\n const TEXT_LOCATOR_DEBOUNCE_MS = 200;\n let textLocatorTimer;\n const emitTextLocatorDebounced = (locator) => {\n if (textLocatorTimer !== undefined)\n clearTimeout(textLocatorTimer);\n textLocatorTimer = setTimeout(() => {\n textLocatorTimer = undefined;\n window.updateTextLocator?.(JSON.stringify(locator.serialize()));\n }, TEXT_LOCATOR_DEBOUNCE_MS);\n };\n const configuration = {\n preferences,\n defaults: _webPubPrefences__WEBPACK_IMPORTED_MODULE_2__.defaults,\n };\n const p = new _peripherals__WEBPACK_IMPORTED_MODULE_1__["default"]({\n moveTo: (direction) => {\n if (direction === "right") {\n nav.goRight(true, () => { });\n }\n else if (direction === "left") {\n nav.goLeft(true, () => { });\n }\n else if (direction === "up") {\n const iframes = document.querySelectorAll(".readium-navigator-iframe");\n iframes.forEach((iframe) => {\n if (iframe instanceof HTMLIFrameElement) {\n if (iframe.style.visibility !== "hidden") {\n iframe.contentWindow?.scrollBy(0, -100);\n }\n }\n });\n }\n else if (direction === "down") {\n const iframes = document.querySelectorAll(".readium-navigator-iframe");\n iframes.forEach((iframe) => {\n if (iframe instanceof HTMLIFrameElement) {\n if (iframe.style.visibility !== "hidden") {\n iframe.contentWindow?.scrollBy(0, 100);\n }\n }\n });\n }\n },\n menu: (_show) => {\n },\n goProgression: (_shiftKey) => {\n nav.goForward(true, () => { });\n },\n });\n const listeners = {\n scroll: function (_amount) { },\n frameLoaded: function (_wnd) {\n nav._cframes.forEach((frameManager) => {\n if (frameManager) {\n p.observe(frameManager.window);\n (0,_helpers__WEBPACK_IMPORTED_MODULE_3__.injectDecorationOverrides)(frameManager.window);\n }\n });\n p.observe(window);\n },\n positionChanged: (_locator) => {\n emitTextLocatorDebounced((0,_Epub_epubNavigator__WEBPACK_IMPORTED_MODULE_5__.enrichWithTotalProgression)(_locator, totalPositions));\n },\n tap: function (_e) {\n log.debug("tap event");\n return false;\n },\n click: function (_e) {\n log.debug("click event");\n return false;\n },\n zoom: function (_scale) { },\n customEvent: function (_key, _data) { },\n handleLocator: function (locator) {\n const href = locator.href;\n if (href.startsWith("http://") ||\n href.startsWith("https://") ||\n href.startsWith("mailto:") ||\n href.startsWith("tel:")) {\n if (confirm(`Open "${href}" ?`))\n window.open(href, "_blank");\n }\n else {\n log.warn("Unhandled locator href:", href);\n }\n return false;\n },\n contentProtection: function (_type, _data) { },\n peripheral: function (_data) { },\n contextMenu: function (_data) { },\n textSelected: function (_selection) {\n const locatorJson = {\n ...nav.currentLocator.serialize(),\n text: { highlight: _selection.text },\n };\n window.onTextSelectedCallback?.(JSON.stringify({ locator: locatorJson, selectedText: _selection.text }));\n },\n };\n const nav = new _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.WebPubNavigator(container, publication, listeners, initialPosition, configuration);\n try {\n await nav.load();\n }\n catch (error) {\n throw error;\n }\n setNav(nav);\n p.observe(window);\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/WebPub/webpubNavigator.ts?\n}')},"./web/_scripts/enums.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ReadiumReaderStatus: () => (/* binding */ ReadiumReaderStatus)\n/* harmony export */ });\nvar ReadiumReaderStatus;\n(function (ReadiumReaderStatus) {\n ReadiumReaderStatus["loading"] = "loading";\n ReadiumReaderStatus["ready"] = "ready";\n ReadiumReaderStatus["closed"] = "closed";\n ReadiumReaderStatus["reachedEndOfPublication"] = "reachedEndOfPublication";\n ReadiumReaderStatus["error"] = "error";\n})(ReadiumReaderStatus || (ReadiumReaderStatus = {}));\n\n\n//# sourceURL=webpack:///./web/_scripts/enums.ts?\n}')},"./web/_scripts/extensions/ReadiumPublication.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ReadiumPublication: () => (/* binding */ ReadiumPublication)\n/* harmony export */ });\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n\nclass ReadiumPublication extends _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Publication {\n conformsToArray = this.manifest.metadata.conformsTo;\n conformsToEpub = this.conformsToArray?.some((profile) => {\n return profile == _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Profile.EPUB;\n }) ?? false;\n conformsToAudiobook = this.conformsToArray?.some((profile) => {\n return profile == _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Profile.AUDIOBOOK;\n }) ?? false;\n conformsToDivina = this.conformsToArray?.some((profile) => {\n return profile == _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Profile.DIVINA;\n }) ?? false;\n conformsToPDF = this.conformsToArray?.some((profile) => {\n return profile == _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Profile.PDF;\n }) ?? false;\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/extensions/ReadiumPublication.ts?\n}')},"./web/_scripts/helpers.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ SPOTLIGHT_GROUP_SUFFIX: () => (/* binding */ SPOTLIGHT_GROUP_SUFFIX),\n/* harmony export */ UNDERLINE_GROUP_SUFFIX: () => (/* binding */ UNDERLINE_GROUP_SUFFIX),\n/* harmony export */ clearSpotlightState: () => (/* binding */ clearSpotlightState),\n/* harmony export */ convertVerticalScroll: () => (/* binding */ convertVerticalScroll),\n/* harmony export */ dartColorToCss: () => (/* binding */ dartColorToCss),\n/* harmony export */ fetchManifest: () => (/* binding */ fetchManifest),\n/* harmony export */ highlightSelection: () => (/* binding */ highlightSelection),\n/* harmony export */ injectDecorationOverrides: () => (/* binding */ injectDecorationOverrides),\n/* harmony export */ injectFlutterReadiumHelperScripts: () => (/* binding */ injectFlutterReadiumHelperScripts),\n/* harmony export */ mediaTypes: () => (/* binding */ mediaTypes),\n/* harmony export */ navIframeWindows: () => (/* binding */ navIframeWindows),\n/* harmony export */ normalizeTypes: () => (/* binding */ normalizeTypes),\n/* harmony export */ registerPendingDecorationGroup: () => (/* binding */ registerPendingDecorationGroup),\n/* harmony export */ sendDecorate: () => (/* binding */ sendDecorate),\n/* harmony export */ setPreferencesFromString: () => (/* binding */ setPreferencesFromString),\n/* harmony export */ setSpotlightGroupOnIframes: () => (/* binding */ setSpotlightGroupOnIframes),\n/* harmony export */ textAlignFromJson: () => (/* binding */ textAlignFromJson)\n/* harmony export */ });\n/* harmony import */ var _readium_navigator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/navigator */ "./node_modules/@readium/navigator/dist/index.js");\n/* harmony import */ var _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @readium/navigator-html-injectables */ "./node_modules/@readium/navigator-html-injectables/dist/index.js");\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n\n\n\nasync function fetchManifest(publicationURL) {\n const manifestLink = new _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Link({ href: "manifest.json" });\n const fetcher = new _readium_shared__WEBPACK_IMPORTED_MODULE_2__.HttpFetcher(undefined, publicationURL);\n const resource = fetcher.get(manifestLink);\n const resourceLink = await resource.link();\n const selfLink = resourceLink.toURL(publicationURL);\n const manifest = await resource.readAsJSON().then((response) => {\n const manifest = _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Manifest.deserialize(response);\n manifest.setSelfLink(selfLink);\n return manifest;\n });\n return { manifest, fetcher, selfLink };\n}\nfunction mediaTypes(publication) {\n let selfLinks = publication.manifest.linksWithRel("self");\n let mediaTypesString = selfLinks\n .map((link) => link.type)\n .filter((type) => typeof type === "string");\n let mediaTypes = mediaTypesString.map((type) => _readium_shared__WEBPACK_IMPORTED_MODULE_2__.MediaType.parse({ mediaType: type }));\n return mediaTypes;\n}\nfunction convertVerticalScroll(prefs) {\n if ("verticalScroll" in prefs) {\n prefs.scroll = prefs.verticalScroll;\n delete prefs.verticalScroll;\n }\n}\nfunction textAlignFromJson(textAlignString) {\n switch (textAlignString) {\n case "left":\n return _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.left;\n case "right":\n return _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.right;\n case "start":\n return _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.start;\n case "justify":\n return _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.justify;\n default:\n return _readium_navigator__WEBPACK_IMPORTED_MODULE_0__.TextAlignment.left;\n }\n}\nfunction normalizeTypes(obj) {\n if (Array.isArray(obj)) {\n return obj.map(normalizeTypes);\n }\n else if (obj !== null && typeof obj === "object") {\n for (const key in obj) {\n if (!obj.hasOwnProperty(key))\n continue;\n const value = obj[key];\n if (typeof value === "string") {\n if (value === "true") {\n obj[key] = true;\n }\n else if (value === "false") {\n obj[key] = false;\n }\n else if (/^-?\\d+(\\.\\d+)?$/.test(value)) {\n obj[key] = value.includes(".")\n ? parseFloat(value)\n : parseInt(value, 10);\n }\n }\n else if (typeof value === "object" && value !== null) {\n obj[key] = normalizeTypes(value);\n }\n else if (value === "null" || value == null) {\n delete obj[key];\n }\n }\n }\n return obj;\n}\nfunction setPreferencesFromString(newPreferencesString, nav) {\n let newPreferences = JSON.parse(newPreferencesString);\n convertVerticalScroll(newPreferences);\n if (newPreferences.textAlign != null) {\n newPreferences.textAlign = textAlignFromJson(newPreferences.textAlign);\n }\n if (newPreferences.pageMargins != null) {\n newPreferences.pageGutter = newPreferences.pageMargins;\n delete newPreferences.pageMargins;\n }\n newPreferences = normalizeTypes(newPreferences);\n nav.submitPreferences(newPreferences);\n}\nconst UNDERLINE_GROUP_SUFFIX = "__underline";\nconst SPOTLIGHT_GROUP_SUFFIX = "__spotlight";\nfunction dartColorToCss(color) {\n if (/^#[0-9a-fA-F]{8}$/.test(color)) {\n return "#" + color.slice(3) + color.slice(1, 3);\n }\n return color;\n}\nconst SPOTLIGHT_CLASS = "flutter-readium-spotlight";\nconst AUGMENT_STYLE_ID_PREFIX = "flutter-readium-augment-";\nconst SPOTLIGHT_STYLE_ID = "flutter-readium-spotlight-style";\nconst OVERRIDES_STYLE_ID = "flutter-readium-decoration-overrides";\nconst OVERRIDES_DATASET_FLAG = "flutterReadiumOverrides";\nconst IFRAME_STATE_KEY = "__flutterReadiumDecorationState";\nconst _spotlightGroups = new Set();\nfunction getIframeState(wnd) {\n const w = wnd;\n if (!w[IFRAME_STATE_KEY]) {\n w[IFRAME_STATE_KEY] = {\n pendingNewGroups: [],\n groupInternalId: new Map(),\n spotlightGroups: new Set(),\n };\n }\n return w[IFRAME_STATE_KEY];\n}\nfunction sendDecorate(nav, group, action, decoration) {\n const frameComms = nav._cframes?.[0]?.msg;\n if (!frameComms) {\n console.warn("sendDecorate: no FrameComms channel available");\n return;\n }\n frameComms.send("decorate", { group, action, decoration });\n}\nfunction navIframeWindows(nav) {\n const frames = nav._cframes ?? [];\n return frames\n .map((f) => f?.window)\n .filter((w) => !!w);\n}\nfunction resolveLocatorElement(doc, locator) {\n const css = locator.locations?.otherLocations?.get?.("cssSelector");\n if (css) {\n try {\n const el = doc.querySelector(css);\n if (el)\n return el;\n }\n catch {\n }\n }\n const fragId = locator.locations?.fragments?.[0]?.replace(/^#/, "");\n if (fragId)\n return doc.getElementById(fragId);\n return null;\n}\nfunction registerPendingDecorationGroup(iframes, group, isUnderline, tint) {\n for (const wnd of iframes) {\n const state = getIframeState(wnd);\n if (state.groupInternalId.has(group))\n continue;\n if (state.pendingNewGroups.some((p) => p.group === group))\n continue;\n state.pendingNewGroups.push({ group, isUnderline, tint });\n }\n}\nfunction clearSpotlightState() {\n _spotlightGroups.clear();\n}\nfunction setSpotlightGroupOnIframes(iframes, group, active) {\n if (active)\n _spotlightGroups.add(group);\n else\n _spotlightGroups.delete(group);\n for (const wnd of iframes) {\n const state = getIframeState(wnd);\n if (active)\n state.spotlightGroups.add(group);\n else\n state.spotlightGroups.delete(group);\n applySpotlightToIframe(wnd);\n }\n}\nfunction applySpotlightToIframe(wnd) {\n const doc = wnd.document;\n const body = doc.body;\n if (!body)\n return;\n const state = getIframeState(wnd);\n const groups = state.spotlightGroups;\n body.classList.toggle(SPOTLIGHT_CLASS, groups.size > 0);\n let styleEl = doc.getElementById(SPOTLIGHT_STYLE_ID);\n if (!styleEl) {\n styleEl = doc.createElement("style");\n styleEl.id = SPOTLIGHT_STYLE_ID;\n styleEl.dataset.readium = "true";\n doc.head.appendChild(styleEl);\n }\n if (groups.size === 0) {\n styleEl.textContent = "";\n return;\n }\n const internalIds = [];\n for (const group of groups) {\n const mainId = state.groupInternalId.get(group);\n if (mainId)\n internalIds.push(mainId);\n const underlineId = state.groupInternalId.get(group + UNDERLINE_GROUP_SUFFIX);\n if (underlineId)\n internalIds.push(underlineId);\n }\n const restoreRules = internalIds\n .map((id) => `body.${SPOTLIGHT_CLASS} ::highlight(${id}) { color: initial !important; }`)\n .join("\\n ");\n styleEl.textContent = `\n :root[style*="--USER__textColor"] body.${SPOTLIGHT_CLASS} *:not(a),\n body.${SPOTLIGHT_CLASS} *:not(a) {\n color: rgba(0, 0, 0, 0.22) !important;\n }\n ${restoreRules}\n `;\n}\nfunction pairWithPendingGroup(wnd, styleEl) {\n const state = getIframeState(wnd);\n const pending = state.pendingNewGroups.shift();\n if (!pending)\n return;\n const internalId = styleEl.id.replace(/-style$/, "");\n state.groupInternalId.set(pending.group, internalId);\n if (pending.isUnderline) {\n const augment = wnd.document.createElement("style");\n augment.dataset.readium = "true";\n augment.id = AUGMENT_STYLE_ID_PREFIX + internalId;\n augment.textContent = `\n ::highlight(${internalId}) {\n color: inherit;\n background-color: transparent;\n text-decoration: underline 0.15em solid ${pending.tint};\n }\n `;\n styleEl.parentNode?.insertBefore(augment, styleEl.nextSibling);\n }\n if (state.spotlightGroups.size > 0) {\n applySpotlightToIframe(wnd);\n }\n}\nfunction injectDecorationOverrides(wnd) {\n const doc = wnd.document;\n if (doc.documentElement.dataset[OVERRIDES_DATASET_FLAG] === "true")\n return;\n doc.documentElement.dataset[OVERRIDES_DATASET_FLAG] = "true";\n const overrides = doc.createElement("style");\n overrides.dataset.readium = "true";\n overrides.id = OVERRIDES_STYLE_ID;\n overrides.textContent = `\n [data-group$="${UNDERLINE_GROUP_SUFFIX}"] .readium-highlight {\n background-color: transparent !important;\n border-bottom: 0.15em solid var(--flutter-readium-underline-tint, currentColor) !important;\n box-sizing: border-box !important;\n }\n `;\n doc.head.appendChild(overrides);\n const mirrorTint = (box) => {\n const tint = box.style.backgroundColor;\n if (tint) {\n box.style.setProperty("--flutter-readium-underline-tint", tint);\n }\n };\n const isUnderlineBox = (el) => el.classList?.contains("readium-highlight") === true &&\n el.closest(`[data-group$="${UNDERLINE_GROUP_SUFFIX}"]`) !== null;\n const bodyObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (let i = 0; i < m.addedNodes.length; i++) {\n const node = m.addedNodes[i];\n if (node.nodeType !== 1)\n continue;\n const el = node;\n if (isUnderlineBox(el))\n mirrorTint(el);\n el.querySelectorAll?.(`[data-group$="${UNDERLINE_GROUP_SUFFIX}"] .readium-highlight`).forEach((b) => mirrorTint(b));\n }\n }\n });\n bodyObserver.observe(doc.body, { childList: true, subtree: true });\n const isReadiumGroupStyle = (el) => el.tagName === "STYLE" &&\n typeof el.id === "string" &&\n /^readium-decoration-\\d+-style$/.test(el.id);\n doc.head.querySelectorAll("style[data-readium]").forEach((el) => {\n if (isReadiumGroupStyle(el))\n pairWithPendingGroup(wnd, el);\n });\n const headObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (let i = 0; i < m.addedNodes.length; i++) {\n const node = m.addedNodes[i];\n if (node.nodeType !== 1)\n continue;\n const el = node;\n if (isReadiumGroupStyle(el))\n pairWithPendingGroup(wnd, el);\n }\n }\n });\n headObserver.observe(doc.head, { childList: true });\n if (_spotlightGroups.size > 0) {\n const state = getIframeState(wnd);\n state.spotlightGroups = new Set(_spotlightGroups);\n applySpotlightToIframe(wnd);\n }\n}\nconst HELPER_INJECTED_FLAG = "flutterReadiumHelperInjected";\nconst HELPER_JS_ASSET = "assets/packages/flutter_readium/assets/helpers/flutterReadiumTools.js";\nconst HELPER_CSS_ASSET = "assets/packages/flutter_readium/assets/helpers/flutterReadiumTools.css";\nlet _cachedHelperJs = null;\nlet _cachedHelperCss = null;\nasync function _fetchHelperAssets() {\n try {\n if (_cachedHelperJs === null) {\n const res = await fetch(HELPER_JS_ASSET);\n if (!res.ok)\n throw new Error(`HTTP ${res.status} for ${HELPER_JS_ASSET}`);\n _cachedHelperJs = await res.text();\n }\n if (_cachedHelperCss === null) {\n const res = await fetch(HELPER_CSS_ASSET);\n if (!res.ok)\n throw new Error(`HTTP ${res.status} for ${HELPER_CSS_ASSET}`);\n _cachedHelperCss = await res.text();\n }\n return { js: _cachedHelperJs, css: _cachedHelperCss };\n }\n catch (err) {\n console.warn("[FlutterReadium] Failed to fetch helper assets:", err);\n return null;\n }\n}\nasync function injectFlutterReadiumHelperScripts(wnd, tocIds) {\n const doc = wnd.document;\n if (doc.documentElement.dataset[HELPER_INJECTED_FLAG] === "true")\n return;\n doc.documentElement.dataset[HELPER_INJECTED_FLAG] = "true";\n const assets = await _fetchHelperAssets();\n if (!assets)\n return;\n const bootstrap = doc.createElement("script");\n bootstrap.textContent = [\n "const isAndroid = false;",\n "const isIos = false;",\n `window.readiumTocIDs = ${JSON.stringify(tocIds)};`,\n "(function() {",\n " try {",\n " Object.defineProperty(document, \'scrollingElement\', {",\n " get: function() { return document.body || document.documentElement; },",\n " configurable: true",\n " });",\n " } catch (_) {}",\n "})();",\n ].join("\\n");\n doc.head.appendChild(bootstrap);\n const style = doc.createElement("style");\n style.textContent = assets.css;\n doc.head.appendChild(style);\n const script = doc.createElement("script");\n script.textContent = assets.js;\n doc.head.appendChild(script);\n}\nfunction highlightSelection(nav, publication, selection) {\n const currentLocator = nav.currentLocator;\n const locator = new _readium_shared__WEBPACK_IMPORTED_MODULE_2__.Locator({\n href: currentLocator.href,\n type: currentLocator.type,\n locations: currentLocator.locations,\n text: {\n highlight: selection.text,\n },\n });\n const decorationId = [selection.text, selection.x, selection.y].join("_");\n const decoration = {\n id: decorationId,\n locator,\n style: {\n tint: "#ff9fff55",\n layout: _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_1__.Layout.Bounds,\n width: _readium_navigator_html_injectables__WEBPACK_IMPORTED_MODULE_1__.Width.Wrap,\n },\n };\n sendDecorate(nav, "selection_" + publication.metadata.identifier, "add", decoration);\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/helpers.ts?\n}')},"./web/_scripts/helpers/tocHref.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ enrichLocatorWithTocHref: () => (/* binding */ enrichLocatorWithTocHref),\n/* harmony export */ flattenToc: () => (/* binding */ flattenToc),\n/* harmony export */ tocHrefForTimeLocator: () => (/* binding */ tocHrefForTimeLocator)\n/* harmony export */ });\n/* harmony import */ var _readium_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @readium/shared */ "./node_modules/@readium/shared/dist/index.js");\n\nfunction flattenToc(items) {\n const out = [];\n for (const link of items) {\n out.push(link);\n const children = link.children?.items;\n if (children && children.length > 0) {\n out.push(...flattenToc(children));\n }\n }\n return out;\n}\nfunction enrichLocatorWithTocHref(locator, flatToc) {\n if (flatToc.length === 0)\n return locator;\n const tocHref = _findCurrentTocHref(locator.href, flatToc);\n if (!tocHref)\n return locator;\n const existing = locator.locations?.otherLocations ?? new Map();\n if (existing.get("tocHref") === tocHref)\n return locator;\n const merged = new Map(existing);\n merged.set("tocHref", tocHref);\n return new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.Locator({\n href: locator.href,\n type: locator.type,\n title: locator.title,\n text: locator.text,\n locations: new _readium_shared__WEBPACK_IMPORTED_MODULE_0__.LocatorLocations({\n fragments: locator.locations?.fragments,\n progression: locator.locations?.progression,\n position: locator.locations?.position,\n totalProgression: locator.locations?.totalProgression,\n otherLocations: merged,\n }),\n });\n}\nfunction tocHrefForTimeLocator(locator, flatToc) {\n if (flatToc.length === 0)\n return undefined;\n const resourcePath = _stripFragment(locator.href);\n let currentTime = locator.locations?.time?.();\n if (currentTime === undefined) {\n const tFrag = locator.locations?.fragments?.find((f) => f.startsWith("t="));\n if (tFrag) {\n const parsed = parseFloat(tFrag.slice(2).split(",")[0]);\n if (!isNaN(parsed))\n currentTime = parsed;\n }\n }\n const matching = flatToc.filter((l) => _stripFragment(l.href) === resourcePath);\n if (matching.length === 0)\n return undefined;\n let matched;\n for (const tocLink of matching) {\n const beginTime = _parseTimeFragmentBegin(tocLink.href);\n if (beginTime === undefined)\n continue;\n if (currentTime !== undefined && beginTime > currentTime)\n break;\n matched = tocLink;\n }\n return matched?.href;\n}\nfunction _findCurrentTocHref(resourceHref, flatToc) {\n const targetPath = _stripFragment(resourceHref);\n const match = flatToc.find((l) => _stripFragment(l.href) === targetPath);\n return match?.href;\n}\nfunction _stripFragment(href) {\n const i = href.indexOf("#");\n return i === -1 ? href : href.substring(0, i);\n}\nfunction _parseTimeFragmentBegin(href) {\n const hashIdx = href.indexOf("#");\n if (hashIdx === -1)\n return undefined;\n const fragment = href.slice(hashIdx + 1);\n const match = fragment.match(/^t=([^,]+)/);\n if (!match)\n return undefined;\n const n = parseFloat(match[1]);\n return isNaN(n) ? undefined : n;\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/helpers/tocHref.ts?\n}')},"./web/_scripts/logger.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ LogLevel: () => (/* binding */ LogLevel),\n/* harmony export */ createLogger: () => (/* binding */ createLogger),\n/* harmony export */ getLogLevel: () => (/* binding */ getLogLevel),\n/* harmony export */ setLogLevel: () => (/* binding */ setLogLevel)\n/* harmony export */ });\nvar LogLevel;\n(function (LogLevel) {\n LogLevel[LogLevel["none"] = 0] = "none";\n LogLevel[LogLevel["error"] = 1] = "error";\n LogLevel[LogLevel["warn"] = 2] = "warn";\n LogLevel[LogLevel["info"] = 3] = "info";\n LogLevel[LogLevel["debug"] = 4] = "debug";\n})(LogLevel || (LogLevel = {}));\nlet _currentLevel = LogLevel.info;\nfunction setLogLevel(level) {\n _currentLevel = level;\n}\nfunction getLogLevel() {\n return _currentLevel;\n}\nfunction format(args) {\n return args\n .map((a) => {\n if (typeof a === "string")\n return a;\n if (a instanceof Error)\n return `${a.name}: ${a.message}`;\n try {\n return JSON.stringify(a);\n }\n catch {\n return String(a);\n }\n })\n .join(" ");\n}\nfunction inspectables(args) {\n return args.filter((a) => a !== null && typeof a === "object");\n}\nfunction createLogger(tag) {\n const prefix = `[Readium/${tag}]`;\n return {\n debug: (...args) => {\n if (_currentLevel >= LogLevel.debug)\n console.debug(`DEBUG ${prefix} ${format(args)}`, ...inspectables(args));\n },\n info: (...args) => {\n if (_currentLevel >= LogLevel.info)\n console.info(`INFO ${prefix} ${format(args)}`, ...inspectables(args));\n },\n warn: (...args) => {\n if (_currentLevel >= LogLevel.warn)\n console.warn(`WARN ${prefix} ${format(args)}`, ...inspectables(args));\n },\n error: (...args) => {\n if (_currentLevel >= LogLevel.error)\n console.error(`ERROR ${prefix} ${format(args)}`, ...inspectables(args));\n },\n };\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/logger.ts?\n}')},"./web/_scripts/peripherals.ts"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Peripherals)\n/* harmony export */ });\nclass Peripherals {\n observers = ['keyup', 'keydown'];\n targets = [];\n callbacks;\n constructor(callbacks) {\n this.observers.forEach((method) => {\n this['on' + method] = this['on' + method].bind(this);\n });\n this.callbacks = callbacks;\n }\n destroy() {\n this.targets.forEach((t) => this.unobserve(t));\n }\n unobserve(item) {\n if (!item)\n return;\n this.observers.forEach((EventName) => {\n item.removeEventListener(EventName, this['on' + EventName], false);\n });\n this.targets = this.targets.filter((t) => t !== item);\n }\n observe(item) {\n if (!item)\n return;\n if (this.targets.includes(item))\n return;\n this.observers.forEach((EventName) => {\n item.addEventListener(EventName, this['on' + EventName], false);\n });\n this.targets.push(item);\n }\n onkeyup(e) {\n if (e.code === 'Space')\n this.callbacks.goProgression(e.shiftKey);\n if (e.code === 'Enter')\n this.callbacks.menu(true);\n }\n onkeydown(e) {\n switch (e.code) {\n case 'ArrowRight':\n this.callbacks.moveTo('right');\n e.preventDefault();\n break;\n case 'ArrowLeft':\n this.callbacks.moveTo('left');\n e.preventDefault();\n break;\n case 'ArrowUp':\n this.callbacks.moveTo('up');\n e.preventDefault();\n break;\n case 'ArrowDown':\n this.callbacks.moveTo('down');\n e.preventDefault();\n break;\n }\n }\n}\n\n\n//# sourceURL=webpack:///./web/_scripts/peripherals.ts?\n}")},"./node_modules/@readium/navigator-html-injectables/dist/ar-DyHX_uy2.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ t),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "لا تتوفر أي معلومات", "publisher-contact": "لمزيد من المعلومات حول إمكانية الوصول إلى هذا المنتج، يُرجى التواصل مع الناشر: ", title: "ملخص إمكانية الوصول" }, "additional-accessibility-information": { aria: { compact: "أدوار ARIA مدرَجة", descriptive: "يتم تعزيز المحتوى باستخدام أدوار ARIA لتحسين التنظيم وتيسير التنقّل" }, "audio-descriptions": "الوصف الصوتي", braille: "برايل", "color-not-sole-means-of-conveying-information": "اللون ليس الوسيلة الوحيدة لنقل المعلومات", "dyslexia-readability": "سهولة القراءة لذوي عُسر القراءة", "full-ruby-annotations": "شروح روبي كاملة", "high-contrast-between-foreground-and-background-audio": "تباين عالٍ بين الصوت الرئيسي وصوت الخلفية", "high-contrast-between-text-and-background": "تباين عالٍ بين النص والخلفية", "large-print": "خط كبير", "page-breaks": { compact: "فواصل الصفحات متضمَّنة", descriptive: "فواصل الصفحات متضمَّنة من المصدر المطبوع الأصلي" }, "ruby-annotations": "بعض شروح الروبي", "sign-language": "لغة الإشارة", "tactile-graphics": { compact: "الرسوم اللمسية مدرجة", descriptive: "تم دمج الرسوم اللمسية لتيسير الوصول إلى العناصر البصرية للأشخاص المكفوفين" }, "tactile-objects": "مجسمات لمسية ثلاثية الأبعاد", "text-to-speech-hinting": "إرشادات تحويل النص إلى كلام (TTS)متوفرة", title: "معلومات إضافية عن إمكانية الوصول", "ultra-high-contrast-between-text-and-background": "تباين عالٍ جدًا بين النص والخلفية", "visible-page-numbering": "ترقيم صفحات مرئي", "without-background-sounds": "من دون أصوات في خلفية" }, conformance: { a: { compact: "هذا المنشور يفي بالمعايير الدنيا لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى A من معيار WCAG 2" }, aa: { compact: "هذا المنشور يفي بالمعايير المعتمدة لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى AA من معيار WCAG 2" }, aaa: { compact: "هذا المنشور يفوق المعايير المقبولة لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى AAA من معيار WCAG 2" }, certifier: "تم اعتماد هذا المنشور من قبل ", "certifier-credentials": "بيانات اعتماد جهة التصديق ", details: { "certification-info": "تم اعتماد هذا المنشور في تاريخ ", "certifier-report": "لمزيد من المعلومات، يرجى الرجوع إلى تقرير جهة التصديق", claim: "يدّعي هذا المنشور أنه يستوفي", "epub-accessibility-1-0": "معيار إمكانية الوصول لـ EPUB إصدار 1.0", "epub-accessibility-1-1": "معيار إمكانية الوصول لـ EPUB إصدار 1.1", "level-a": "المستوى A", "level-aa": "المستوى AA", "level-aaa": "المستوى AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.2" } }, "details-title": "معلومات تفصيلية عن مدى المطابقة", no: "لا تتوفر أي معلومات", title: "المطابقة", "unknown-standard": "لا يمكن التأكد من مدى مطابقة هذا المنشور للمعايير المقبولة لإمكانية الوصول" }, hazards: { flashing: { compact: "محتوى وامض", descriptive: "يحتوي هذا المنشور على محتوى وامض قد يسبب نوبات حساسة للضوء" }, "flashing-none": { compact: "لا توجد مخاطر وميض", descriptive: "لا يحتوي هذا المنشور على محتوى وامض قد يسبب نوبات حساسة للضوء" }, "flashing-unknown": { compact: "مخاطر الوميض غير معروفة", descriptive: "لم يُمكن التأكد من وجود محتوى وامض قد يسبب نوبات حساسية للضوء" }, motion: { compact: "محاكاة الحركة", descriptive: "يحتوي المنشور على محاكاة حركة قد تسبّب دوار الحركة" }, "motion-none": { compact: "لا توجد مخاطر محاكاة الحركة", descriptive: "لا يحتوي المنشور على محاكاة حركة قد تسبّب دوار الحركة" }, "motion-unknown": { compact: "مخاطر محاكاة الحركة غير معروفة", descriptive: "تعذّر تحديد ما إذا كانت هناك محاكاة للحركة قد تُسبب دوار الحركة" }, "no-metadata": "لا تتوفر أي معلومات", none: { compact: "لا توجد مخاطر", descriptive: "لا يحتوي المنشور على أي مخاطر" }, sound: { compact: "أصوات", descriptive: "يحتوي المنشور على أصوات قد تؤدي إلى مشاكل حساسية صوتية" }, "sound-none": { compact: "لا توجد مخاطر صوتية", descriptive: "لا يحتوي المنشور على أصوات قد تؤدي إلى مشاكل حساسية صوتية" }, "sound-unknown": { compact: "مخاطر الصوت غير معروفة", descriptive: "تعذّر تحديد ما إذا كانت هناك أصوات قد تُسبب مشكلات في الحساسية" }, title: "مخاطر", unknown: "وجود المخاطر غير معروف" }, "legal-considerations": { exempt: { compact: "يُعلن عن استثناء من متطلبات إمكانية الوصول من بعض السلطات القضائية", descriptive: "يُصرّح هذا المنشور بوجود استثناء من متطلبات إمكانية الوصول من بعض السلطات القضائية" }, "no-metadata": "لا تتوفر أي معلومات", title: "اعتبارات قانونية" }, navigation: { index: { compact: "كشاف", descriptive: "كشاف يحتوي على روابط إلى الإدخالات المشار إليها" }, "no-metadata": "لا تتوفر أي معلومات", "page-navigation": { compact: "الانتقال إلى صفحة", descriptive: "قائمة الصفحات للانتقال إلى صفحات من النسخة المطبوعة الأصلية" }, structural: { compact: "العناوين", descriptive: "عناصر مثل العناوين والجداول وغيرها للتنقل المنظّم" }, title: "التنقل", toc: { compact: "جدول المحتويات", descriptive: "جدول المحتويات لكل فصول النص عبر روابط" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "الصيغ الكيميائية بصيغة LaTeX", descriptive: "الصيغ الكيميائية بشكل ميسر (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "الصيغ الكيميائية بصيغة MathML", descriptive: "الصيغ الكيميائية بشكل ميسر (MathML)" }, "accessible-math-as-latex": { compact: "الرياضيات بصيغة LaTeX", descriptive: "الصيغ الرياضية بشكل ميسر (LaTeX)" }, "accessible-math-described": "تتوفر أوصاف نصية للصيغ الرياضية", "closed-captions": { compact: "تحتوي الفيديوهات على شروح مغلقة", descriptive: "الفيديوهات الموجودة في المنشورات تحتوي على شروح مغلقة" }, "extended-descriptions": "يتم وصف الصور الغنية بالمعلومات بأوصاف مفصّلة", "math-as-mathml": { compact: "الرياضيات بصيغة MathML", descriptive: "الصيغ الرياضية بشكل ميسر(MathML)" }, "open-captions": { compact: "تحتوي الفيديوهات على شروح مدمجة", descriptive: "الفيديوهات الموجودة في المنشورات تحتوي على شروح مدمجة" }, title: "محتوى غني", transcript: "يتوفر نص(نصوص)", unknown: "لا تتوفر أي معلومات" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "يحتوي على نص بديل", descriptive: "يحتوي على أوصاف نصية بديلة للصور" }, "no-metadata": "لا تتوفر معلومات عن القراءة غير البصرية", none: { compact: "غير قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "المحتوى غير قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية" }, "not-fully": { compact: "غير قابل للقراءة بالكامل بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "لن يكون كل المحتوى قابلًا للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية" }, readable: { compact: "قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "يمكن قراءة كل المحتوى بصوتٍ عالٍ أو بطريقة برايل الديناميكية" } }, "prerecorded-audio": { complementary: { compact: "مقاطع الصوت المسجّلة مسبقًا", descriptive: "مقاطع الصوت المسجّلة مسبقًا مدمجة في المحتوى" }, "no-metadata": "لا توجد معلومات عن الصوت المسجّل مسبقًا", only: { compact: "الصوت المسجّل مسبقًا فقط", descriptive: "كتاب صوتي بدون بديل نصي" }, synchronized: { compact: "صوت مسجّل مسبقًا متزامن مع النص", descriptive: "كل المحتوى متوفر كصوت مسجّل مسبقًا متزامن مع النص" } }, title: "طرق القراءة", "visual-adjustments": { modifiable: { compact: "يمكن تعديل المظهر", descriptive: "يمكن تعديل مظهر النص وتخطيط الصفحة وفقاً لإمكانات نظام القراءة (اسم الخط وحجمه، والمسافات بين الفقرات والجمل والكلمات والأحرف، بالإضافة إلى لون الخلفية والنص)" }, unknown: "لا توجد معلومات عن إمكانية تعديل المظهر", unmodifiable: { compact: "لا يمكن تعديل المظهر", descriptive: "لا يمكن تعديل مظهر النص وتخطيط الصفحات لأن تجربة القراءة قريبة من النسخة المطبوعة، ولكن تطبيقات القراءة ما زالت تتيح خيارات التكبير" } } } } }, altIdentifier_one: "رمز تعريفي بديل", altIdentifier_other: "رموز تعريفية بديلة", artist_one: "فنان", artist_other: "فنانون", author_one: "مؤلف", author_other: "مؤلفون", collection_one: "سلسلة تحريرية", collection_other: "سلاسل تحريرية", colorist_one: "ملوّن الألوان", colorist_other: "ملوّنو الألوان", contributor_one: "مساهم", contributor_other: "مساهمون", description: "وصف", duration: "مدة", editor_one: "محرر", editor_other: "محررون", identifier_one: "رمز تعريفي", identifier_other: "رموز تعريفية", illustrator_one: "رسًام", illustrator_other: "رسامون", imprint_one: "العلامة التجارية للنشر", imprint_other: "العلامات التجارية للنشر", inker_one: "مُحَبِّر", inker_other: "مُحَبِّرون", language_one: "اللغة", language_other: "اللغات", letterer_one: "خطّاط", letterer_other: "خطّاطون", modified: "تاريخ التعديل", narrator_one: "قارئ صوتي", narrator_other: "قرّاء صوتيون", numberOfPages: "عدد الصفحات في النسخة المطبوعة", penciler_one: "رسّام أولي", penciler_other: "رسّامون أوّليون", published: "تاريخ النشر", publisher_one: "ناشر", publisher_other: "ناشرون", series_one: "سلسلة", series_other: "سلاسل", subject_one: "موضوع", subject_other: "مواضيع", subtitle: "عنوان فرعي", title: "العنوان", translator_one: "مترجم", translator_other: "مترجمون" } }, t = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/ar-DyHX_uy2.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/da-Dct0PS3E.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ i),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "Ingen information tilgængelig", "publisher-contact": "For mere information om tilgængeligheden af denne bog, kontakt venligst udgiveren: ", title: "Tilgængeligheds-oversigt" }, "additional-accessibility-information": { aria: { compact: "Indeholder ARIA roller", descriptive: "Indhold forbedres med ARIA-roller for at optimere organisering og gøre navigation lettere" }, "audio-descriptions": "Lydbeskrivelser", braille: "Punktskrift (braille)", "color-not-sole-means-of-conveying-information": "Information gives ikke udelukkende via farver", "dyslexia-readability": "Læsbarhed for ordblinde", "full-ruby-annotations": \'Indeholder såkalde "ruby" notationer (til asiatiske sprog)\', "high-contrast-between-foreground-and-background-audio": "Høj kontrast imellem forgrunds- og baggrunds-lyd", "high-contrast-between-text-and-background": "Høj kontrast imellem tekst og baggrunden", "large-print": "Forstørret tekst", "page-breaks": { compact: "Indeholder sideskift", descriptive: "Indeholder sideskift fra den trykte version af bogen" }, "ruby-annotations": \'Nogle "ruby" annotationer (til asiatiske sprog)\', "sign-language": "Tegnsprog", "tactile-graphics": { compact: "Indeholder taktil grafik", descriptive: "Indeholder taktil grafik for at muliggøre adgang til visuel information for blinde" }, "tactile-objects": "Taktile 3D objekter", "text-to-speech-hinting": "Udtaleforbedringer til syntetisk tale", title: "Yderligere information om tilgængelighed", "ultra-high-contrast-between-text-and-background": "Ultra høj kontrast imellem tekst og baggrund", "visible-page-numbering": "Synlige sidenumre", "without-background-sounds": "Uden baggrundslyd" }, conformance: { a: { compact: "Denne bog overholder minimum-tilgængelighedskravene", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau A" }, aa: { compact: "Denne bog lever op til de accepterede tilgængelighedskrav", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau AA" }, aaa: { compact: "Denne bog mere end opfylder de accepterede tilgængelighedskrav", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau AAA" }, certifier: "Denne bog blev certificeret af ", "certifier-credentials": "Certificeringsorganets legitimationsoplysninger er ", details: { "certification-info": "Bogen blev certificeret den ", "certifier-report": "Se certificeringsorganets rapport for mere information", claim: "Denne bog hævder at opfylde", "epub-accessibility-1-0": "EPUB Tilgængelighed 1.0", "epub-accessibility-1-1": "EPUB Tilgængelighed 1.1", "level-a": "Niveau A", "level-aa": "Niveau AA", "level-aaa": "Niveau AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.2" } }, "details-title": "Detaljeret overholdelses-information", no: "Ingen information tilgængelig", title: "Overholdelse", "unknown-standard": "Overholdelse af de accepterede tilgængelighedskrav kan ikke vurderes for denne bog" }, hazards: { flashing: { compact: "Blinkende indhold", descriptive: "Bogen indeholder blinkende indhold der kan forårsage epileptiske anfald" }, "flashing-none": { compact: "Ingen blinkende indhold", descriptive: "Bogen indeholder ikke noget blinkende indhold, der kunne forårsage epileptiske anfald" }, "flashing-unknown": { compact: "Ingen information om bogen har blinkende indhold", descriptive: "Det kunne ikke afgøres om bogen indeholder blinkende indhold der kan lede til epileptiske anfald" }, motion: { compact: "Simuleret bevægelse", descriptive: "Bogen indeholder simuleret bevægelse, der kan forårsage en følelse af køresyge" }, "motion-none": { compact: "Indeholder ikke simuleret bevægelse", descriptive: "Denne bog indeholder ikke noget indhold med simuleret bevægelse, der kunne lede til en følelse af køresyge" }, "motion-unknown": { compact: "Ingen information om simuleret bevægelse", descriptive: "Det kunne ikke vurderes om bogen indeholder simuleret bevægelse, der kan lede til en følelse af køresyge" }, "no-metadata": "Ingen information tilgængelig", none: { compact: "Ingen farer", descriptive: "Bogen indeholder ikke noget indhold der kategoriseres som farligt" }, sound: { compact: "Lyde", descriptive: "Bogen indeholder lyde der kan være ubehagelige hvis man er sensitiv overfor lyde" }, "sound-none": { compact: "Ingen ubehagelige lyde", descriptive: "Bogen indeholder ikke lyde der kunne opleves som ubehagelige hvis man er sensitiv overfor lyde" }, "sound-unknown": { compact: "Ingen information om ubehagelige lyde", descriptive: "Det kunne ikke afgøres om bogen indeholder ubehagelige lyde" }, title: "Farer", unknown: "Ingen information om farligt indhold" }, "legal-considerations": { exempt: { compact: "Gør krav på undtagelser fra tilgængelighedskrav", descriptive: "Denne bog gør krav på en tilgængelighedsundtagelse i en eller flere jurisdiktioner" }, "no-metadata": "Ingen information tilgængelig", title: "Juridiske overvejelser" }, navigation: { index: { compact: "Indholdsfortegnelse", descriptive: "Indholdsfortegnelse med links til referencer" }, "no-metadata": "Ingen information tilgængelig", "page-navigation": { compact: "Gå til side", descriptive: "Sideliste for at gå til sider fra den trykte kildeversion" }, structural: { compact: "Overskrifter", descriptive: "Elementer så som overskrifter og tabeller til struktureret navigation" }, title: "Navigation", toc: { compact: "Indholdsfortegnelse", descriptive: "Indholdsfortegnelse med links til alle kapitler" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "Kemiske formularer i LaTeX", descriptive: "Kemiske formularer i tilgængeligt format (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "Kemiske formularer i MathML notation", descriptive: "Kemiske formularer i tilgængeligt format (MathML)" }, "accessible-math-as-latex": { compact: "Matematik som LaTeX", descriptive: "Matematikformler i tilgængeligt format (LaTeX)" }, "accessible-math-described": "Tekstbeskrivelser til matematiske formler", "closed-captions": { compact: "Videoer har undertekster", descriptive: "Videoer der optræder i bogen har undertekster" }, "extended-descriptions": "Informationsrige billeder beskrives med udvidede beskrivelser", "math-as-mathml": { compact: "Matematik som MathML", descriptive: "Matematiske formler i tilgængeligt format (MathML)" }, "open-captions": { compact: "Videoer har indlejrede undertekster", descriptive: "Videoer der optræder i bogen har indlejrede undertekster" }, title: "Komplekst indhold", transcript: "Indeholder transskription(er)", unknown: "Ingen information tilgængelig" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "Har alternativ tekst", descriptive: "Har billedbeskrivelser" }, "no-metadata": "Ingen information omkring ikke-visuel læsning", none: { compact: "Ikke læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Dette indhold er ikke læsbart med oplæsning eller dynamisk punktskrift" }, "not-fully": { compact: "Ikke fuldt læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Alt indholdet er ikke fuldt læsbart med oplæsning eller dynamisk punktskrift" }, readable: { compact: "Læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Alt indholdet er læsbart med oplæsning eller dynamisk punktskrift" } }, "prerecorded-audio": { complementary: { compact: "Indlæste lydklip", descriptive: "Indlæste lydklip er indlejret i indholdet" }, "no-metadata": "Ingen information om indlæst lyd", only: { compact: "Kun indlæst lyd", descriptive: "Lydbog uden tekst alternativer" }, synchronized: { compact: "Indlæst lyd med synkroniseret tekst", descriptive: "Alt indholdet er tilgængeligt med indlæst lyd og synkroniseret tekst" } }, title: "Læseformer", "visual-adjustments": { modifiable: { compact: "Udseende kan ændres", descriptive: "Udseende af tekst og sidelayout kan ændres, så vidt muligt i læsesystemet (skrifttype, skriftstørrelse, afstand mellem afsnit, sætninger, ord og bogstaver, samt farven på tekst og baggrund)" }, unknown: "Ingen information om mulighed for ændring af udseende", unmodifiable: { compact: "Udseende kan ikke ændres", descriptive: "Tekst og sidelayout kan ikke ændres, da læseoplevelsen afspejler den trykte version af materialet. Læsesystemet kan dog stadig give mulighed for zoom" } } } } }, altIdentifier_one: "alternativt ID", altIdentifier_other: "alternative ID\'er", artist_one: "kunstner", artist_other: "kunstnere", author_one: "forfatter", author_other: "forfattere", collection_one: "redaktionel samling", collection_other: "redaktionelle samlinger", colorist_one: "farvelægger", colorist_other: "farvelæggere", contributor_one: "bidragsyder", contributor_other: "bidragsydere", description: "beskrivelse", duration: "varighed", editor_one: "redaktør", editor_other: "redaktører", identifier_one: "ID", identifier_other: "ID\'er", illustrator_one: "illustrator", illustrator_other: "illustratorer", imprint_one: "trykkeri", imprint_other: "trykkerier", inker_one: "tegner", inker_other: "tegnere", language_one: "sprog", language_other: "sprog", letterer_one: "taleboble-forfatter", letterer_other: "taleboble-forfattere", modified: "rettet dato", narrator_one: "indlæser", narrator_other: "indlæsere", numberOfPages: "printbare sider", penciler_one: "tegneseriekunstner", penciler_other: "tegneseriekunstnere", published: "udgivelsesdato", publisher_one: "udgiver", publisher_other: "udgivere", series_one: "serie", series_other: "serier", subject_one: "emne", subject_other: "emner", subtitle: "undertitel", title: "titel", translator_one: "oversætter", translator_other: "oversættere" } }, i = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/da-Dct0PS3E.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/fr-C5HEel98.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ i),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = /* @__PURE__ */ JSON.parse(`{"format":{"audiobook":"Livre audio","audiobookJSON":"Manifeste de livre audio","cbz":"Bande dessinée","divina":"Bande dessinée Divina","divinaJSON":"Manifeste de bande dessinée Divina","epub":"EPUB","lcpa":"Livre audio protégé par LCP","lcpdf":"PDF protégé par LCP","lcpl":"Licence LCP","pdf":"PDF","rwp":"Publication web Readium","rwpm":"Manifeste de publication web Readium","zab":"Livre audio","zip":"Archive ZIP"},"kind":{"audiobook_many":"livres audio","audiobook_one":"livre audio","audiobook_other":"livres audio","book_many":"livres","book_one":"livre","book_other":"livres","comic_many":"bandes dessinées","comic_one":"bande dessinée","comic_other":"bandes dessinées","document_many":"documents","document_one":"document","document_other":"documents"},"metadata":{"accessibility":{"display-guide":{"accessibility-summary":{"no-metadata":"Aucune information disponible","publisher-contact":"Pour plus d\'information à propos de l\'accessibilité de cette publication, veuillez contacter l\'éditeur : ","title":"Informations d\'accessibilité supplémentaires fournies par l\'éditeur"},"additional-accessibility-information":{"aria":{"compact":"Information enrichie pour les technologies d\'assistances","descriptive":"La structure est enrichi de rôles ARIA afin d\'optimiser l\'organisation et de faciliter la navigation via les technologies d\'assistances"},"audio-descriptions":"Description audio","braille":"Braille","color-not-sole-means-of-conveying-information":"La couleur n\'est pas la seule manière de communiquer de l\'information","dyslexia-readability":"Lisibilité adapté aux publics dys","full-ruby-annotations":"Annotations complètes au format ruby (langues asiatiques)","high-contrast-between-foreground-and-background-audio":"Contraste sonore amélioré entre les différents plans","high-contrast-between-text-and-background":"Contraste élevé entre le texte et l\'arrière-plan","large-print":"Grands caractères","page-breaks":{"compact":"Pagination identique à l\'imprimé","descriptive":"Contient une pagination identique à la version imprimée"},"ruby-annotations":"Annotations partielles au format ruby (langues asiatiques)","sign-language":"Langue des signes","tactile-graphics":{"compact":"Graphiques tactiles","descriptive":"Des graphiques tactiles ont été intégrés pour faciliter l\'accès des personnes aveugles aux éléments visuels"},"tactile-objects":"Objets 3D ou tactiles","text-to-speech-hinting":"Prononciation améliorée pour la synthèse vocale","title":"Informations complémentaires sur l\'accessibilité","ultra-high-contrast-between-text-and-background":"Contraste très élevé entre le texte et l\'arrière-plan","visible-page-numbering":"Numérotation de page visible","without-background-sounds":"Aucun bruit de fond"},"conformance":{"a":{"compact":"Cette publication répond aux règles minimales d\'accessibilité","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau A"},"aa":{"compact":"Cette publication répond aux règles d\'accessibilité reconnues","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau AA"},"aaa":{"compact":"Cette publication dépasse les règles d\'accessibilité reconnues","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau AAA"},"certifier":"Accessibilité évaluée par ","certifier-credentials":"L\'évaluateur est accrédité par ","details":{"certification-info":"Cette publication a été certifié le","certifier-report":"Pour plus d\'information, veuillez consulter le rapport de certification","claim":"Cette publication indique respecter","epub-accessibility-1-0":"EPUB Accessibilité 1.0","epub-accessibility-1-1":"EPUB Accessibilité 1.1","level-a":"Niveau A","level-aa":"Niveau AA","level-aaa":"Niveau AAA","wcag-2-0":{"compact":"WCAG 2.0","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.0"},"wcag-2-1":{"compact":"WCAG 2.1","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.1"},"wcag-2-2":{"compact":"WCAG 2.2","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.2"}},"details-title":"Information détaillée","no":"Aucune information disponible","title":"Règles d\'accessibilité","unknown-standard":"Aucune indication concernant les normes d\'accessibilité"},"hazards":{"flashing":{"compact":"Flashs lumineux","descriptive":"La publication contient des flashs lumineux qui peuvent provoquer des crises d’épilepsie"},"flashing-none":{"compact":"Pas de flashs lumineux","descriptive":"La publication ne contient pas de flashs lumineux susceptibles de provoquer des crises d’épilepsie"},"flashing-unknown":{"compact":"Pas d\'information concernant la présence de flashs lumineux","descriptive":"La présence de flashs lumineux susceptibles de provoquer des crises d’épilepsie n\'a pas pu être déterminée"},"motion":{"compact":"Sensations de mouvement","descriptive":"La publication contient des images en mouvement qui peuvent provoquer des nausées, des vertiges et des maux de tête"},"motion-none":{"compact":"Pas de sensations de mouvement","descriptive":"La publication ne contient pas d\'images en mouvement qui pourraient provoquer des nausées, des vertiges et des maux de tête"},"motion-unknown":{"compact":"Pas d\'information concernant la présence d\'images en mouvement","descriptive":"La présence d\'images en mouvement susceptibles de provoquer des nausées, des vertiges et des maux de tête n\'a pas pu être déterminée"},"no-metadata":"Aucune information disponible","none":{"compact":"Aucun points d\'attention","descriptive":"La publication ne présente aucun risque lié à la présence de flashs lumineux, de sensations de mouvement ou de sons"},"sound":{"compact":"Sons","descriptive":"La publication contient des sons qui peuvent causer des troubles de la sensibilité"},"sound-none":{"compact":"Pas de risques sonores","descriptive":"La publication ne contient pas de sons susceptibles de provoquer des troubles de la sensibilité"},"sound-unknown":{"compact":"Pas d\'information concernant la présence de sons","descriptive":"La présence de sons susceptibles de causer des troubles de sensibilité n\'a pas pu être déterminée"},"title":"Points d\'attention","unknown":"La présence de risques est inconnue"},"legal-considerations":{"exempt":{"compact":"Déclare être sous le coup d\'une exemption dans certaines juridictions","descriptive":"Cette publication dééclare être sous le coup d\'une exemption dans certaines juridictions"},"no-metadata":"Aucune information disponible","title":"Considérations légales"},"navigation":{"index":{"compact":"Index","descriptive":"Index comportant des liens vers les entrées référencées"},"no-metadata":"Aucune information disponible","page-navigation":{"compact":"Aller à la page","descriptive":"Permet d\'accéder aux pages de la version source imprimée"},"structural":{"compact":"Titres","descriptive":"Contient des titres pour une navigation structurée"},"title":"Points de repère","toc":{"compact":"Table des matières","descriptive":"Table des matières"}},"rich-content":{"accessible-chemistry-as-latex":{"compact":"Formules chimiques en LaTeX","descriptive":"Formules chimiques en format accessible (LaTeX)"},"accessible-chemistry-as-mathml":{"compact":"Formules chimiques en MathML","descriptive":"Formules chimiques en format accessible (MathML)"},"accessible-math-as-latex":{"compact":"Mathématiques en LaTeX","descriptive":"Formules mathématiques en format accessible (LaTeX)"},"accessible-math-described":"Des descriptions textuelles des formules mathématiques sont fournies","closed-captions":{"compact":"Sous-titres disponibles pour les vidéos","descriptive":"Des sous titres sont disponibles pour les vidéos"},"extended-descriptions":"Les images porteuses d\'informations complexes sont décrites par des descriptions longues","math-as-mathml":{"compact":"Mathématiques en MathML","descriptive":"Formules mathématiques en format accessible (MathML)"},"open-captions":{"compact":"Sous-titres incrustés","descriptive":"Des sous titres sont incrustés pour les vidéos"},"title":"Contenus spécifiques","transcript":"Transcriptions fournies","unknown":"Aucune information disponible"},"ways-of-reading":{"nonvisual-reading":{"alt-text":{"compact":"Images décrites","descriptive":"Les images sont décrites par un texte"},"no-metadata":"Aucune information pour la lecture en voix de synthèse ou en braille","none":{"compact":"Non lisible en voix de synthèse ou en braille","descriptive":"Le contenu n\'est pas lisible en voix de synthèse ou en braille"},"not-fully":{"compact":"Pas entièrement lisible en voix de synthèse ou en braille","descriptive":"Tous les contenus ne pourront pas être lus à haute voix ou en braille"},"readable":{"compact":"Entièrement lisible en voix de synthèse ou en braille","descriptive":"Tous les contenus peuvent être lus en voix de synthèse ou en braille"}},"prerecorded-audio":{"complementary":{"compact":"Clips audio préenregistrés","descriptive":"Des clips audio préenregistrés sont intégrés au contenu"},"no-metadata":"Aucune information sur les enregistrements audio","only":{"compact":"Audio préenregistré uniquement","descriptive":"Livre audio sans texte alternatif"},"synchronized":{"compact":"Audio préenregistré synchronisé avec du texte","descriptive":"Tous les contenus sont disponibles comme audio préenregistrés synchronisés avec le texte"}},"title":"Lisibilité","visual-adjustments":{"modifiable":{"compact":"L\'affichage peut être adapté","descriptive":"L\'apparence du texte et la mise en page peuvent être modifiées en fonction des capacités du système de lecture (famille et taille des polices, espaces entre les paragraphes, les phrases, les mots et les lettres, ainsi que la couleur de l\'arrière-plan et du texte)"},"unknown":"Aucune information sur les possibilités d\'adaptation de l\'affichage","unmodifiable":{"compact":"L\'affichage ne peut pas être adapté","descriptive":"Le texte et la mise en page ne peuvent pas être adaptés étant donné que l\'expérience de lecture est proche de celle de la version imprimée, mais l\'application de lecture peut tout de même proposer la capacité de zoomer"}}}}},"altIdentifier_many":"","altIdentifier_one":"identifiant alternatif","altIdentifier_other":"identifiants alternatifs","artist_many":"","artist_one":"artiste","artist_other":"artiste","author_many":"","author_one":"auteur","author_other":"auteurs","collection_many":"","collection_one":"collection éditoriale","collection_other":"collections éditoriales","colorist_many":"","colorist_one":"coloriste","colorist_other":"coloristes","contributor_many":"","contributor_one":"contributeur","contributor_other":"contributeurs","description":"description","duration":"durée","editor_many":"","editor_one":"éditeur","editor_other":"éditeurs","identifier_many":"","identifier_one":"identifiant","identifier_other":"identifiants","illustrator_many":"","illustrator_one":"illustrateur","illustrator_other":"illustrateurs","imprint_many":"","imprint_one":"marque éditoriale","imprint_other":"marques éditoriales","inker_many":"","inker_one":"encreur","inker_other":"encreurs","language_many":"","language_one":"langue","language_other":"langues","letterer_many":"","letterer_one":"lettreur","letterer_other":"lettreurs","modified":"date de modification","narrator_many":"","narrator_one":"narrateur","narrator_other":"narrateurs","numberOfPages":"pagination papier","penciler_many":"","penciler_one":"dessinateur","penciler_other":"dessinateurs","published":"date de publication","publisher_many":"","publisher_one":"éditeur","publisher_other":"éditeurs","series_many":"","series_one":"série","series_other":"séries","subject_many":"","subject_one":"catégorie","subject_other":"catégories","subtitle":"sous-titre","title":"titre","translator_many":"","translator_one":"traducteur","translator_other":"traducteurs"}}`), i = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/fr-C5HEel98.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/index.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BulkCopyProtector: () => (/* binding */ Ai),\n/* harmony export */ COMMS_VERSION: () => (/* binding */ Z),\n/* harmony export */ Comms: () => (/* binding */ Be),\n/* harmony export */ DEV_TOOLS: () => (/* binding */ Oi),\n/* harmony export */ Decorator: () => (/* binding */ Tt),\n/* harmony export */ FXLModules: () => (/* binding */ Ti),\n/* harmony export */ KeyCombinationManager: () => (/* binding */ xi),\n/* harmony export */ Layout: () => (/* binding */ li),\n/* harmony export */ Loader: () => (/* binding */ Li),\n/* harmony export */ Module: () => (/* binding */ K),\n/* harmony export */ ModuleLibrary: () => (/* binding */ Ae),\n/* harmony export */ PRINT: () => (/* binding */ Di),\n/* harmony export */ PatternAnalyzer: () => (/* binding */ bt),\n/* harmony export */ Peripherals: () => (/* binding */ Ot),\n/* harmony export */ PrintProtector: () => (/* binding */ zt),\n/* harmony export */ ReflowableModules: () => (/* binding */ Pi),\n/* harmony export */ SAVE: () => (/* binding */ Ii),\n/* harmony export */ SELECT_ALL: () => (/* binding */ Ri),\n/* harmony export */ SelectionAnalyzer: () => (/* binding */ Ci),\n/* harmony export */ WebPubModules: () => (/* binding */ Ni),\n/* harmony export */ Width: () => (/* binding */ ai),\n/* harmony export */ mid: () => (/* binding */ Ue)\n/* harmony export */ });\nconst We = Math.pow(2, 32), Yt = () => Math.round(Math.random() * We).toString(36), Ue = () => `${Math.round(performance.now())}-${Yt()}-${Yt()}`, Z = 1;\nclass Be {\n constructor(t) {\n this.destination = null, this.registrar = /* @__PURE__ */ new Map(), this.origin = "", this.channelId = "", this.receiver = this.receive.bind(this), this.preLog = [], this.wnd = t, t.addEventListener("message", this.receiver);\n }\n receive(t) {\n if (t.source === null) throw Error("Event source is null");\n if (typeof t.data != "object") return;\n const e = t.data;\n if (!(!("_readium" in e) || !e._readium || e._readium <= 0)) {\n if (e.key === "_ping") {\n if (!this.destination) {\n if (this.destination = t.source, this.origin = t.origin, this.channelId = e._channel, e._readium !== Z) {\n e._readium > Z ? this.send("error", `received comms version ${e._readium} higher than ${Z}`) : this.send("error", `received comms version ${e._readium} lower than ${Z}`), this.destination = null, this.origin = "", this.channelId = "";\n return;\n }\n this.send("_pong", void 0), this.preLog.forEach((i) => this.send("log", i)), this.preLog = [];\n }\n return;\n } else if (this.channelId) {\n if (e._channel !== this.channelId || t.origin !== this.origin) return;\n } else\n return;\n this.handle(e);\n }\n }\n handle(t) {\n const e = this.registrar.get(t.key);\n if (!e || e.length === 0) {\n t.strict && this.send("_unhandled", t);\n return;\n }\n e.forEach((i) => i.cb(t.data, (s) => {\n this.send("_ack", s, t.id);\n }));\n }\n register(t, e, i) {\n Array.isArray(t) || (t = [t]), t.forEach((s) => {\n const r = this.registrar.get(s);\n if (r && r.length >= 0) {\n if (r.find((a) => a.module === e)) throw new Error(`Trying to register another callback for combination of event ${s} and module ${e}`);\n r.push({\n cb: i,\n module: e\n }), this.registrar.set(s, r);\n } else\n this.registrar.set(s, [{\n cb: i,\n module: e\n }]);\n });\n }\n unregister(t, e) {\n Array.isArray(t) || (t = [t]), t.forEach((i) => {\n const s = this.registrar.get(i);\n !s || s.length === 0 || s.splice(s.findIndex((r) => r.module === e), 1);\n });\n }\n unregisterAll(t) {\n this.registrar.forEach((e, i) => this.registrar.set(i, e.filter((s) => s.module !== t)));\n }\n log(...t) {\n this.destination ? this.send("log", t) : this.preLog.push(t);\n }\n get ready() {\n return !!this.destination;\n }\n destroy() {\n this.destination = null, this.channelId = "", this.preLog = [], this.registrar.clear(), this.wnd.removeEventListener("message", this.receiver);\n }\n send(t, e, i = void 0, s = []) {\n if (!this.destination) throw Error("Attempted to send comms message before destination has been initialized");\n const r = {\n _readium: Z,\n _channel: this.channelId,\n id: i ?? Ue(),\n // scrict,\n key: t,\n data: e\n };\n try {\n this.destination.postMessage(r, {\n targetOrigin: this.origin,\n transfer: s\n });\n } catch (o) {\n if (s.length > 0) throw o;\n this.destination.postMessage(r, this.origin, s);\n }\n }\n}\nconst y = class y {\n constructor(t) {\n this.uri = t;\n }\n /**\n * Parses an [AccessibilityProfile] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new y(t);\n }\n /**\n * Serializes an [AccessibilityProfile] to its RWPM JSON representation.\n */\n serialize() {\n return this.uri;\n }\n /**\n * Returns true if the profile is a WCAG Level A profile.\n */\n get isWCAGLevelA() {\n return this === y.EPUB_A11Y_10_WCAG_20_A || this === y.EPUB_A11Y_11_WCAG_20_A || this === y.EPUB_A11Y_11_WCAG_21_A || this === y.EPUB_A11Y_11_WCAG_22_A;\n }\n /**\n * Returns true if the profile is a WCAG Level AA profile.\n */\n get isWCAGLevelAA() {\n return this === y.EPUB_A11Y_10_WCAG_20_AA || this === y.EPUB_A11Y_11_WCAG_20_AA || this === y.EPUB_A11Y_11_WCAG_21_AA || this === y.EPUB_A11Y_11_WCAG_22_AA;\n }\n /**\n * Returns true if the profile is a WCAG Level AAA profile.\n */\n get isWCAGLevelAAA() {\n return this === y.EPUB_A11Y_10_WCAG_20_AAA || this === y.EPUB_A11Y_11_WCAG_20_AAA || this === y.EPUB_A11Y_11_WCAG_21_AAA || this === y.EPUB_A11Y_11_WCAG_22_AAA;\n }\n};\ny.EPUB_A11Y_10_WCAG_20_A = new y("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-a"), y.EPUB_A11Y_10_WCAG_20_AA = new y("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-aa"), y.EPUB_A11Y_10_WCAG_20_AAA = new y("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-aaa"), y.EPUB_A11Y_11_WCAG_20_A = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-a"), y.EPUB_A11Y_11_WCAG_20_AA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-aa"), y.EPUB_A11Y_11_WCAG_20_AAA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-aaa"), y.EPUB_A11Y_11_WCAG_21_A = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-a"), y.EPUB_A11Y_11_WCAG_21_AA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-aa"), y.EPUB_A11Y_11_WCAG_21_AAA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-aaa"), y.EPUB_A11Y_11_WCAG_22_A = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-a"), y.EPUB_A11Y_11_WCAG_22_AA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-aa"), y.EPUB_A11Y_11_WCAG_22_AAA = new y("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-aaa");\nlet qt = y;\nconst w = class w {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses an [AccessMode] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new w(t);\n }\n /**\n * Serializes an [AccessMode] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nw.AUDITORY = new w("auditory"), w.CHART_ON_VISUAL = new w("chartOnVisual"), w.CHEM_ON_VISUAL = new w("chemOnVisual"), w.COLOR_DEPENDENT = new w("colorDependent"), w.DIAGRAM_ON_VISUAL = new w("diagramOnVisual"), w.MATH_ON_VISUAL = new w("mathOnVisual"), w.MUSIC_ON_VISUAL = new w("musicOnVisual"), w.TACTILE = new w("tactile"), w.TEXT_ON_VISUAL = new w("textOnVisual"), w.TEXTUAL = new w("textual"), w.VISUAL = new w("visual");\nlet Xt = w;\nconst x = class x {\n constructor(t) {\n if (typeof t == "string") {\n if (!x.VALID_MODES.has(t.toLowerCase()))\n return;\n this.value = t.toLowerCase();\n } else {\n const e = t.filter(\n (i) => x.VALID_MODES.has(i.toLowerCase())\n );\n if (e.length === 0)\n return;\n this.value = Array.from(new Set(e));\n }\n }\n /**\n * Parses a [PrimaryAccessMode] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n if (typeof t == "string")\n return new x(t);\n if (!Array.isArray(t)) return;\n const e = t.filter((i) => i ? x.VALID_MODES.has(i.toLowerCase()) : !1);\n if (e.length !== 0)\n return new x(e);\n }\n /**\n * Serializes a [PrimaryAccessMode] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nx.VALID_MODES = /* @__PURE__ */ new Set(["auditory", "tactile", "textual", "visual"]), x.AUDITORY = new x("auditory"), x.TACTILE = new x("tactile"), x.TEXTUAL = new x("textual"), x.VISUAL = new x("visual");\nlet Kt = x;\nconst h = class h {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses a [Feature] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new h(t);\n }\n /**\n * Serializes a [Feature] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nh.NONE = new h("none"), h.ANNOTATIONS = new h("annotations"), h.ARIA = new h("ARIA"), h.INDEX = new h("index"), h.PAGE_BREAK_MARKERS = new h("pageBreakMarkers"), h.PAGE_NAVIGATION = new h("pageNavigation"), h.PRINT_PAGE_NUMBERS = new h("printPageNumbers"), h.READING_ORDER = new h("readingOrder"), h.STRUCTURAL_NAVIGATION = new h("structuralNavigation"), h.TABLE_OF_CONTENTS = new h("tableOfContents"), h.TAGGED_PDF = new h("taggedPDF"), h.ALTERNATIVE_TEXT = new h("alternativeText"), h.AUDIO_DESCRIPTION = new h("audioDescription"), h.CAPTIONS = new h("captions"), h.CLOSED_CAPTIONS = new h("closedCaptions"), h.DESCRIBED_MATH = new h("describedMath"), h.LONG_DESCRIPTION = new h("longDescription"), h.OPEN_CAPTIONS = new h("openCaptions"), h.SIGN_LANGUAGE = new h("signLanguage"), h.TRANSCRIPT = new h("transcript"), h.DISPLAY_TRANSFORMABILITY = new h("displayTransformability"), h.SYNCHRONIZED_AUDIO_TEXT = new h("synchronizedAudioText"), h.TIMING_CONTROL = new h("timingControl"), h.UNLOCKED = new h("unlocked"), h.CHEM_ML = new h("ChemML"), h.LATEX = new h("latex"), h.LATEX_CHEMISTRY = new h("latex-chemistry"), h.MATH_ML = new h("MathML"), h.MATH_ML_CHEMISTRY = new h("MathML-chemistry"), h.TTS_MARKUP = new h("ttsMarkup"), h.HIGH_CONTRAST_AUDIO = new h("highContrastAudio"), h.HIGH_CONTRAST_DISPLAY = new h("highContrastDisplay"), h.LARGE_PRINT = new h("largePrint"), h.BRAILLE = new h("braille"), h.TACTILE_GRAPHIC = new h("tactileGraphic"), h.TACTILE_OBJECT = new h("tactileObject"), h.FULL_RUBY_ANNOTATIONS = new h("fullRubyAnnotations"), h.HORIZONTAL_WRITING = new h("horizontalWriting"), h.RUBY_ANNOTATIONS = new h("rubyAnnotations"), h.VERTICAL_WRITING = new h("verticalWriting"), h.WITH_ADDITIONAL_WORD_SEGMENTATION = new h("withAdditionalWordSegmentation"), h.WITHOUT_ADDITIONAL_WORD_SEGMENTATION = new h("withoutAdditionalWordSegmentation");\nlet Zt = h;\nconst S = class S {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses a [Hazard] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new S(t);\n }\n /**\n * Serializes a [Hazard] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nS.FLASHING = new S("flashing"), S.NO_FLASHING_HAZARD = new S("noFlashingHazard"), S.UNKNOWN_FLASHING_HAZARD = new S("unknownFlashingHazard"), S.MOTION_SIMULATION = new S("motionSimulation"), S.NO_MOTION_SIMULATION_HAZARD = new S("noMotionSimulationHazard"), S.UNKNOWN_MOTION_SIMULATION_HAZARD = new S("unknownMotionSimulationHazard"), S.SOUND = new S("sound"), S.NO_SOUND_HAZARD = new S("noSoundHazard"), S.UNKNOWN_SOUND_HAZARD = new S("unknownSoundHazard"), S.UNKNOWN = new S("unknown"), S.NONE = new S("none");\nlet Jt = S;\nconst E = class E {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses an [Exemption] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new E(t);\n }\n /**\n * Serializes an [Exemption] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nE.NONE = new E("none"), E.DOCUMENTED = new E("documented"), E.LEGAL = new E("legal"), E.TEMPORARY = new E("temporary"), E.TECHNICAL = new E("technical"), E.EAA_DISPROPORTIONATE_BURDEN = new E("eaa-disproportionate-burden"), E.EAA_FUNDAMENTAL_ALTERATION = new E("eaa-fundamental-alteration"), E.EAA_MICROENTERPRISE = new E("eaa-microenterprise"), E.EAA_TECHNICAL_IMPOSSIBILITY = new E("eaa-technical-impossibility"), E.EAA_TEMPORARY = new E("eaa-temporary");\nlet Qt = E;\nconst jt = ["en", "ar", "da", "fr", "it", "pt_PT", "sv"], He = /* @__PURE__ */ JSON.parse(`{"format":{"audiobook":"Audiobook","audiobookJSON":"Audiobook Manifest","cbz":"Comic Book Archive","divina":"Divina Publication","divinaJSON":"Divina Publication Manifest","epub":"EPUB","lcpa":"LCP Protected Audiobook","lcpdf":"LCP Protected PDF","lcpl":"LCP License Document","pdf":"PDF","rwp":"Readium Web Publication","rwpm":"Readium Web Publication Manifest","zab":"Audiobook Archive","zip":"ZIP Archive"},"kind":{"audiobook_one":"audiobook","audiobook_other":"audiobooks","book_one":"book","book_other":"books","comic_one":"comic","comic_other":"comics","document_one":"document","document_other":"documents"},"metadata":{"accessibility":{"display-guide":{"accessibility-summary":{"no-metadata":"No information is available","publisher-contact":"For more information about the accessibility of this product, please contact the publisher: ","title":"Accessibility summary"},"additional-accessibility-information":{"aria":{"compact":"ARIA roles included","descriptive":"Content is enhanced with ARIA roles to optimize organization and facilitate navigation"},"audio-descriptions":"Audio descriptions","braille":"Braille","color-not-sole-means-of-conveying-information":"Color is not the sole means of conveying information","dyslexia-readability":"Dyslexia readability","full-ruby-annotations":"Full ruby annotations","high-contrast-between-foreground-and-background-audio":"High contrast between foreground and background audio","high-contrast-between-text-and-background":"High contrast between foreground text and background","large-print":"Large print","page-breaks":{"compact":"Page breaks included","descriptive":"Page breaks included from the original print source"},"ruby-annotations":"Some Ruby annotations","sign-language":"Sign language","tactile-graphics":{"compact":"Tactile graphics included","descriptive":"Tactile graphics have been integrated to facilitate access to visual elements for blind people"},"tactile-objects":"Tactile 3D objects","text-to-speech-hinting":"Text-to-speech hinting provided","title":"Additional accessibility information","ultra-high-contrast-between-text-and-background":"Ultra high contrast between text and background","visible-page-numbering":"Visible page numbering","without-background-sounds":"Without background sounds"},"conformance":{"a":{"compact":"This publication meets minimum accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level A standard"},"aa":{"compact":"This publication meets accepted accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level AA standard"},"aaa":{"compact":"This publication exceeds accepted accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level AAA standard"},"certifier":"The publication was certified by ","certifier-credentials":"The certifier\'s credential is ","details":{"certification-info":"The publication was certified on ","certifier-report":"For more information refer to the certifier\'s report","claim":"This publication claims to meet","epub-accessibility-1-0":"EPUB Accessibility 1.0","epub-accessibility-1-1":"EPUB Accessibility 1.1","level-a":"Level A","level-aa":"Level AA","level-aaa":"Level AAA","wcag-2-0":{"compact":"WCAG 2.0","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.0"},"wcag-2-1":{"compact":"WCAG 2.1","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.1"},"wcag-2-2":{"compact":"WCAG 2.2","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.2"}},"details-title":"Detailed conformance information","no":"No information is available","title":"Conformance","unknown-standard":"Conformance to accepted standards for accessibility of this publication cannot be determined"},"hazards":{"flashing":{"compact":"Flashing content","descriptive":"The publication contains flashing content that can cause photosensitive seizures"},"flashing-none":{"compact":"No flashing hazards","descriptive":"The publication does not contain flashing content that can cause photosensitive seizures"},"flashing-unknown":{"compact":"Flashing hazards not known","descriptive":"The presence of flashing content that can cause photosensitive seizures could not be determined"},"motion":{"compact":"Motion simulation","descriptive":"The publication contains motion simulations that can cause motion sickness"},"motion-none":{"compact":"No motion simulation hazards","descriptive":"The publication does not contain motion simulations that can cause motion sickness"},"motion-unknown":{"compact":"Motion simulation hazards not known","descriptive":"The presence of motion simulations that can cause motion sickness could not be determined"},"no-metadata":"No information is available","none":{"compact":"No hazards","descriptive":"The publication contains no hazards"},"sound":{"compact":"Sounds","descriptive":"The publication contains sounds that can cause sensitivity issues"},"sound-none":{"compact":"No sound hazards","descriptive":"The publication does not contain sounds that can cause sensitivity issues"},"sound-unknown":{"compact":"Sound hazards not known","descriptive":"The presence of sounds that can cause sensitivity issues could not be determined"},"title":"Hazards","unknown":"The presence of hazards is unknown"},"legal-considerations":{"exempt":{"compact":"Claims an accessibility exemption in some jurisdictions","descriptive":"This publication claims an accessibility exemption in some jurisdictions"},"no-metadata":"No information is available","title":"Legal considerations"},"navigation":{"index":{"compact":"Index","descriptive":"Index with links to referenced entries"},"no-metadata":"No information is available","page-navigation":{"compact":"Go to page","descriptive":"Page list to go to pages from the print source version"},"structural":{"compact":"Headings","descriptive":"Elements such as headings, tables, etc for structured navigation"},"title":"Navigation","toc":{"compact":"Table of contents","descriptive":"Table of contents to all chapters of the text via links"}},"rich-content":{"accessible-chemistry-as-latex":{"compact":"Chemical formulas in LaTeX","descriptive":"Chemical formulas in accessible format (LaTeX)"},"accessible-chemistry-as-mathml":{"compact":"Chemical formulas in MathML","descriptive":"Chemical formulas in accessible format (MathML)"},"accessible-math-as-latex":{"compact":"Math as LaTeX","descriptive":"Math formulas in accessible format (LaTeX)"},"accessible-math-described":"Text descriptions of math are provided","closed-captions":{"compact":"Videos have closed captions","descriptive":"Videos included in publications have closed captions"},"extended-descriptions":"Information-rich images are described by extended descriptions","math-as-mathml":{"compact":"Math as MathML","descriptive":"Math formulas in accessible format (MathML)"},"open-captions":{"compact":"Videos have open captions","descriptive":"Videos included in publications have open captions"},"title":"Rich content","transcript":"Transcript(s) provided","unknown":"No information is available"},"ways-of-reading":{"nonvisual-reading":{"alt-text":{"compact":"Has alternative text","descriptive":"Has alternative text descriptions for images"},"no-metadata":"No information about nonvisual reading is available","none":{"compact":"Not readable in read aloud or dynamic braille","descriptive":"The content is not readable as read aloud speech or dynamic braille"},"not-fully":{"compact":"Not fully readable in read aloud or dynamic braille","descriptive":"Not all of the content will be readable as read aloud speech or dynamic braille"},"readable":{"compact":"Readable in read aloud or dynamic braille","descriptive":"All content can be read as read aloud speech or dynamic braille"}},"prerecorded-audio":{"complementary":{"compact":"Prerecorded audio clips","descriptive":"Prerecorded audio clips are embedded in the content"},"no-metadata":"No information about prerecorded audio is available","only":{"compact":"Prerecorded audio only","descriptive":"Audiobook with no text alternative"},"synchronized":{"compact":"Prerecorded audio synchronized with text","descriptive":"All the content is available as prerecorded audio synchronized with text"}},"title":"Ways of reading","visual-adjustments":{"modifiable":{"compact":"Appearance can be modified","descriptive":"Appearance of the text and page layout can be modified according to the capabilities of the reading system (font family and font size, spaces between paragraphs, sentences, words, and letters, as well as color of background and text)"},"unknown":"No information about appearance modifiability is available","unmodifiable":{"compact":"Appearance cannot be modified","descriptive":"Text and page layout cannot be modified as the reading experience is close to a print version, but reading systems can still provide zooming options"}}}}},"altIdentifier_one":"alternate identifier","altIdentifier_other":"alternate identifiers","artist_one":"artist","artist_other":"artists","author_one":"author","author_other":"authors","collection_one":"editorial collection","collection_other":"editorial collections","colorist_one":"colorist","colorist_other":"colorists","contributor_one":"contributor","contributor_other":"contributors","description":"description","duration":"duration","editor_one":"editor","editor_other":"editors","identifier_one":"identifier","identifier_other":"identifiers","illustrator_one":"illustrator","illustrator_other":"illustrators","imprint_one":"imprint","imprint_other":"imprints","inker_one":"inker","inker_other":"inkers","language_one":"language","language_other":"languages","letterer_one":"letterer","letterer_other":"letterers","modified":"modification date","narrator_one":"narrator","narrator_other":"narrators","numberOfPages":"print length","penciler_one":"penciler","penciler_other":"pencilers","published":"publication date","publisher_one":"publisher","publisher_other":"publishers","series_one":"series","series_other":"series","subject_one":"subject","subject_other":"subjects","subtitle":"subtitle","title":"title","translator_one":"translator","translator_other":"translators"}}`), _e = {\n publication: He\n}, te = {\n fr: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./fr-C5HEel98.js */ "./node_modules/@readium/navigator-html-injectables/dist/fr-C5HEel98.js")),\n ar: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./ar-DyHX_uy2.js */ "./node_modules/@readium/navigator-html-injectables/dist/ar-DyHX_uy2.js")),\n da: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./da-Dct0PS3E.js */ "./node_modules/@readium/navigator-html-injectables/dist/da-Dct0PS3E.js")),\n // \'el\': () => import(\'@edrlab/thorium-locales/publication-metadata/el.json\'),\n // \'et\': () => import(\'@edrlab/thorium-locales/publication-metadata/et.json\'),\n it: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./it-DFOBoXGy.js */ "./node_modules/@readium/navigator-html-injectables/dist/it-DFOBoXGy.js")),\n pt_PT: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./pt_PT-Di3sVjze.js */ "./node_modules/@readium/navigator-html-injectables/dist/pt_PT-Di3sVjze.js")),\n sv: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./sv-BfzAFsVN.js */ "./node_modules/@readium/navigator-html-injectables/dist/sv-BfzAFsVN.js"))\n // \'tr\': () => import(\'@edrlab/thorium-locales/publication-metadata/tr.json\'),\n // \'uk\': () => import(\'@edrlab/thorium-locales/publication-metadata/uk.json\')\n}, ee = _e?.publication?.metadata?.accessibility?.["display-guide"] || {};\nclass $ {\n constructor() {\n this.currentLocaleCode = "en", this.locale = ee, this.loadedLocales = {}, this.loadedLocales.en = ee;\n }\n static getInstance() {\n return $.instance || ($.instance = new $()), $.instance;\n }\n /**\n * Loads a locale dynamically\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr\')\n * @returns Promise indicating if the locale was loaded successfully\n */\n async loadLocale(t) {\n if (!jt.includes(t))\n return console.warn(`Locale \'${t}\' is not enabled`), !1;\n if (t in this.loadedLocales)\n return !0;\n try {\n if (!(t in te))\n return console.warn(`Locale file not found for: ${t}`), !1;\n const s = (await te[t]()).default?.publication?.metadata?.accessibility?.["display-guide"];\n return s ? (this.loadedLocales[t] = s, !0) : (console.warn(`No accessibility strings found in locale ${t}`), !1);\n } catch (e) {\n return console.warn(`Failed to load locale ${t}:`, e), !1;\n }\n }\n /**\n * Registers a new locale or updates an existing one\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr-FR\')\n * @param localeData The locale data to register\n */\n registerLocale(t, e) {\n if (!t || typeof t != "string")\n throw new Error("Locale code must be a non-empty string");\n this.loadedLocales[t] = e;\n }\n /**\n * Sets the current locale by language code, loading it dynamically if needed\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr\')\n * @returns Promise indicating if the locale was set successfully\n */\n async setLocale(t) {\n return t in this.loadedLocales || await this.loadLocale(t), t in this.loadedLocales ? (this.locale = this.loadedLocales[t], this.currentLocaleCode = t, !0) : (console.warn(`Locale \'${t}\' is not available`), !1);\n }\n /**\n * Gets the current locale code (BCP 47)\n */\n getCurrentLocale() {\n return this.currentLocaleCode;\n }\n /**\n * Gets a list of available locale codes\n */\n getAvailableLocales() {\n return jt;\n }\n getNestedValue(t, e) {\n const i = e.split(".");\n let s = t;\n for (const r of i) {\n if (s == null)\n return;\n s = s[r];\n }\n return s;\n }\n /**\n * Gets a localized string by key\n * @param key The key for the string to retrieve\n * @returns The localized string as a [L10nString], or an empty string if not found\n */\n getString(t) {\n let e = this.getNestedValue(this.locale, t);\n return e === void 0 && this.currentLocaleCode !== "en" && (e = this.getNestedValue(this.loadedLocales.en, t)), e !== void 0 ? typeof e == "string" ? { compact: e, descriptive: e } : e : (console.warn(`Missing localization for key: ${t}`), { compact: "", descriptive: "" });\n }\n}\n$.getInstance();\nclass kt {\n /**\n * Creates a [Encryption].\n */\n constructor(t) {\n this.algorithm = t.algorithm, this.compression = t.compression, this.originalLength = t.originalLength, this.profile = t.profile, this.scheme = t.scheme;\n }\n /**\n * Parses a [Encryption] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.algorithm)\n return new kt({\n algorithm: t.algorithm,\n compression: t.compression,\n originalLength: t.originalLength,\n profile: t.profile,\n scheme: t.scheme\n });\n }\n /**\n * Serializes a [Encryption] to its RWPM JSON representation.\n */\n serialize() {\n const t = { algorithm: this.algorithm };\n return this.compression !== void 0 && (t.compression = this.compression), this.originalLength !== void 0 && (t.originalLength = this.originalLength), this.profile !== void 0 && (t.profile = this.profile), this.scheme !== void 0 && (t.scheme = this.scheme), t;\n }\n}\nclass R {\n constructor(t) {\n this.otherProperties = t;\n }\n get page() {\n return this.otherProperties.page;\n }\n /**\n * Creates a [Properties] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new R(t);\n }\n /**\n * Serializes a [Properties] to its RWPM JSON representation.\n */\n serialize() {\n return this.otherProperties;\n }\n /**\n * Makes a copy of this [Properties] after merging in the given additional other [properties].\n */\n add(t) {\n const e = Object.assign({}, this.otherProperties);\n for (const i in t)\n e[i] = t[i];\n return new R(e);\n }\n}\nObject.defineProperty(R.prototype, "encryption", {\n get: function() {\n return kt.deserialize(this.otherProperties.encrypted);\n }\n});\nfunction Ve(n) {\n return n && Array.isArray(n) ? n : void 0;\n}\nfunction Ce(n) {\n return n && typeof n == "string" ? [n] : Ve(n);\n}\nfunction ie(n) {\n return typeof n == "string" ? new Date(n) : void 0;\n}\nfunction ht(n) {\n return isNaN(n) ? void 0 : n;\n}\nfunction O(n) {\n return ht(n) !== void 0 && Math.sign(n) >= 0 ? n : void 0;\n}\nfunction Fe(n) {\n const t = new Array();\n return n.forEach((e) => t.push(e)), t;\n}\nclass l {\n /** Creates a MediaType object. */\n constructor(t) {\n let e, i, s = t.mediaType.replace(/\\s/g, "").split(";");\n const r = s[0].split("/");\n if (r.length === 2) {\n if (e = r[0].toLowerCase().trim(), i = r[1].toLowerCase().trim(), e.length === 0 || i.length === 0)\n throw new Error("Invalid media type");\n } else\n throw new Error("Invalid media type");\n const o = {};\n for (let p = 1; p < s.length; p++) {\n const v = s[p].split("=");\n if (v.length === 2) {\n const g = v[0].toLocaleLowerCase(), m = g === "charset" ? v[1].toUpperCase() : v[1];\n o[g] = m;\n }\n }\n const a = {}, c = Object.keys(o);\n c.sort((p, v) => p.localeCompare(v)), c.forEach((p) => a[p] = o[p]);\n let u = "";\n for (const p in a) {\n const v = a[p];\n u += `;${p}=${v}`;\n }\n const d = `${e}/${i}${u}`, f = a.encoding;\n this.string = d, this.type = e, this.subtype = i, this.parameters = a, this.encoding = f, this.name = t.name, this.fileExtension = t.fileExtension;\n }\n static parse(t) {\n return new l(t);\n }\n /** Structured syntax suffix, e.g. `+zip` in `application/epub+zip`.\n * Gives a hint on the underlying structure of this media type.\n * See. https://tools.ietf.org/html/rfc6838#section-4.2.8\n */\n get structuredSyntaxSuffix() {\n const t = this.subtype.split("+");\n return t.length > 1 ? `+${t[t.length - 1]}` : void 0;\n }\n /** Parameter values might or might not be case-sensitive, depending on the semantics of\n * the parameter name.\n * https://tools.ietf.org/html/rfc2616#section-3.7\n *\n * The character set names may be up to 40 characters taken from the printable characters\n * of US-ASCII. However, no distinction is made between use of upper and lower case\n * letters.\n * https://www.iana.org/assignments/character-sets/character-sets.xhtml\n */\n get charset() {\n return this.parameters.charset;\n }\n /** Returns whether the given `other` media type is included in this media type.\n * For example, `text/html` contains `text/html;charset=utf-8`.\n * - `other` must match the parameters in the `parameters` property, but extra parameters\n * are ignored.\n * - Order of parameters is ignored.\n * - Wildcards are supported, meaning that `image/*` contains `image/png`\n */\n contains(t) {\n const e = typeof t == "string" ? l.parse({ mediaType: t }) : t;\n if (!((this.type === "*" || this.type === e.type) && (this.subtype === "*" || this.subtype === e.subtype)))\n return !1;\n const i = new Set(\n Object.entries(this.parameters).map(([r, o]) => `${r}=${o}`)\n ), s = new Set(\n Object.entries(e.parameters).map(([r, o]) => `${r}=${o}`)\n );\n for (const r of Array.from(i.values()))\n if (!s.has(r))\n return !1;\n return !0;\n }\n /** Returns whether this media type and `other` are the same, ignoring parameters that\n * are not in both media types.\n * For example, `text/html` matches `text/html;charset=utf-8`, but `text/html;charset=ascii`\n * doesn\'t. This is basically like `contains`, but working in both direction.\n */\n matches(t) {\n const e = typeof t == "string" ? l.parse({ mediaType: t }) : t;\n return this.contains(e) || e.contains(this);\n }\n /**\n * Returns whether this media type matches any of the [others] media types.\n */\n matchesAny(...t) {\n for (const e of t)\n if (this.matches(e))\n return !0;\n return !1;\n }\n /** Checks the MediaType equals another one (comparing their string) */\n equals(t) {\n return this.string === t.string;\n }\n /** Returns whether this media type is structured as a ZIP archive. */\n get isZIP() {\n return this.matchesAny(\n l.ZIP,\n l.LCP_PROTECTED_AUDIOBOOK,\n l.LCP_PROTECTED_PDF\n ) || this.structuredSyntaxSuffix === "+zip";\n }\n /** Returns whether this media type is structured as a JSON file. */\n get isJSON() {\n return this.matchesAny(l.JSON) || this.structuredSyntaxSuffix === "+json";\n }\n /** Returns whether this media type is of an OPDS feed. */\n get isOPDS() {\n return this.matchesAny(\n l.OPDS1,\n l.OPDS1_ENTRY,\n l.OPDS2,\n l.OPDS2_PUBLICATION,\n l.OPDS_AUTHENTICATION\n ) || this.structuredSyntaxSuffix === "+json";\n }\n /** Returns whether this media type is of an HTML document. */\n get isHTML() {\n return this.matchesAny(l.HTML, l.XHTML);\n }\n /** Returns whether this media type is of a bitmap image, so excluding vectorial formats. */\n get isBitmap() {\n return this.matchesAny(\n l.AVIF,\n l.BMP,\n l.GIF,\n l.JPEG,\n l.PNG,\n l.TIFF,\n l.WEBP\n );\n }\n /** Returns whether this media type is of an audio clip. */\n get isAudio() {\n return this.type === "audio";\n }\n /** Returns whether this media type is of a video clip. */\n get isVideo() {\n return this.type === "video";\n }\n /** Returns whether this media type is of a Readium Web Publication Manifest. */\n get isRWPM() {\n return this.matchesAny(\n l.READIUM_AUDIOBOOK_MANIFEST,\n l.DIVINA_MANIFEST,\n l.READIUM_WEBPUB_MANIFEST\n );\n }\n /** Returns whether this media type is of a publication file. */\n get isPublication() {\n return this.matchesAny(\n l.READIUM_AUDIOBOOK,\n l.READIUM_AUDIOBOOK_MANIFEST,\n l.CBZ,\n l.DIVINA,\n l.DIVINA_MANIFEST,\n l.EPUB,\n l.LCP_PROTECTED_AUDIOBOOK,\n l.LCP_PROTECTED_PDF,\n l.LPF,\n l.PDF,\n l.W3C_WPUB_MANIFEST,\n l.READIUM_WEBPUB,\n l.READIUM_WEBPUB_MANIFEST,\n l.ZAB\n );\n }\n // Known Media Types\n static get AAC() {\n return l.parse({ mediaType: "audio/aac", fileExtension: "aac" });\n }\n static get ACSM() {\n return l.parse({\n mediaType: "application/vnd.adobe.adept+xml",\n name: "Adobe Content Server Message",\n fileExtension: "acsm"\n });\n }\n static get AIFF() {\n return l.parse({ mediaType: "audio/aiff", fileExtension: "aiff" });\n }\n static get AVI() {\n return l.parse({\n mediaType: "video/x-msvideo",\n fileExtension: "avi"\n });\n }\n static get AVIF() {\n return l.parse({ mediaType: "image/avif", fileExtension: "avif" });\n }\n static get BINARY() {\n return l.parse({ mediaType: "application/octet-stream" });\n }\n static get BMP() {\n return l.parse({ mediaType: "image/bmp", fileExtension: "bmp" });\n }\n static get CBZ() {\n return l.parse({\n mediaType: "application/vnd.comicbook+zip",\n name: "Comic Book Archive",\n fileExtension: "cbz"\n });\n }\n static get CSS() {\n return l.parse({ mediaType: "text/css", fileExtension: "css" });\n }\n static get DIVINA() {\n return l.parse({\n mediaType: "application/divina+zip",\n name: "Digital Visual Narratives",\n fileExtension: "divina"\n });\n }\n static get DIVINA_MANIFEST() {\n return l.parse({\n mediaType: "application/divina+json",\n name: "Digital Visual Narratives",\n fileExtension: "json"\n });\n }\n static get EPUB() {\n return l.parse({\n mediaType: "application/epub+zip",\n name: "EPUB",\n fileExtension: "epub"\n });\n }\n static get GIF() {\n return l.parse({ mediaType: "image/gif", fileExtension: "gif" });\n }\n static get GZ() {\n return l.parse({\n mediaType: "application/gzip",\n fileExtension: "gz"\n });\n }\n static get HTML() {\n return l.parse({ mediaType: "text/html", fileExtension: "html" });\n }\n static get JAVASCRIPT() {\n return l.parse({\n mediaType: "text/javascript",\n fileExtension: "js"\n });\n }\n static get JPEG() {\n return l.parse({ mediaType: "image/jpeg", fileExtension: "jpeg" });\n }\n static get JSON() {\n return l.parse({ mediaType: "application/json" });\n }\n static get LCP_LICENSE_DOCUMENT() {\n return l.parse({\n mediaType: "application/vnd.readium.lcp.license.v1.0+json",\n name: "LCP License",\n fileExtension: "lcpl"\n });\n }\n static get LCP_PROTECTED_AUDIOBOOK() {\n return l.parse({\n mediaType: "application/audiobook+lcp",\n name: "LCP Protected Audiobook",\n fileExtension: "lcpa"\n });\n }\n static get LCP_PROTECTED_PDF() {\n return l.parse({\n mediaType: "application/pdf+lcp",\n name: "LCP Protected PDF",\n fileExtension: "lcpdf"\n });\n }\n static get LCP_STATUS_DOCUMENT() {\n return l.parse({\n mediaType: "application/vnd.readium.license.status.v1.0+json"\n });\n }\n static get LPF() {\n return l.parse({\n mediaType: "application/lpf+zip",\n fileExtension: "lpf"\n });\n }\n static get MP3() {\n return l.parse({ mediaType: "audio/mpeg", fileExtension: "mp3" });\n }\n static get MPEG() {\n return l.parse({ mediaType: "video/mpeg", fileExtension: "mpeg" });\n }\n static get NCX() {\n return l.parse({\n mediaType: "application/x-dtbncx+xml",\n fileExtension: "ncx"\n });\n }\n static get OGG() {\n return l.parse({ mediaType: "audio/ogg", fileExtension: "oga" });\n }\n static get OGV() {\n return l.parse({ mediaType: "video/ogg", fileExtension: "ogv" });\n }\n static get OPDS1() {\n return l.parse({\n mediaType: "application/atom+xml;profile=opds-catalog"\n });\n }\n static get OPDS1_ENTRY() {\n return l.parse({\n mediaType: "application/atom+xml;type=entry;profile=opds-catalog"\n });\n }\n static get OPDS2() {\n return l.parse({ mediaType: "application/opds+json" });\n }\n static get OPDS2_PUBLICATION() {\n return l.parse({ mediaType: "application/opds-publication+json" });\n }\n static get OPDS_AUTHENTICATION() {\n return l.parse({\n mediaType: "application/opds-authentication+json"\n });\n }\n static get OPUS() {\n return l.parse({ mediaType: "audio/opus", fileExtension: "opus" });\n }\n static get OTF() {\n return l.parse({ mediaType: "font/otf", fileExtension: "otf" });\n }\n static get PDF() {\n return l.parse({\n mediaType: "application/pdf",\n name: "PDF",\n fileExtension: "pdf"\n });\n }\n static get PNG() {\n return l.parse({ mediaType: "image/png", fileExtension: "png" });\n }\n static get READIUM_AUDIOBOOK() {\n return l.parse({\n mediaType: "application/audiobook+zip",\n name: "Readium Audiobook",\n fileExtension: "audiobook"\n });\n }\n static get READIUM_AUDIOBOOK_MANIFEST() {\n return l.parse({\n mediaType: "application/audiobook+json",\n name: "Readium Audiobook",\n fileExtension: "json"\n });\n }\n static get READIUM_CONTENT_DOCUMENT() {\n return l.parse({\n mediaType: "application/vnd.readium.content+json",\n name: "Readium Content Document",\n fileExtension: "json"\n });\n }\n static get READIUM_GUIDED_NAVIGATION_DOCUMENT() {\n return l.parse({\n mediaType: "application/guided-navigation+json",\n name: "Readium Guided Navigation Document",\n fileExtension: "json"\n });\n }\n static get READIUM_POSITION_LIST() {\n return l.parse({\n mediaType: "application/vnd.readium.position-list+json",\n name: "Readium Position List",\n fileExtension: "json"\n });\n }\n static get READIUM_WEBPUB() {\n return l.parse({\n mediaType: "application/webpub+zip",\n name: "Readium Web Publication",\n fileExtension: "webpub"\n });\n }\n static get READIUM_WEBPUB_MANIFEST() {\n return l.parse({\n mediaType: "application/webpub+json",\n name: "Readium Web Publication",\n fileExtension: "json"\n });\n }\n static get SMIL() {\n return l.parse({\n mediaType: "application/smil+xml",\n fileExtension: "smil"\n });\n }\n static get SVG() {\n return l.parse({\n mediaType: "image/svg+xml",\n fileExtension: "svg"\n });\n }\n static get TEXT() {\n return l.parse({ mediaType: "text/plain", fileExtension: "txt" });\n }\n static get TIFF() {\n return l.parse({ mediaType: "image/tiff", fileExtension: "tiff" });\n }\n static get TTF() {\n return l.parse({ mediaType: "font/ttf", fileExtension: "ttf" });\n }\n static get W3C_WPUB_MANIFEST() {\n return l.parse({\n mediaType: "application/x.readium.w3c.wpub+json",\n name: "Web Publication",\n fileExtension: "json"\n });\n }\n static get WAV() {\n return l.parse({ mediaType: "audio/wav", fileExtension: "wav" });\n }\n static get WEBM_AUDIO() {\n return l.parse({ mediaType: "audio/webm", fileExtension: "webm" });\n }\n static get WEBM_VIDEO() {\n return l.parse({ mediaType: "video/webm", fileExtension: "webm" });\n }\n static get WEBP() {\n return l.parse({ mediaType: "image/webp", fileExtension: "webp" });\n }\n static get WOFF() {\n return l.parse({ mediaType: "font/woff", fileExtension: "woff" });\n }\n static get WOFF2() {\n return l.parse({ mediaType: "font/woff2", fileExtension: "woff2" });\n }\n static get XHTML() {\n return l.parse({\n mediaType: "application/xhtml+xml",\n fileExtension: "xhtml"\n });\n }\n static get XML() {\n return l.parse({\n mediaType: "application/xml",\n fileExtension: "xml"\n });\n }\n static get ZAB() {\n return l.parse({\n mediaType: "application/x.readium.zab+zip",\n name: "Zipped Audio Book",\n fileExtension: "zab"\n });\n }\n static get ZIP() {\n return l.parse({\n mediaType: "application/zip",\n fileExtension: "zip"\n });\n }\n}\nclass se {\n constructor(t) {\n this.uri = t, this.parameters = this.getParameters(t);\n }\n /**\n * List of URI template parameter keys, if the [Link] is templated.\n */\n getParameters(t) {\n const e = /\\{\\??([^}]+)\\}/g, i = t.match(e);\n return i ? new Set(\n i.join(",").replace(e, "$1").split(",").map((s) => s.trim())\n ) : /* @__PURE__ */ new Set();\n }\n /** Expands the URI by replacing the template variables by the given parameters.\n * Any extra parameter is appended as query parameters.\n * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570\n */\n expand(t) {\n const e = (s) => s.split(",").map((r) => {\n const o = t[r];\n return o ? encodeURIComponent(o) : "";\n }).join(","), i = (s) => "?" + s.split(",").map((r) => {\n const o = r.split("=")[0], a = t[o];\n return a ? `${o}=${encodeURIComponent(a)}` : "";\n }).join("&");\n return this.uri.replace(/\\{(\\??)([^}]+)\\}/g, (...s) => s[1] ? i(s[2]) : e(s[2]));\n }\n}\nclass C {\n /**\n * Creates a [Locations].\n */\n constructor(t) {\n this.fragments = t.fragments ? t.fragments : new Array(), this.progression = t.progression, this.totalProgression = t.totalProgression, this.position = t.position, this.otherLocations = t.otherLocations;\n }\n /**\n * Parses a [Locations] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n const e = ht(t.progression), i = ht(t.totalProgression), s = ht(t.position), r = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set([\n "fragment",\n "fragments",\n "progression",\n "totalProgression",\n "position"\n ]);\n return Object.entries(t).forEach(([a, c]) => {\n o.has(a) || r.set(a, c);\n }), new C({\n fragments: Ce(t.fragments || t.fragment),\n progression: e !== void 0 && e >= 0 && e <= 1 ? e : void 0,\n totalProgression: i !== void 0 && i >= 0 && i <= 1 ? i : void 0,\n position: s !== void 0 && s > 0 ? s : void 0,\n otherLocations: r.size === 0 ? void 0 : r\n });\n }\n /**\n * Serializes a [Locations] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.fragments && (t.fragments = this.fragments), this.progression !== void 0 && (t.progression = this.progression), this.totalProgression !== void 0 && (t.totalProgression = this.totalProgression), this.position !== void 0 && (t.position = this.position), this.otherLocations && this.otherLocations.forEach((e, i) => t[i] = e), t;\n }\n}\nclass H {\n /**\n * Creates a [Text].\n */\n constructor(t) {\n this.after = t.after, this.before = t.before, this.highlight = t.highlight;\n }\n /**\n * Parses a [Locations] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new H({\n after: t.after,\n before: t.before,\n highlight: t.highlight\n });\n }\n /**\n * Serializes a [Locations] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.after !== void 0 && (t.after = this.after), this.before !== void 0 && (t.before = this.before), this.highlight !== void 0 && (t.highlight = this.highlight), t;\n }\n}\nclass k {\n /**\n * Creates a [Locator].\n */\n constructor(t) {\n this.href = t.href, this.type = t.type, this.title = t.title, this.locations = t.locations ? t.locations : new C({}), this.text = t.text;\n }\n /**\n * Parses a [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.href && t.type)\n return new k({\n href: t.href,\n type: t.type,\n title: t.title,\n locations: C.deserialize(t.locations),\n text: H.deserialize(t.text)\n });\n }\n /**\n * Serializes a [Link] to its RWPM JSON representation.\n */\n serialize() {\n const t = { href: this.href, type: this.type };\n return this.title !== void 0 && (t.title = this.title), this.locations && (t.locations = this.locations.serialize()), this.text && (t.text = this.text.serialize()), t;\n }\n /**\n * Shortcut to get a copy of the [Locator] with different [Locations] sub-properties.\n */\n copyWithLocations(t) {\n return new k({\n href: this.href,\n type: this.type,\n title: this.title,\n text: this.text,\n locations: new C({ ...this.locations, ...t })\n });\n }\n}\nclass q {\n /**\n * Creates a [Link].\n */\n constructor(t) {\n this.href = t.href, this.templated = t.templated, this.type = t.type, this.title = t.title, this.rels = t.rels, this.properties = t.properties, this.height = t.height, this.width = t.width, this.size = t.size, this.duration = t.duration, this.bitrate = t.bitrate, this.languages = t.languages, this.alternates = t.alternates, this.children = t.children;\n }\n /**\n * Parses a [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t.href != "string"))\n return new q({\n href: t.href,\n templated: t.templated,\n type: t.type,\n title: t.title,\n rels: t.rel ? Array.isArray(t.rel) ? new Set(t.rel) : /* @__PURE__ */ new Set([t.rel]) : void 0,\n properties: R.deserialize(t.properties),\n height: O(t.height),\n width: O(t.width),\n size: O(t.size),\n duration: O(t.duration),\n bitrate: O(t.bitrate),\n languages: Ce(t.language),\n alternates: dt.deserialize(t.alternate),\n children: dt.deserialize(t.children)\n });\n }\n /**\n * Serializes a [Link] to its RWPM JSON representation.\n */\n serialize() {\n const t = { href: this.href };\n return this.templated !== void 0 && (t.templated = this.templated), this.type !== void 0 && (t.type = this.type), this.title !== void 0 && (t.title = this.title), this.rels && (t.rel = Fe(this.rels)), this.properties && (t.properties = this.properties.serialize()), this.height !== void 0 && (t.height = this.height), this.width !== void 0 && (t.width = this.width), this.size !== void 0 && (t.size = this.size), this.duration !== void 0 && (t.duration = this.duration), this.bitrate !== void 0 && (t.bitrate = this.bitrate), this.languages && (t.language = this.languages), this.alternates && (t.alternate = this.alternates.serialize()), this.children && (t.children = this.children.serialize()), t;\n }\n /** MediaType of the linked resource. */\n get mediaType() {\n return this.type !== void 0 ? l.parse({ mediaType: this.type }) : l.BINARY;\n }\n /** Computes an absolute URL to the link, relative to the given `baseURL`.\n * If the link\'s `href` is already absolute, the `baseURL` is ignored.\n */\n toURL(t) {\n const e = this.href.replace(/^(\\/)/, "");\n if (e.length === 0) return;\n let i = t || "/";\n return i.startsWith("/") && (i = "file://" + i), new URL(e, i).href.replace(/^(file:\\/\\/)/, "");\n }\n /** List of URI template parameter keys, if the `Link` is templated. */\n get templateParameters() {\n return this.templated ? new se(this.href).parameters : /* @__PURE__ */ new Set();\n }\n /** Expands the `Link`\'s HREF by replacing URI template variables by the given parameters.\n * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570\n */\n expandTemplate(t) {\n return new q({\n href: new se(this.href).expand(t),\n templated: !1\n });\n }\n /**\n * Makes a copy of this [Link] after merging in the given additional other [properties].\n */\n addProperties(t) {\n const e = q.deserialize(this.serialize());\n return e.properties = e.properties ? e.properties?.add(t) : new R(t), e;\n }\n /**\n * Creates a [Locator] from a reading order [Link].\n */\n get locator() {\n let t = this.href.split("#");\n return new k({\n href: t.length > 0 && t[0] !== void 0 ? t[0] : this.href,\n type: this.type ?? "",\n title: this.title,\n locations: new C({\n fragments: t.length > 1 && t[1] !== void 0 ? [t[1]] : []\n })\n });\n }\n}\nclass dt {\n /**\n * Creates a [Links].\n */\n constructor(t) {\n this.items = t;\n }\n /**\n * Creates a list of [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && Array.isArray(t))\n return new dt(\n t.map((e) => q.deserialize(e)).filter((e) => e !== void 0)\n );\n }\n /**\n * Serializes an array of [Link] to its RWPM JSON representation.\n */\n serialize() {\n return this.items.map((t) => t.serialize());\n }\n /** Finds the first link with the given relation. */\n findWithRel(t) {\n const e = (i) => i.rels && i.rels.has(t);\n return this.items.find(e);\n }\n /** Finds all the links with the given relation. */\n filterByRel(t) {\n const e = (i) => i.rels && i.rels.has(t);\n return this.items.filter(e);\n }\n /** Finds the first link matching the given HREF. */\n findWithHref(t) {\n const e = (i) => i.href === t;\n return this.items.find(e);\n }\n /** Finds the index of the first link matching the given HREF. */\n findIndexWithHref(t) {\n const e = (i) => i.href === t;\n return this.items.findIndex(e);\n }\n /** Finds the first link matching the given media type. */\n findWithMediaType(t) {\n const e = (i) => i.mediaType.matches(t);\n return this.items.find(e);\n }\n /** Finds all the links matching the given media type. */\n filterByMediaType(t) {\n const e = (i) => i.mediaType.matches(t);\n return this.items.filter(e);\n }\n /** Finds all the links matching any of the given media types. */\n filterByMediaTypes(t) {\n const e = (i) => {\n for (const s of t)\n if (i.mediaType.matches(s))\n return !0;\n return !1;\n };\n return this.items.filter(e);\n }\n /** Returns whether all the resources in the collection are audio clips. */\n everyIsAudio() {\n const t = (e) => e.mediaType.isAudio;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are bitmaps. */\n everyIsBitmap() {\n const t = (e) => e.mediaType.isBitmap;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are HTML documents. */\n everyIsHTML() {\n const t = (e) => e.mediaType.isHTML;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are video clips. */\n everyIsVideo() {\n const t = (e) => e.mediaType.isVideo;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are matching any of the given media types. */\n everyMatchesMediaType(t) {\n return Array.isArray(t) ? this.items.length > 0 && this.items.every((e) => {\n for (const i of t)\n return e.mediaType.matches(i);\n return !1;\n }) : this.items.length > 0 && this.items.every((e) => e.mediaType.matches(t));\n }\n filterLinksHasType() {\n return this.items.filter((t) => t.type);\n }\n}\nR.prototype.getContains = function() {\n return new Set(this.otherProperties.contains || []);\n};\nclass ut {\n /**\n * Creates a [DomRange].\n */\n constructor(t) {\n this.cssSelector = t.cssSelector, this.textNodeIndex = t.textNodeIndex, this.charOffset = t.charOffset;\n }\n /**\n * Parses a [DomRangePoint] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(t && t.cssSelector)) return;\n let e = O(t.textNodeIndex);\n if (e === void 0) return;\n let i = O(t.charOffset);\n return i === void 0 && (i = O(t.offset)), new ut({\n cssSelector: t.cssSelector,\n textNodeIndex: e,\n charOffset: i\n });\n }\n /**\n * Serializes a [DomRangePoint] to its RWPM JSON representation.\n */\n serialize() {\n const t = {\n cssSelector: this.cssSelector,\n textNodeIndex: this.textNodeIndex\n };\n return this.charOffset !== void 0 && (t.charOffset = this.charOffset), t;\n }\n}\nclass Wt {\n /**\n * Creates a [DomRange].\n */\n constructor(t) {\n this.start = t.start, this.end = t.end;\n }\n /**\n * Parses a [DomRange] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n let e = ut.deserialize(t.start);\n if (e)\n return new Wt({\n start: e,\n end: ut.deserialize(t.end)\n });\n }\n /**\n * Serializes a [DomRange] to its RWPM JSON representation.\n */\n serialize() {\n const t = { start: this.start.serialize() };\n return this.end && (t.end = this.end.serialize()), t;\n }\n}\nC.prototype.getCssSelector = function() {\n return this.otherLocations?.get("cssSelector");\n};\nC.prototype.getPartialCfi = function() {\n return this.otherLocations?.get("partialCfi");\n};\nC.prototype.getDomRange = function() {\n return Wt.deserialize(this.otherLocations?.get("domRange"));\n};\nC.prototype.fragmentParameters = function() {\n return new Map(\n this.fragments.map((n) => n.startsWith("#") ? n.slice(1) : n).join("&").split("&").filter((n) => !n.startsWith("#")).map((n) => n.split("=")).filter((n) => n.length === 2).map((n) => [\n n[0].trim().toLowerCase(),\n n[1].trim()\n ])\n );\n};\nC.prototype.htmlId = function() {\n if (!this.fragments.length) return;\n let n = this.fragments.find((t) => t.length && !t.includes("="));\n if (!n) {\n const t = this.fragmentParameters();\n t.has("id") ? n = t.get("id") : t.has("name") && (n = t.get("name"));\n }\n return n?.startsWith("#") ? n.slice(1) : n;\n};\nC.prototype.page = function() {\n const n = parseInt(this.fragmentParameters().get("page"));\n if (!isNaN(n) && n >= 0) return n;\n};\nC.prototype.time = function() {\n const n = parseInt(this.fragmentParameters().get("t"));\n if (!isNaN(n)) return n;\n};\nC.prototype.space = function() {\n const n = this.fragmentParameters();\n if (!n.has("xywh")) return;\n const t = n.get("xywh").split(",").map((e) => parseInt(e));\n if (t.length === 4 && !t.some(isNaN))\n return t;\n};\nclass Ut {\n /** Creates a [Price]. */\n constructor(t) {\n this.currency = t.currency, this.value = t.value;\n }\n /**\n * Parses a [Price] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n let e = t.currency;\n if (!(e && typeof e == "string" && e.length > 0))\n return;\n let i = O(t.value);\n if (i !== void 0)\n return new Ut({ currency: e, value: i });\n }\n /**\n * Serializes a [Price] to its RWPM JSON representation.\n */\n serialize() {\n return { currency: this.currency, value: this.value };\n }\n}\nclass Q {\n /** Creates a [Acquisition]. */\n constructor(t) {\n this.type = t.type, this.children = t.children;\n }\n /**\n * Parses a [Acquisition] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.type)\n return new Q({\n type: t.type,\n children: Q.deserializeArray(t.children)\n });\n }\n static deserializeArray(t) {\n if (Array.isArray(t))\n return t.map((e) => Q.deserialize(e)).filter((e) => e !== void 0);\n }\n /**\n * Serializes a [Acquisition] to its RWPM JSON representation.\n */\n serialize() {\n const t = { type: this.type };\n return this.children && (t.children = this.children.map((e) => e.serialize())), t;\n }\n}\nclass Bt {\n /** Creates a [Price]. */\n constructor(t) {\n this.total = t.total, this.position = t.position;\n }\n /**\n * Parses a [Holds] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new Bt({\n total: O(t.total),\n position: O(t.position)\n });\n }\n /**\n * Serializes a [Holds] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.total !== void 0 && (t.total = this.total), this.position !== void 0 && (t.position = this.position), t;\n }\n}\nclass Ht {\n /** Creates a [Copies]. */\n constructor(t) {\n this.total = t.total, this.available = t.available;\n }\n /**\n * Parses a [Copies] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new Ht({\n total: O(t.total),\n available: O(t.available)\n });\n }\n /**\n * Serializes a [Copies] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.total !== void 0 && (t.total = this.total), this.available !== void 0 && (t.available = this.available), t;\n }\n}\nclass _t {\n /** Creates a [Availability]. */\n constructor(t) {\n this.state = t.state, this.since = t.since, this.until = t.until;\n }\n /**\n * Parses a [Availability] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.state)\n return new _t({\n state: t.state,\n since: ie(t.since),\n until: ie(t.until)\n });\n }\n /**\n * Serializes a [Availability] to its RWPM JSON representation.\n */\n serialize() {\n const t = { state: this.state };\n return this.since !== void 0 && (t.since = this.since.toISOString()), this.until !== void 0 && (t.until = this.until.toISOString()), t;\n }\n}\nR.prototype.getNumberOfItems = function() {\n return O(this.otherProperties.numberOfItems);\n};\nR.prototype.getPrice = function() {\n return Ut.deserialize(this.otherProperties.price);\n};\nR.prototype.getIndirectAcquisitions = function() {\n const n = this.otherProperties.indirectAcquisition;\n if (n && Array.isArray(n))\n return n.map((t) => Q.deserialize(t)).filter((t) => t !== void 0);\n};\nR.prototype.getHolds = function() {\n return Bt.deserialize(this.otherProperties.holds);\n};\nR.prototype.getCopies = function() {\n return Ht.deserialize(this.otherProperties.copies);\n};\nR.prototype.getAvailability = function() {\n return _t.deserialize(this.otherProperties.availability);\n};\nR.prototype.getAuthenticate = function() {\n return q.deserialize(this.otherProperties.authenticate);\n};\nconst Ge = "CssSelectorGenerator";\nfunction re(n = "unknown problem", ...t) {\n console.warn(`${Ge}: ${n}`, ...t);\n}\nfunction $e(n) {\n return n instanceof RegExp;\n}\nfunction Ye(n) {\n return n.replace(/[|\\\\{}()[\\]^$+?.]/g, "\\\\$&").replace(/\\*/g, ".+");\n}\nfunction qe(n) {\n const t = n.map((e) => {\n if ($e(e))\n return (i) => e.test(i);\n if (typeof e == "function")\n return (i) => {\n const s = e(i);\n return typeof s != "boolean" ? (re("pattern matcher function invalid", "Provided pattern matching function does not return boolean. It\'s result will be ignored.", e), !1) : s;\n };\n if (typeof e == "string") {\n const i = new RegExp("^" + Ye(e) + "$");\n return (s) => i.test(s);\n }\n return re("pattern matcher invalid", "Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.", e), () => !1;\n });\n return (e) => t.some((i) => i(e));\n}\nqe([\n "class",\n "id",\n // Angular attributes\n "ng-*"\n]);\nclass K {\n}\nfunction ne(n) {\n return n.split("").reverse().join("");\n}\nfunction Xe(n, t, e) {\n const i = ne(t);\n return e.map((s) => {\n const r = Math.max(0, s.end - t.length - s.errors), o = ne(n.slice(r, s.end));\n return {\n start: xe(o, i, s.errors).reduce((c, u) => s.end - u.end < c ? s.end - u.end : c, s.end),\n end: s.end,\n errors: s.errors\n };\n });\n}\nfunction vt(n) {\n return (n | -n) >> 31 & 1;\n}\nfunction oe(n, t, e, i) {\n let s = n.P[e], r = n.M[e];\n const o = i >>> 31, a = t[e] | o, c = a | r, u = (a & s) + s ^ s | a;\n let d = r | ~(u | s), f = s & u;\n const p = vt(d & n.lastRowMask[e]) - vt(f & n.lastRowMask[e]);\n return d <<= 1, f <<= 1, f |= o, d |= vt(i) - o, s = f | ~(c | d), r = d & c, n.P[e] = s, n.M[e] = r, p;\n}\nfunction xe(n, t, e) {\n if (t.length === 0)\n return [];\n e = Math.min(e, t.length);\n const i = [], s = 32, r = Math.ceil(t.length / s) - 1, o = {\n P: new Uint32Array(r + 1),\n M: new Uint32Array(r + 1),\n lastRowMask: new Uint32Array(r + 1)\n };\n o.lastRowMask.fill(1 << 31), o.lastRowMask[r] = 1 << (t.length - 1) % s;\n const a = new Uint32Array(r + 1), c = /* @__PURE__ */ new Map(), u = [];\n for (let p = 0; p < 256; p++)\n u.push(a);\n for (let p = 0; p < t.length; p += 1) {\n const v = t.charCodeAt(p);\n if (c.has(v))\n continue;\n const g = new Uint32Array(r + 1);\n c.set(v, g), v < u.length && (u[v] = g);\n for (let m = 0; m <= r; m += 1) {\n g[m] = 0;\n for (let b = 0; b < s; b += 1) {\n const D = m * s + b;\n if (D >= t.length)\n continue;\n t.charCodeAt(D) === v && (g[m] |= 1 << b);\n }\n }\n }\n let d = Math.max(0, Math.ceil(e / s) - 1);\n const f = new Uint32Array(r + 1);\n for (let p = 0; p <= d; p += 1)\n f[p] = (p + 1) * s;\n f[r] = t.length;\n for (let p = 0; p <= d; p += 1)\n o.P[p] = -1, o.M[p] = 0;\n for (let p = 0; p < n.length; p += 1) {\n const v = n.charCodeAt(p);\n let g;\n v < u.length ? g = u[v] : (g = c.get(v), typeof g > "u" && (g = a));\n let m = 0;\n for (let b = 0; b <= d; b += 1)\n m = oe(o, g, b, m), f[b] += m;\n if (f[d] - m <= e && d < r && (g[d + 1] & 1 || m < 0)) {\n d += 1, o.P[d] = -1, o.M[d] = 0;\n let b;\n if (d === r) {\n const D = t.length % s;\n b = D === 0 ? s : D;\n } else\n b = s;\n f[d] = f[d - 1] + b - m + oe(o, g, d, m);\n } else\n for (; d > 0 && f[d] >= e + s; )\n d -= 1;\n d === r && f[d] <= e && (f[d] < e && i.splice(0, i.length), i.push({\n start: -1,\n end: p + 1,\n errors: f[d]\n }), e = f[d]);\n }\n return i;\n}\nfunction Ke(n, t, e) {\n const i = xe(n, t, e);\n return Xe(n, t, i);\n}\nfunction Te(n, t, e) {\n let i = 0;\n const s = [];\n for (; i !== -1; )\n i = n.indexOf(t, i), i !== -1 && (s.push({\n start: i,\n end: i + t.length,\n errors: 0\n }), i += 1);\n return s.length > 0 ? s : Ke(n, t, e);\n}\nfunction ae(n, t) {\n return t.length === 0 || n.length === 0 ? 0 : 1 - Te(n, t, t.length)[0].errors / t.length;\n}\nfunction Ze(n, t, e = {}) {\n if (t.length === 0)\n return null;\n const i = Math.min(256, t.length / 2), s = Te(n, t, i);\n if (s.length === 0)\n return null;\n const r = (a) => {\n const p = 1 - a.errors / t.length, v = e.prefix ? ae(\n n.slice(\n Math.max(0, a.start - e.prefix.length),\n a.start\n ),\n e.prefix\n ) : 1, g = e.suffix ? ae(\n n.slice(a.end, a.end + e.suffix.length),\n e.suffix\n ) : 1;\n let m = 1;\n return typeof e.hint == "number" && (m = 1 - Math.abs(a.start - e.hint) / n.length), (50 * p + 20 * v + 20 * g + 2 * m) / 92;\n }, o = s.map((a) => ({\n start: a.start,\n end: a.end,\n score: r(a)\n }));\n return o.sort((a, c) => c.score - a.score), o[0];\n}\nfunction At(n, t, e) {\n const i = e === 1 ? t : t - 1;\n if (n.charAt(i).trim() !== "")\n return t;\n let s, r;\n if (e === 2 ? (s = n.substring(0, t), r = s.trimEnd()) : (s = n.substring(t), r = s.trimStart()), !r.length)\n return -1;\n const o = s.length - r.length;\n return e === 2 ? t - o : t + o;\n}\nfunction le(n, t) {\n const e = n.commonAncestorContainer.ownerDocument.createNodeIterator(\n n.commonAncestorContainer,\n NodeFilter.SHOW_TEXT\n ), i = t === 1 ? n.startContainer : n.endContainer, s = t === 1 ? n.endContainer : n.startContainer;\n let r = e.nextNode();\n for (; r && r !== i; )\n r = e.nextNode();\n t === 2 && (r = e.previousNode());\n let o = -1;\n const a = () => {\n if (r = t === 1 ? e.nextNode() : e.previousNode(), r) {\n const c = r.textContent, u = t === 1 ? 0 : c.length;\n o = At(c, u, t);\n }\n };\n for (; r && o === -1 && r !== s; )\n a();\n if (r && o >= 0)\n return { node: r, offset: o };\n throw new RangeError("No text nodes with non-whitespace text found in range");\n}\nfunction Je(n) {\n if (!n.toString().trim().length)\n throw new RangeError("Range contains no non-whitespace text");\n if (n.startContainer.nodeType !== Node.TEXT_NODE)\n throw new RangeError("Range startContainer is not a text node");\n if (n.endContainer.nodeType !== Node.TEXT_NODE)\n throw new RangeError("Range endContainer is not a text node");\n const t = n.cloneRange();\n let e = !1, i = !1;\n const s = {\n start: At(\n n.startContainer.textContent,\n n.startOffset,\n 1\n /* Forwards */\n ),\n end: At(\n n.endContainer.textContent,\n n.endOffset,\n 2\n /* Backwards */\n )\n };\n if (s.start >= 0 && (t.setStart(n.startContainer, s.start), e = !0), s.end > 0 && (t.setEnd(n.endContainer, s.end), i = !0), e && i)\n return t;\n if (!e) {\n const { node: r, offset: o } = le(\n t,\n 1\n /* Forwards */\n );\n r && o >= 0 && t.setStart(r, o);\n }\n if (!i) {\n const { node: r, offset: o } = le(\n t,\n 2\n /* Backwards */\n );\n r && o > 0 && t.setEnd(r, o);\n }\n return t;\n}\nfunction Pe(n) {\n switch (n.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.TEXT_NODE:\n return n.textContent?.length ?? 0;\n default:\n return 0;\n }\n}\nfunction ce(n) {\n let t = n.previousSibling, e = 0;\n for (; t; )\n e += Pe(t), t = t.previousSibling;\n return e;\n}\nfunction Ne(n, ...t) {\n let e = t.shift();\n const i = n.ownerDocument.createNodeIterator(\n n,\n NodeFilter.SHOW_TEXT\n ), s = [];\n let r = i.nextNode(), o, a = 0;\n for (; e !== void 0 && r; )\n o = r, a + o.data.length > e ? (s.push({ node: o, offset: e - a }), e = t.shift()) : (r = i.nextNode(), a += o.data.length);\n for (; e !== void 0 && o && a === e; )\n s.push({ node: o, offset: o.data.length }), e = t.shift();\n if (e !== void 0)\n throw new RangeError("Offset exceeds text length");\n return s;\n}\nclass M {\n constructor(t, e) {\n if (e < 0)\n throw new Error("Offset is invalid");\n this.element = t, this.offset = e;\n }\n /**\n * Return a copy of this position with offset relative to a given ancestor\n * element.\n *\n * @param parent - Ancestor of `this.element`\n */\n relativeTo(t) {\n if (!t.contains(this.element))\n throw new Error("Parent is not an ancestor of current element");\n let e = this.element, i = this.offset;\n for (; e !== t; )\n i += ce(e), e = e.parentElement;\n return new M(e, i);\n }\n /**\n * Resolve the position to a specific text node and offset within that node.\n *\n * Throws if `this.offset` exceeds the length of the element\'s text. In the\n * case where the element has no text and `this.offset` is 0, the `direction`\n * option determines what happens.\n *\n * Offsets at the boundary between two nodes are resolved to the start of the\n * node that begins at the boundary.\n *\n * @param options.direction - Specifies in which direction to search for the\n * nearest text node if `this.offset` is `0` and\n * `this.element` has no text. If not specified an\n * error is thrown.\n *\n * @throws {RangeError}\n */\n resolve(t = {}) {\n try {\n return Ne(this.element, this.offset)[0];\n } catch (e) {\n if (this.offset === 0 && t.direction !== void 0) {\n const i = document.createTreeWalker(\n this.element.getRootNode(),\n NodeFilter.SHOW_TEXT\n );\n i.currentNode = this.element;\n const s = t.direction === 1, r = s ? i.nextNode() : i.previousNode();\n if (!r)\n throw e;\n return { node: r, offset: s ? 0 : r.data.length };\n } else\n throw e;\n }\n }\n /**\n * Construct a `TextPosition` that refers to the `offset`th character within\n * `node`.\n */\n static fromCharOffset(t, e) {\n switch (t.nodeType) {\n case Node.TEXT_NODE:\n return M.fromPoint(t, e);\n case Node.ELEMENT_NODE:\n return new M(t, e);\n default:\n throw new Error("Node is not an element or text node");\n }\n }\n /**\n * Construct a `TextPosition` representing the range start or end point (node, offset).\n *\n * @param node\n * @param offset - Offset within the node\n */\n static fromPoint(t, e) {\n switch (t.nodeType) {\n case Node.TEXT_NODE: {\n if (e < 0 || e > t.data.length)\n throw new Error("Text node offset is out of range");\n if (!t.parentElement)\n throw new Error("Text node has no parent");\n const i = ce(t) + e;\n return new M(t.parentElement, i);\n }\n case Node.ELEMENT_NODE: {\n if (e < 0 || e > t.childNodes.length)\n throw new Error("Child node offset is out of range");\n let i = 0;\n for (let s = 0; s < e; s++)\n i += Pe(t.childNodes[s]);\n return new M(t, i);\n }\n default:\n throw new Error("Point is not in an element or text node");\n }\n }\n}\nclass B {\n constructor(t, e) {\n this.start = t, this.end = e;\n }\n /**\n * Create a new TextRange whose `start` and `end` are computed relative to\n * `element`. `element` must be an ancestor of both `start.element` and\n * `end.element`.\n */\n relativeTo(t) {\n return new B(\n this.start.relativeTo(t),\n this.end.relativeTo(t)\n );\n }\n /**\n * Resolve this TextRange to a (DOM) Range.\n *\n * The resulting DOM Range will always start and end in a `Text` node.\n * Hence `TextRange.fromRange(range).toRange()` can be used to "shrink" a\n * range to the text it contains.\n *\n * May throw if the `start` or `end` positions cannot be resolved to a range.\n */\n toRange() {\n let t, e;\n this.start.element === this.end.element && this.start.offset <= this.end.offset ? [t, e] = Ne(\n this.start.element,\n this.start.offset,\n this.end.offset\n ) : (t = this.start.resolve({\n direction: 1\n /* FORWARDS */\n }), e = this.end.resolve({\n direction: 2\n /* BACKWARDS */\n }));\n const i = new Range();\n return i.setStart(t.node, t.offset), i.setEnd(e.node, e.offset), i;\n }\n /**\n * Create a TextRange from a (DOM) Range\n */\n static fromRange(t) {\n const e = M.fromPoint(\n t.startContainer,\n t.startOffset\n ), i = M.fromPoint(t.endContainer, t.endOffset);\n return new B(e, i);\n }\n /**\n * Create a TextRange representing the `start`th to `end`th characters in\n * `root`\n */\n static fromOffsets(t, e, i) {\n return new B(\n new M(t, e),\n new M(t, i)\n );\n }\n /**\n * Return a new Range representing `range` trimmed of any leading or trailing\n * whitespace\n */\n static trimmedRange(t) {\n return Je(B.fromRange(t).toRange());\n }\n}\nclass pt {\n constructor(t, e, i) {\n this.root = t, this.start = e, this.end = i;\n }\n static fromRange(t, e) {\n const i = B.fromRange(e).relativeTo(t);\n return new pt(\n t,\n i.start.offset,\n i.end.offset\n );\n }\n static fromSelector(t, e) {\n return new pt(t, e.start, e.end);\n }\n toSelector() {\n return {\n type: "TextPositionSelector",\n start: this.start,\n end: this.end\n };\n }\n toRange() {\n return B.fromOffsets(this.root, this.start, this.end).toRange();\n }\n}\nclass mt {\n /**\n * @param root - A root element from which to anchor.\n */\n constructor(t, e, i = {}) {\n this.root = t, this.exact = e, this.context = i;\n }\n /**\n * Create a `TextQuoteAnchor` from a range.\n *\n * Will throw if `range` does not contain any text nodes.\n */\n static fromRange(t, e) {\n const i = t.textContent, s = B.fromRange(e).relativeTo(t), r = s.start.offset, o = s.end.offset, a = 32;\n return new mt(t, i.slice(r, o), {\n prefix: i.slice(Math.max(0, r - a), r),\n suffix: i.slice(o, Math.min(i.length, o + a))\n });\n }\n static fromSelector(t, e) {\n const { prefix: i, suffix: s } = e;\n return new mt(t, e.exact, { prefix: i, suffix: s });\n }\n toSelector() {\n return {\n type: "TextQuoteSelector",\n exact: this.exact,\n prefix: this.context.prefix,\n suffix: this.context.suffix\n };\n }\n toRange(t = {}) {\n return this.toPositionAnchor(t).toRange();\n }\n toPositionAnchor(t = {}) {\n const e = this.root.textContent, i = Ze(e, this.exact, {\n ...this.context,\n hint: t.hint\n });\n if (!i)\n throw new Error("Quote not found");\n return new pt(this.root, i.start, i.end);\n }\n}\nfunction Qe(n) {\n const t = n.tagName.toUpperCase();\n return t === "IMG" || t === "VIDEO" || t === "AUDIO" || t === "IFRAME" || t === "OBJECT" || t === "EMBED" || t === "CANVAS";\n}\nfunction rt(n, t) {\n try {\n const e = t.locations, i = t.text;\n if (i && i.highlight) {\n let s;\n e && e.getCssSelector() && (s = n.querySelector(e.getCssSelector())), s || (s = n.body);\n const r = new mt(s, i.highlight, {\n prefix: i.before,\n suffix: i.after\n });\n try {\n return r.toRange();\n } catch {\n return console.warn("Quote not found:", r), null;\n }\n }\n if (e) {\n let s = null;\n if (!s && e.getCssSelector() && (s = n.querySelector(e.getCssSelector())), !s && e.fragments) {\n for (const r of e.fragments)\n if (s = n.getElementById(r), s)\n break;\n }\n if (s) {\n const r = n.createRange();\n return s.childNodes.length === 0 || Qe(s) ? (r.selectNode(s), r) : (r.setStartBefore(s), r.setEndAfter(s), r);\n }\n }\n } catch (e) {\n console.error(e);\n }\n return null;\n}\nfunction je(n, t) {\n let e = n.getClientRects();\n e.length || n.commonAncestorContainer.nodeType === Node.ELEMENT_NODE && (e = n.commonAncestorContainer.getClientRects());\n const i = 1, s = [];\n for (const u of e)\n s.push({\n bottom: u.bottom,\n height: u.height,\n left: u.left,\n right: u.right,\n top: u.top,\n width: u.width\n });\n const r = Le(\n s,\n i\n ), o = ei(r, i), a = Oe(o), c = 4;\n for (let u = a.length - 1; u >= 0; u--) {\n const d = a[u];\n if (!(d.width * d.height > c))\n if (a.length > 1)\n a.splice(u, 1);\n else\n break;\n }\n return a;\n}\nfunction Le(n, t, e) {\n for (let i = 0; i < n.length; i++)\n for (let s = i + 1; s < n.length; s++) {\n const r = n[i], o = n[s];\n if (r === o)\n continue;\n const a = I(r.top, o.top, t) && I(r.bottom, o.bottom, t), c = I(r.left, o.left, t) && I(r.right, o.right, t);\n if (a && !c && Re(r, o, t)) {\n const f = n.filter((v) => v !== r && v !== o), p = ti(r, o);\n return f.push(p), Le(\n f,\n t\n );\n }\n }\n return n;\n}\nfunction ti(n, t) {\n const e = Math.min(n.left, t.left), i = Math.max(n.right, t.right), s = Math.min(n.top, t.top), r = Math.max(n.bottom, t.bottom);\n return {\n bottom: r,\n height: r - s,\n left: e,\n right: i,\n top: s,\n width: i - e\n };\n}\nfunction ei(n, t) {\n const e = new Set(n);\n for (const i of n) {\n if (!(i.width > 1 && i.height > 1)) {\n e.delete(i);\n continue;\n }\n for (const r of n)\n if (i !== r && e.has(r) && ii(r, i, t)) {\n e.delete(i);\n break;\n }\n }\n return Array.from(e);\n}\nfunction ii(n, t, e) {\n return at(n, t.left, t.top, e) && at(n, t.right, t.top, e) && at(n, t.left, t.bottom, e) && at(n, t.right, t.bottom, e);\n}\nfunction at(n, t, e, i) {\n return (n.left < t || I(n.left, t, i)) && (n.right > t || I(n.right, t, i)) && (n.top < e || I(n.top, e, i)) && (n.bottom > e || I(n.bottom, e, i));\n}\nfunction Oe(n) {\n for (let t = 0; t < n.length; t++)\n for (let e = t + 1; e < n.length; e++) {\n const i = n[t], s = n[e];\n if (i !== s && Re(i, s, -1)) {\n let r = [], o;\n const a = he(i, s);\n if (a.length === 1)\n r = a, o = i;\n else {\n const u = he(s, i);\n a.length < u.length ? (r = a, o = i) : (r = u, o = s);\n }\n const c = n.filter((u) => u !== o);\n return Array.prototype.push.apply(c, r), Oe(c);\n }\n }\n return n;\n}\nfunction he(n, t) {\n const e = si(t, n);\n if (e.height === 0 || e.width === 0)\n return [n];\n const i = [];\n {\n const s = {\n bottom: n.bottom,\n height: 0,\n left: n.left,\n right: e.left,\n top: n.top,\n width: 0\n };\n s.width = s.right - s.left, s.height = s.bottom - s.top, s.height !== 0 && s.width !== 0 && i.push(s);\n }\n {\n const s = {\n bottom: e.top,\n height: 0,\n left: e.left,\n right: e.right,\n top: n.top,\n width: 0\n };\n s.width = s.right - s.left, s.height = s.bottom - s.top, s.height !== 0 && s.width !== 0 && i.push(s);\n }\n {\n const s = {\n bottom: n.bottom,\n height: 0,\n left: e.left,\n right: e.right,\n top: e.bottom,\n width: 0\n };\n s.width = s.right - s.left, s.height = s.bottom - s.top, s.height !== 0 && s.width !== 0 && i.push(s);\n }\n {\n const s = {\n bottom: n.bottom,\n height: 0,\n left: e.right,\n right: n.right,\n top: n.top,\n width: 0\n };\n s.width = s.right - s.left, s.height = s.bottom - s.top, s.height !== 0 && s.width !== 0 && i.push(s);\n }\n return i;\n}\nfunction si(n, t) {\n const e = Math.max(n.left, t.left), i = Math.min(n.right, t.right), s = Math.max(n.top, t.top), r = Math.min(n.bottom, t.bottom);\n return {\n bottom: r,\n height: Math.max(0, r - s),\n left: e,\n right: i,\n top: s,\n width: Math.max(0, i - e)\n };\n}\nfunction Re(n, t, e) {\n return (n.left < t.right || e >= 0 && I(n.left, t.right, e)) && (t.left < n.right || e >= 0 && I(t.left, n.right, e)) && (n.top < t.bottom || e >= 0 && I(n.top, t.bottom, e)) && (t.top < n.bottom || e >= 0 && I(t.top, n.bottom, e));\n}\nfunction I(n, t, e) {\n return Math.abs(n - t) <= e;\n}\nfunction Vt(n) {\n const t = {}, e = n.document.documentElement.style;\n for (const i in n.document.documentElement.style)\n Object.hasOwn(e, i) && !Number.isNaN(Number.parseInt(i)) && (t[e[i]] = e.getPropertyValue(e[i]));\n return t;\n}\nfunction De(n, t) {\n const e = Vt(n);\n Object.keys(e).forEach((i) => {\n t.hasOwnProperty(i) || gt(n, i);\n }), Object.entries(t).forEach(([i, s]) => {\n e[i] !== s && st(n, i, s);\n });\n}\nfunction wt(n, t) {\n return n.document.documentElement.style.getPropertyValue(t);\n}\nfunction st(n, t, e) {\n n.document.documentElement.style.setProperty(t, e);\n}\nfunction gt(n, t) {\n n.document.documentElement.style.removeProperty(t);\n}\nlet lt = null, St = null, J = 0;\nconst G = { r: 255, g: 255, b: 255, a: 1 }, F = /* @__PURE__ */ new Map(), ri = () => {\n if (!lt)\n if (typeof OffscreenCanvas < "u")\n lt = new OffscreenCanvas(5, 5), St = lt.getContext("2d", {\n willReadFrequently: !0,\n desynchronized: !0\n });\n else {\n const n = document.createElement("canvas");\n n.width = 5, n.height = 5, lt = n, St = n.getContext("2d", {\n willReadFrequently: !0,\n desynchronized: !0\n });\n }\n return St;\n}, ni = (n) => {\n if (!n) return !0;\n const t = n.trim().toLowerCase();\n return t.startsWith("var(") || [\n "transparent",\n "currentcolor",\n "inherit",\n "initial",\n "revert",\n "unset",\n "revert-layer"\n ].includes(t) ? !0 : [\n "linear-gradient",\n "radial-gradient",\n "conic-gradient",\n "repeating-linear-gradient",\n "repeating-radial-gradient",\n "repeating-conic-gradient"\n ].some((s) => t.includes(s));\n}, ct = (n, t) => {\n console.warn(\n `[Decorator] Could not parse color: "${n}". ${t} Falling back to ${JSON.stringify(G)} to compute contrast. Please use a CSS color value that can be computed to RGB(A).`\n );\n}, Ct = (n, t = null) => {\n const e = t ? `${n}|${t}` : n, i = F.get(e);\n if (i !== void 0)\n return i ?? G;\n if (ni(n))\n return ct(n, "Unsupported color format or special value."), F.set(e, null), G;\n const s = ri();\n if (!s)\n return ct(n, "Could not get canvas context."), F.set(e, null), G;\n try {\n J === 0 && s.clearRect(0, 0, 5, 5);\n const r = J % 5, o = Math.floor(J / 5);\n s.clearRect(r, o, 1, 1), t && (s.fillStyle = t, s.fillRect(r, o, 1, 1)), s.fillStyle = n, s.fillRect(r, o, 1, 1);\n const a = s.getImageData(r, o, 1, 1);\n J = (J + 1) % 25;\n const [c, u, d, f] = a.data;\n if (f === 0)\n return ct(n, "Fully transparent color."), F.set(e, null), G;\n const p = { r: c, g: u, b: d, a: f / 255 };\n return F.set(e, p), p;\n } catch (r) {\n return ct(n, `Error: ${r instanceof Error ? r.message : String(r)}`), F.set(e, null), G;\n }\n}, Et = (n) => {\n const t = n / 255;\n return t <= 0.03928 ? t / 12.92 : Math.pow((t + 0.055) / 1.055, 2.4);\n}, de = (n) => {\n const t = Et(n.r), e = Et(n.g), i = Et(n.b);\n return 0.2126 * t + 0.7152 * e + 0.0722 * i;\n}, ue = (n, t) => {\n const e = typeof n == "string" ? Ct(n) : n, i = typeof t == "string" ? Ct(t) : t, s = de(e), r = de(i), o = Math.max(s, r), a = Math.min(s, r);\n return (o + 0.05) / (a + 0.05);\n}, xt = (n, t = null) => {\n const e = Ct(n, t), i = ue(e, { r: 255, g: 255, b: 255, a: 1 }), s = ue(e, { r: 0, g: 0, b: 0, a: 1 });\n return i > s;\n}, oi = (n, t = null) => xt(n, t) ? "white" : "black", pe = "#FFFF00";\nvar ai = /* @__PURE__ */ ((n) => (n.Wrap = "wrap", n.Viewport = "viewport", n.Bounds = "bounds", n.Page = "page", n))(ai || {}), li = /* @__PURE__ */ ((n) => (n.Boxes = "boxes", n.Bounds = "bounds", n))(li || {});\nconst ci = () => "Highlight" in window, me = ["IMG", "IMAGE", "AUDIO", "VIDEO", "SVG"];\nclass hi {\n /**\n * Creates a DecorationGroup object\n * @param id Unique HTML ID-adhering name of the group\n * @param name Human-readable name of the group\n */\n constructor(t, e, i, s) {\n this.wnd = t, this.comms = e, this.id = i, this.name = s, this.items = [], this.lastItemId = 0, this.container = void 0, this.activateable = !1, this.experimentalHighlights = !1, this.currentRender = 0, ci() && (this.experimentalHighlights = !0, this.notTextFlag = /* @__PURE__ */ new Map());\n }\n get activeable() {\n return this.activateable;\n }\n set activeable(t) {\n this.activateable = t;\n }\n /**\n * Adds a new decoration to the group.\n * @param decoration Decoration to add\n */\n add(t) {\n const e = `${this.id}-${this.lastItemId++}`, i = rt(this.wnd.document, t.locator);\n if (!i) {\n this.comms.log("Can\'t locate DOM range for decoration", t);\n return;\n }\n const s = i.commonAncestorContainer;\n s.nodeType !== Node.TEXT_NODE && this.experimentalHighlights && (me.includes(s.nodeName.toUpperCase()) && this.notTextFlag?.set(e, !0), i.cloneContents().querySelector(me.join(", ").toLowerCase()) && this.notTextFlag?.set(e, !0), (s.textContent?.trim() || "").length === 0 && this.notTextFlag?.set(e, !0));\n const r = {\n decoration: t,\n id: e,\n range: i\n };\n this.items.push(r), this.layout(r), this.renderLayout([r]);\n }\n /**\n * Removes the decoration with given ID from the group.\n * @param identifier ID of item to remove\n */\n remove(t) {\n const e = this.items.findIndex((s) => s.decoration.id === t);\n if (e < 0) return;\n const i = this.items[e];\n this.items.splice(e, 1), i.clickableElements = void 0, i.container && (i.container.remove(), i.container = void 0), this.experimentalHighlights && !this.notTextFlag?.has(i.id) && this.wnd.CSS.highlights.get(this.id)?.delete(i.range), this.notTextFlag?.delete(i.id);\n }\n /**\n * Notifies that the given decoration was modified and needs to be updated.\n * @param decoration Decoration to update\n */\n update(t) {\n this.remove(t.id), this.add(t);\n }\n /**\n * Removes all decorations from this group.\n */\n clear() {\n this.clearContainer(), this.items.length = 0, this.notTextFlag?.clear();\n }\n /**\n * Recreates the decoration elements.\n * To be called after reflowing the resource, for example.\n */\n requestLayout() {\n this.wnd.cancelAnimationFrame(this.currentRender), this.clearContainer(), this.items.forEach((t) => this.layout(t)), this.renderLayout(this.items);\n }\n experimentalLayout(t) {\n const [e, i] = this.requireContainer(!0);\n i.add(t.range);\n const s = wt(this.wnd, "--USER__backgroundColor") || this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color"), r = t.decoration?.style?.tint ?? pe;\n e.innerHTML = `\n ::highlight(${this.id}) {\n color: ${oi(r, s)};\n background-color: ${r};\n }`;\n }\n /**\n * Layouts a single DecorationItem.\n * @param item\n */\n layout(t) {\n if (this.experimentalHighlights && !this.notTextFlag?.has(t.id))\n return this.experimentalLayout(t);\n const e = this.wnd.document.createElement("div");\n e.setAttribute("id", t.id), e.dataset.highlightId = t.decoration.id, e.style.setProperty("pointer-events", "none");\n const i = this.wnd.innerWidth, s = parseInt(\n getComputedStyle(this.wnd.document.documentElement).getPropertyValue(\n "column-count"\n )\n ), r = i / (s || 1), o = this.wnd.document.scrollingElement, a = o.scrollLeft, c = o.scrollTop, u = (g, m, b) => {\n if (g.style.position = "absolute", t.decoration?.style?.width === "viewport") {\n g.style.width = `${i}px`, g.style.height = `${m.height}px`;\n let D = Math.floor(m.left / i) * i;\n g.style.left = `${D + a}px`, g.style.top = `${m.top + c}px`;\n } else if (t.decoration?.style?.width === "bounds")\n g.style.width = `${b.width}px`, g.style.height = `${m.height}px`, g.style.left = `${b.left + a}px`, g.style.top = `${m.top + c}px`;\n else if (t.decoration?.style?.width === "page") {\n g.style.width = `${r}px`, g.style.height = `${m.height}px`;\n let D = Math.floor(m.left / r) * r;\n g.style.left = `${D + a}px`, g.style.top = `${m.top + c}px`;\n } else\n g.style.width = `${m.width}px`, g.style.height = `${m.height}px`, g.style.left = `${m.left + a}px`, g.style.top = `${m.top + c}px`;\n }, d = t.range.getBoundingClientRect();\n let f = this.wnd.document.createElement("template");\n const p = this.getCurrentDarkMode();\n f.innerHTML = `\n \n \n `.trim();\n const v = f.content.firstElementChild;\n if (t.decoration?.style?.layout === "bounds") {\n const g = v.cloneNode(!0);\n g.style.setProperty("pointer-events", "none"), u(g, d, d), e.append(g);\n } else {\n let g = je(\n t.range\n );\n g = g.sort((m, b) => m.top < b.top ? -1 : m.top > b.top ? 1 : 0);\n for (let m of g) {\n const b = v.cloneNode(!0);\n b.style.setProperty("pointer-events", "none"), u(b, m, d), e.append(b);\n }\n }\n t.container = e, t.clickableElements = Array.from(\n e.querySelectorAll("[data-activable=\'1\']")\n ), t.clickableElements.length || (t.clickableElements = Array.from(e.children));\n }\n renderLayout(t) {\n this.wnd.cancelAnimationFrame(this.currentRender), this.currentRender = this.wnd.requestAnimationFrame(() => {\n if (t = t.filter((i) => !this.experimentalHighlights || !!this.notTextFlag?.has(i.id)), !t || t.length === 0) return;\n this.requireContainer().append(...t.map((i) => i.container).filter((i) => !!i));\n });\n }\n /**\n * Returns the group container element, after making sure it exists.\n * @returns Group\'s container\n */\n requireContainer(t = !1) {\n if (t) {\n let e;\n this.wnd.document.getElementById(`${this.id}-style`) ? e = this.wnd.document.getElementById(`${this.id}-style`) : (e = this.wnd.document.createElement("style"), e.dataset.readium = "true", e.id = `${this.id}-style`, this.wnd.document.head.appendChild(e));\n let i;\n return this.wnd.CSS.highlights.has(this.id) ? i = this.wnd.CSS.highlights.get(this.id) : (i = new this.wnd.Highlight(), this.wnd.CSS.highlights.set(this.id, i)), [e, i];\n }\n return this.container || (this.container = this.wnd.document.createElement("div"), this.container.setAttribute("id", this.id), this.container.dataset.group = this.name, this.container.dataset.readium = "true", this.container.style.setProperty("pointer-events", "none"), this.container.style.display = "contents", this.wnd.document.body.append(this.container)), this.container;\n }\n getCurrentDarkMode() {\n return wt(this.wnd, "--USER__appearance") === "readium-night-on" || xt(wt(this.wnd, "--USER__backgroundColor")) || xt(this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color"));\n }\n /**\n * Removes the group container.\n */\n clearContainer() {\n this.experimentalHighlights && this.wnd.CSS.highlights.delete(this.id), this.container && (this.container.remove(), this.container = void 0);\n }\n}\nconst j = class j extends K {\n constructor() {\n super(...arguments), this.resizeFrame = 0, this.lastGroupId = 0, this.groups = /* @__PURE__ */ new Map(), this.handleResizer = this.handleResize.bind(this);\n }\n cleanup() {\n this.groups.forEach((t) => t.clear()), this.groups.clear();\n }\n updateHighlightStyles() {\n this.groups.forEach((t) => {\n t.requestLayout();\n });\n }\n extractCustomProperty(t, e) {\n if (!t) return null;\n const i = t.match(new RegExp(`${e}:\\\\s*([^;]+)`));\n return i ? i[1].trim() : null;\n }\n handleResize() {\n this.wnd.clearTimeout(this.resizeFrame), this.resizeFrame = this.wnd.setTimeout(() => {\n this.groups.forEach((t) => {\n t.experimentalHighlights || t.requestLayout();\n });\n }, 50);\n }\n mount(t, e) {\n return this.wnd = t, e.register("decorate", j.moduleName, (i, s) => {\n const r = i;\n r.decoration && r.decoration.locator && (r.decoration.locator = k.deserialize(r.decoration.locator)), this.groups.has(r.group) || this.groups.set(r.group, new hi(\n t,\n e,\n `readium-decoration-${this.lastGroupId++}`,\n r.group\n ));\n const o = this.groups.get(r.group);\n switch (r.action) {\n case "add":\n o?.add(r.decoration);\n break;\n case "remove":\n o?.remove(r.decoration.id);\n break;\n case "clear":\n o?.clear();\n break;\n case "update":\n o?.update(r.decoration);\n break;\n }\n s(!0);\n }), this.resizeObserver = new ResizeObserver(() => t.requestAnimationFrame(() => this.handleResize())), this.resizeObserver.observe(t.document.body), t.addEventListener("orientationchange", this.handleResizer), t.addEventListener("resize", this.handleResizer), this.backgroundObserver = new MutationObserver((i) => {\n i.some((r) => {\n if (r.type === "attributes" && r.attributeName === "style") {\n const o = r.target, a = r.oldValue, c = o.getAttribute("style"), u = this.extractCustomProperty(a, "--USER__appearance"), d = this.extractCustomProperty(c, "--USER__appearance"), f = this.extractCustomProperty(a, "--USER__backgroundColor"), p = this.extractCustomProperty(c, "--USER__backgroundColor");\n return u !== d || f !== p;\n }\n return !1;\n }) && this.updateHighlightStyles();\n }), this.backgroundObserver.observe(t.document.documentElement, {\n attributes: !0,\n attributeFilter: ["style"],\n attributeOldValue: !0,\n subtree: !0\n }), e.log("Decorator Mounted"), !0;\n }\n unmount(t, e) {\n return t.removeEventListener("orientationchange", this.handleResizer), t.removeEventListener("resize", this.handleResizer), e.unregisterAll(j.moduleName), this.resizeObserver.disconnect(), this.backgroundObserver.disconnect(), this.cleanup(), e.log("Decorator Unmounted"), !0;\n }\n};\nj.moduleName = "decorator";\nlet Tt = j;\nconst fe = "readium-snapper-style", tt = class tt extends K {\n constructor() {\n super(...arguments), this.protected = !1;\n }\n buildStyles() {\n return `\n html, body {\n touch-action: manipulation;\n user-select: ${this.protected ? "none" : "auto"};\n }`;\n }\n mount(t, e) {\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = fe, i.textContent = this.buildStyles(), t.document.head.appendChild(i), e.register("protect", tt.moduleName, (s, r) => {\n this.protected = !0, i.textContent = this.buildStyles(), r(!0);\n }), e.register("unprotect", tt.moduleName, (s, r) => {\n this.protected = !1, i.textContent = this.buildStyles(), r(!0);\n }), e.log("Snapper Mounted"), !0;\n }\n unmount(t, e) {\n return t.document.getElementById(fe)?.remove(), e.log("Snapper Unmounted"), !0;\n }\n};\ntt.moduleName = "snapper";\nlet X = tt;\nfunction di(n) {\n return (n.document.documentElement.dir || n.document.body.dir).toLowerCase() === "rtl";\n}\nfunction ui(n) {\n return (n.getComputedStyle(n.document.documentElement).writingMode || n.getComputedStyle(n.document.body).writingMode) === "vertical-lr";\n}\nfunction Ie(n) {\n return parseInt(\n n.getComputedStyle(\n n.document.documentElement\n ).getPropertyValue("column-count")\n );\n}\nfunction ge(n) {\n const t = getComputedStyle(n), e = parseFloat(t.paddingTop || "0"), i = parseFloat(t.paddingBottom || "0");\n return n.clientHeight - e - i;\n}\nfunction ye(n) {\n const t = Ie(n);\n if (!t)\n return !1;\n const e = n.document.querySelectorAll("div[id^=\'readium-virtual-page\']");\n for (const u of e)\n u.remove();\n const i = e.length, s = n.document.scrollingElement.scrollWidth, r = n.visualViewport.width, a = Math.round(s / r * t) % t, c = t === 1 || a === 0 ? 0 : t - a;\n if (c > 0)\n for (let u = 0; u < c; u++) {\n const d = n.document.createElement("div");\n d.setAttribute("id", `readium-virtual-page-${u}`), d.dataset.readium = "true", CSS.supports("break-before", "column") ? d.style.breakBefore = "column" : (CSS.supports("break-inside", "avoid-column") && (d.style.breakInside = "avoid-column"), d.style.height = ge(n.document.documentElement) + "px"), d.innerHTML = "​", n.document.body.appendChild(d);\n }\n return i !== c;\n}\nfunction Ft(n) {\n const t = n.document.createElement("style");\n t.appendChild(n.document.createTextNode("*{}")), n.document.body.appendChild(t), n.document.body.removeChild(t);\n}\nfunction pi(n) {\n return n < 0.5 ? 2 * n * n : -1 + (4 - 2 * n) * n;\n}\nfunction A(n) {\n const t = n.getSelection();\n t && t.removeAllRanges();\n}\nconst mi = [\n "a",\n "area",\n "audio",\n "button",\n "canvas",\n "details",\n "input",\n "label",\n "option",\n "select",\n "submit",\n "textarea",\n "video"\n], fi = ["dialog", "radiogroup", "radio", "menu", "menuitem"];\nfunction Gt(n) {\n return gi(n) ? null : ze(n) ? n : n.parentElement ? Gt(n.parentElement) : null;\n}\nfunction gi(n) {\n return n ? n.closest("[inert]") !== null || n.hasAttribute("disabled") : !0;\n}\nfunction ze(n) {\n return n ? n.role && fi.includes(n.role) || n.tabIndex >= 0 ? !0 : mi.includes(n.nodeName.toLowerCase()) || n.hasAttribute("contenteditable") && n.getAttribute("contenteditable")?.toLowerCase() !== "false" : !1;\n}\nfunction yt(n, t) {\n const e = Me(n, n.document.body, t), i = n._readium_cssSelectorGenerator.getCssSelector(e, {\n selectors: ["tag", "id", "class", "nthchild", "nthoftype", "attribute"]\n });\n return new k({\n href: "#",\n type: "application/xhtml+xml",\n locations: new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", i]\n ])\n }),\n text: new H({\n highlight: e.textContent || void 0\n })\n });\n}\nfunction Me(n, t, e) {\n for (var i = 0; i < t.children.length; i++) {\n const s = t.children[i];\n if (!vi(s) && yi(n, s, e))\n return bi(n, s) ? s : Me(n, s, e);\n }\n return t;\n}\nfunction yi(n, t, e) {\n if (t === document.body || t === document.documentElement)\n return !0;\n if (!document || !document.documentElement || !document.body)\n return !1;\n const i = t.getBoundingClientRect();\n return e ? i.bottom > 0 && i.top < n.innerHeight : i.right > 0 && i.left < n.innerWidth;\n}\nfunction bi(n, t) {\n const e = t.getBoundingClientRect();\n return e.top >= 0 && e.left >= 0 && e.bottom <= n.innerHeight && e.right <= n.innerWidth;\n}\nfunction vi(n) {\n const t = getComputedStyle(n);\n if (t) {\n const e = t.getPropertyValue("display");\n if (e != "block" && e != "list-item" || t.getPropertyValue("opacity") === "0")\n return !0;\n }\n return !1;\n}\nconst wi = {\n maxVelocity: 200,\n // Reasonable default for human-like scrolling (pixels/ms)\n minVariance: 0.01,\n // Default variance threshold\n historySize: 20,\n // Balanced history size for performance\n minDirectionChanges: 0.2,\n // Reasonable default for detecting patterns\n maxConsistentScrolls: 15\n // Balanced threshold for flagging\n}, $t = {\n maxVelocity: 200,\n // Extremely fast scrolling (pixels/ms)\n minVariance: 1e-5,\n // Near-perfect consistency\n historySize: 100,\n // Large history window\n minDirectionChanges: 0.1,\n // Only trigger on near-perfect patterns\n maxConsistentScrolls: 20\n // Need many consistent scrolls\n}, ke = {\n maxSelectionsPerSecond: 500,\n minVariance: 50,\n historySize: 20\n}, Si = {\n enabled: !0,\n maxSelectionPercent: 0.1,\n minThreshold: 100,\n absoluteMaxChars: 5e3,\n historySize: 20\n};\nclass bt {\n constructor(t = {}) {\n this.history = [], this.consistentScrollCount = 0, this.options = { ...wi, ...t };\n }\n analyze(t, e, i) {\n if (i <= 0) return !1;\n const s = Math.abs(e) / i, r = Date.now();\n if (this.history.push({\n timestamp: r,\n direction: t,\n velocity: s,\n distance: Math.abs(e)\n }), this.history = this.history.filter((m) => r - m.timestamp < 2e3).slice(-(this.options.historySize || 20)), this.history.length < 3) return !1;\n if (s > this.options.maxVelocity)\n return this.resetAfterDetection(), !0;\n const o = this.history.map((m) => m.velocity), a = this.history.map((m) => m.distance), c = o.reduce((m, b) => m + b, 0) / o.length, u = a.reduce((m, b) => m + b, 0) / a.length, d = o.reduce((m, b) => m + Math.pow(b - c, 2), 0) / o.length, f = a.reduce((m, b) => m + Math.pow(b - u, 2), 0) / a.length;\n if (d < this.options.minVariance && f < u * 0.1) {\n if (this.consistentScrollCount++, this.consistentScrollCount >= (this.options.maxConsistentScrolls || 10))\n return this.resetAfterDetection(), !0;\n } else\n this.consistentScrollCount = Math.max(0, this.consistentScrollCount - 1);\n let p = 0, v = this.history[0].direction;\n for (let m = 1; m < this.history.length; m++)\n this.history[m].direction !== v && (p++, v = this.history[m].direction);\n return p / this.history.length > (this.options.minDirectionChanges || 0.3) ? (this.resetAfterDetection(), !0) : !1;\n }\n resetAfterDetection() {\n this.history = this.history.slice(-3), this.consistentScrollCount = 0;\n }\n clear() {\n this.history = [], this.consistentScrollCount = 0;\n }\n}\nconst be = "readium-column-snapper-style", Ei = 200, T = class T extends X {\n constructor() {\n super(...arguments), this.isSnapProtectionEnabled = !1, this.patternAnalyzer = null, this.lastTurnTime = 0, this.rtl = !1, this.shakeTimeout = 0, this.snappingCancelled = !1, this.alreadyScrollLeft = 0, this.overscroll = 0, this.cachedScrollWidth = 0, this.touchState = 0, this.startingX = void 0, this.endingX = void 0, this.onTouchStarter = this.onTouchStart.bind(this), this.onTouchEnder = this.onTouchEnd.bind(this), this.onWidthChanger = this.onWidthChange.bind(this), this.onTouchMover = this.onTouchMove.bind(this);\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n scrollOffset() {\n const t = this.doc().scrollLeft;\n return t !== 0 ? t : this.alreadyScrollLeft;\n }\n snapOffset(t) {\n const e = t + (this.rtl ? -1 : 1);\n return e - e % this.wnd.innerWidth;\n }\n /**\n * Snap a non-negative normalized offset (distance from document start) to\n * the nearest page boundary. Works identically regardless of reading direction.\n */\n snapNormOffset(t) {\n const e = t + 1;\n return e - e % this.wnd.innerWidth;\n }\n /**\n * Normalized scroll position: distance from document start, always in\n * [0, scrollWidth - innerWidth] regardless of reading direction.\n * scrollLeft may be negative depending on the browser — Math.abs() normalizes it.\n */\n normScroll() {\n const t = this.doc().scrollLeft || this.alreadyScrollLeft;\n return this.rtl ? Math.abs(t) : Math.max(0, this.wnd.scrollX > 0 ? this.wnd.scrollX : t);\n }\n reportProgress() {\n const t = this.cachedScrollWidth, e = this.wnd.innerWidth, i = this.normScroll(), s = Math.max(1, t - e), r = Math.max(0, Math.min(1, i / s)), o = Math.max(0, Math.min(1, (i + e) / t));\n this.comms.send("progress", {\n start: r,\n end: o\n });\n }\n shake() {\n if (this.overscroll !== 0 || this.shakeTimeout !== 0) return;\n const t = this.doc(), e = this.normScroll() < 5, i = this.rtl ? e ? "readium-bounce-r" : "readium-bounce-l" : "readium-bounce-r";\n t.classList.add(i);\n const s = this.scrollOffset();\n this.shakeTimeout = this.wnd.setTimeout(() => {\n t.classList.remove(i), this.shakeTimeout = 0, this.doc().scrollLeft = s;\n }, 150);\n }\n // We have to cache this because during overscroll (transform, or left) the width is incorrect due to browser\n takeOverSnap() {\n this.snappingCancelled = !0, this.clearTouches();\n const t = this.doc();\n this.overscroll = t.style.transform?.length > 12 ? parseFloat(t.style.transform.slice(12).split("px")[0]) : 0;\n }\n // Snaps the current offset to the page width.\n snapCurrentOffset(t = !1, e = !1) {\n const i = this.doc(), s = Ie(this.wnd), r = this.cachedScrollWidth - this.wnd.innerWidth, o = Math.min(Math.max(0, this.normScroll()), r), a = this.dragOffset(), c = this.rtl ? -a : a, u = this.wnd.innerWidth / 3 * (c > 0 ? 2 : 1), d = Math.min(r, Math.max(0, this.snapNormOffset(o + u))), f = this.rtl ? -d : d, p = this.rtl ? -o : o, v = f > p ? "right" : "left";\n if (this.checkSuspiciousSnap(v, Math.abs(f - p)), t && f !== p) {\n this.snappingCancelled = !1;\n const g = (_, V, nt, ot) => nt > ot ? V : _ + (V - _) * pi(nt / ot), m = Ei * s;\n let b;\n const D = (_) => {\n if (this.snappingCancelled) return;\n b || (b = _);\n const V = _ - b, nt = g(this.overscroll, 0, V, m), ot = g(p, f, V, m);\n i.scrollLeft = ot, this.overscroll !== 0 && (i.style.transform = `translate3d(${-nt}px, 0px, 0px)`), V < m ? this.wnd.requestAnimationFrame(D) : (this.clearTouches(), i.style.removeProperty("transform"), i.scrollLeft = f, e || this.reportProgress());\n };\n this.wnd.requestAnimationFrame(D);\n } else\n i.style.removeProperty("transform"), this.wnd.requestAnimationFrame(() => {\n i.scrollLeft = f, this.clearTouches(), e || this.reportProgress();\n });\n }\n dragOffset() {\n return (this.startingX ?? 0) - (this.endingX ?? 0);\n }\n clearTouches() {\n this.startingX = void 0, this.endingX = void 0, this.overscroll = 0;\n }\n onTouchStart(t) {\n switch (t.stopPropagation(), this.takeOverSnap(), t.touches.length) {\n case 1:\n break;\n case 2:\n this.onTouchEnd(t);\n return;\n default: {\n this.onTouchEnd(t), this.comms.send("tap_more", t.touches.length);\n return;\n }\n }\n this.startingX = t.touches[0].clientX, this.alreadyScrollLeft = this.doc().scrollLeft, this.touchState = 1;\n }\n onTouchEnd(t) {\n if (this.touchState === 2) {\n const e = this.dragOffset(), i = this.normScroll(), s = this.cachedScrollWidth - this.wnd.innerWidth, r = this.rtl ? -e : e;\n this.cachedScrollWidth <= this.wnd.innerWidth ? (this.reportProgress(), r > 5 && this.comms.send("no_more", void 0), r < -5 && this.comms.send("no_less", void 0)) : i < 5 && r < 5 ? (this.alreadyScrollLeft = 0, this.comms.send("no_less", void 0)) : s - i < 5 && r > 5 && (this.alreadyScrollLeft = this.rtl ? -s : s, this.comms.send("no_more", void 0)), this.snapCurrentOffset(!0), this.comms.send("swipe", e);\n }\n this.touchState = 0;\n }\n onWidthChange() {\n this.cachedScrollWidth = this.doc().scrollWidth, this.comms.ready && this.snapCurrentOffset();\n }\n onTouchMove(t) {\n if (this.touchState === 0) return;\n this.touchState === 1 && (this.touchState = 2, A(this.wnd)), this.endingX = t.touches[0].clientX;\n const e = this.dragOffset(), i = this.alreadyScrollLeft + e, s = this.rtl ? -(this.cachedScrollWidth - this.wnd.innerWidth) : 0, r = this.rtl ? 0 : this.cachedScrollWidth - this.wnd.innerWidth;\n i < s ? (this.overscroll = i, this.doc().style.transform = `translate3d(${-this.overscroll}px, 0px, 0px)`) : i > r ? (this.overscroll = i, this.doc().style.transform = `translate3d(${-i}px, 0px, 0px)`) : (this.overscroll = 0, this.doc().style.removeProperty("transform"), this.doc().scrollLeft = i);\n }\n enableSnapProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new bt({\n maxVelocity: this.wnd.innerWidth,\n // page width\n minVariance: 0.1,\n // Allow for some variation in swipe speed\n historySize: 5,\n // Fewer samples needed for swipe detection\n maxConsistentScrolls: 3,\n // Lower threshold for consistent scrolling\n minDirectionChanges: 0.3\n // Require more direction changes\n }), this.isSnapProtectionEnabled = !0, this.comms?.log("Snap protection enabled"));\n }\n checkSuspiciousSnap(t, e) {\n if (!this.isSnapProtectionEnabled || !this.patternAnalyzer) return;\n const i = Date.now(), s = i - (this.lastTurnTime || i);\n this.lastTurnTime = i, this.patternAnalyzer.analyze(t, e, s) && this.comms?.send("content_protection", {\n type: "suspicious_snapping",\n timestamp: Date.now(),\n event: null\n });\n }\n mount(t, e) {\n if (this.wnd = t, this.comms = e, this.rtl = di(t), !super.mount(t, e)) return !1;\n t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "paginated");\n const i = t.document.createElement("style");\n i.dataset.readium = "true", i.id = be, i.textContent = `\n @keyframes readium-bounce-l-animation {\n 0%, 100% {transform: translate3d(0, 0, 0);}\n 50% {transform: translate3d(-50px, 0, 0);}\n }\n\n @keyframes readium-bounce-r-animation {\n 0%, 100% {transform: translate3d(0, 0, 0);}\n 50% {transform: translate3d(50px, 0, 0);}\n }\n\n .readium-bounce-l {\n animation: readium-bounce-l-animation 150ms ease-out 1;\n }\n\n .readium-bounce-r {\n animation: readium-bounce-r-animation 150ms ease-out 1;\n }\n\n html {\n overflow: hidden;\n }\n\n body {\n -ms-overflow-style: none; /* for Internet Explorer, Edge */\n }\n\n * {\n scrollbar-width: none; /* for Firefox */\n }\n\n body::-webkit-scrollbar {\n display: none; /* for Chrome, Safari, and Opera */\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n t.requestAnimationFrame(() => {\n t && ye(t);\n }), this.onWidthChange();\n }), this.resizeObserver.observe(t.document.body), this.mutationObserver = new MutationObserver((o) => {\n for (const a of o)\n if (a.target === this.wnd.document.documentElement) {\n const c = a.oldValue, u = a.target.getAttribute("style"), d = /transform\\s*:\\s*([^;]+)/, f = c?.match(d), p = u?.match(d);\n (!f && !p || f && !p || f && p && f[1] !== p[1]) && (t.requestAnimationFrame(() => {\n t && ye(t);\n }), this.onWidthChange());\n } else\n t.requestAnimationFrame(() => this.cachedScrollWidth = this.doc().scrollWidth);\n }), t.frameElement && this.mutationObserver.observe(t.frameElement, { attributes: !0, attributeFilter: ["style"] }), this.mutationObserver.observe(t.document, { attributes: !0, attributeFilter: ["style"] }), this.mutationObserver.observe(t.document.documentElement, { attributes: !0, attributeFilter: ["style"] }), e.register("scroll_protection", T.moduleName, (o, a) => {\n this.enableSnapProtection(), a(!0);\n });\n const s = (o) => {\n const a = this.doc().scrollLeft;\n return this.doc().scrollLeft = this.snapOffset(o), a !== this.doc().scrollLeft;\n }, r = (o) => {\n const a = this.doc().scrollLeft, c = this.snapNormOffset(Math.max(0, Math.min(this.cachedScrollWidth - t.innerWidth, o)));\n return this.doc().scrollLeft = -c, a !== this.doc().scrollLeft;\n };\n return t.addEventListener("orientationchange", this.onWidthChanger), t.addEventListener("resize", this.onWidthChanger), t.requestAnimationFrame(() => this.cachedScrollWidth = this.doc().scrollWidth), e.register("go_progression", T.moduleName, (o, a) => {\n const c = o;\n if (c < 0 || c > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n const d = (this.cachedScrollWidth - t.innerWidth) * c;\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(d) : this.doc().scrollLeft = this.snapOffset(d), this.reportProgress(), A(this.wnd), a(!0);\n });\n }), e.register("go_id", T.moduleName, (o, a) => {\n const c = t.document.getElementById(o);\n if (!c) {\n a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(c.getBoundingClientRect().left + t.scrollX) : this.doc().scrollLeft = this.snapOffset(c.getBoundingClientRect().left + t.scrollX), this.reportProgress(), A(this.wnd), a(!0);\n });\n }), e.register("go_text", T.moduleName, (o, a) => {\n let c;\n Array.isArray(o) && (o.length > 1 && (c = o[1]), o = o[0]);\n const u = H.deserialize(o), d = rt(this.wnd.document, new k({\n href: t.location.href,\n type: "text/html",\n text: u,\n locations: c ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", c]\n ])\n }) : void 0\n }));\n if (!d) {\n a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(d.getBoundingClientRect().left + t.scrollX) : this.doc().scrollLeft = this.snapOffset(d.getBoundingClientRect().left + t.scrollX), this.reportProgress(), A(this.wnd), a(!0);\n });\n }), e.register("go_end", T.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let c;\n if (this.rtl ? c = -this.snapNormOffset(this.cachedScrollWidth - t.innerWidth) : c = this.snapOffset(this.cachedScrollWidth), this.doc().scrollLeft === c) return a(!1);\n this.doc().scrollLeft = c, this.reportProgress(), A(this.wnd), a(!0);\n });\n }), e.register("go_start", T.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n if (this.doc().scrollLeft === 0) return a(!1);\n this.doc().scrollLeft = 0, this.reportProgress(), A(this.wnd), a(!0);\n });\n }), e.register("go_prev", T.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let c;\n this.rtl ? c = r(this.normScroll() - t.innerWidth) : c = s(t.scrollX - t.innerWidth), this.reportProgress(), c && (A(this.wnd), this.checkSuspiciousSnap("left", this.wnd.innerWidth)), a(c);\n });\n }), e.register("go_next", T.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let c;\n this.rtl ? c = r(this.normScroll() + t.innerWidth) : c = s(t.scrollX + t.innerWidth), this.reportProgress(), c && (A(this.wnd), this.checkSuspiciousSnap("right", this.wnd.innerWidth)), a(c);\n });\n }), e.register("unfocus", T.moduleName, (o, a) => {\n this.snappingCancelled = !0, A(this.wnd), a(!0);\n }), e.register("shake", T.moduleName, (o, a) => {\n this.shake(), a(!0);\n }), e.register("focus", T.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth, this.snapCurrentOffset(!1, !0), this.reportProgress(), a(!0);\n });\n }), e.register("first_visible_locator", T.moduleName, (o, a) => {\n const c = yt(t, !1);\n this.comms.send("first_visible_locator", c.serialize()), a(!0);\n }), t.addEventListener("touchstart", this.onTouchStarter, { passive: !0 }), t.addEventListener("touchend", this.onTouchEnder, { passive: !0 }), t.addEventListener("touchmove", this.onTouchMover, { passive: !0 }), t.document.addEventListener("touchstart", () => {\n }), e.log("ColumnSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return this.snappingCancelled = !0, e.unregisterAll(T.moduleName), this.resizeObserver.disconnect(), this.mutationObserver.disconnect(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isSnapProtectionEnabled = !1), t.removeEventListener("touchstart", this.onTouchStarter), t.removeEventListener("touchend", this.onTouchEnder), t.removeEventListener("touchmove", this.onTouchMover), t.removeEventListener("orientationchange", this.onWidthChanger), t.removeEventListener("resize", this.onWidthChanger), t.document.getElementById(be)?.remove(), e.log("ColumnSnapper Unmounted"), super.unmount(t, e);\n }\n};\nT.moduleName = "column_snapper";\nlet Pt = T;\nconst ve = "readium-scroll-snapper-style", P = class P extends X {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce = null, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollTop = this.doc().scrollTop, this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = this.doc().scrollTop, i = e - this.lastScrollTop;\n if (this.lastScrollTop = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const s = Date.now(), r = s - (this.lastScrollTime || s);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n i > 0 ? "down" : "up",\n Math.abs(i),\n r\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "down" : "up",\n targetElement: a\n });\n }\n this.lastScrollTime = s;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = Math.ceil(this.doc().scrollTop), e = this.doc().scrollHeight, i = this.wnd.innerHeight, s = Math.max(0, Math.min(1, t / e)), r = Math.max(0, Math.min(1, (t + i) / e));\n this.comms.send("progress", {\n start: s,\n end: r\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new bt($t), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "scrolling");\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = ve, i.textContent = `\n * {\n scrollbar-width: none; /* for Firefox */\n }\n\n body::-webkit-scrollbar {\n display: none; /* for Chrome, Safari, and Opera */\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", P.moduleName, () => {\n Ft(this.wnd);\n const s = this.doc().scrollTop;\n s > 1 ? this.doc().scrollTop = s - 1 : this.doc().scrollTop = s + 1, this.doc().scrollTop = s;\n }), e.register("go_progression", P.moduleName, (s, r) => {\n const o = s;\n if (o < 0 || o > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = this.doc().offsetHeight * o, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_id", P.moduleName, (s, r) => {\n const o = t.document.getElementById(s);\n if (!o) {\n r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = o.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_text", P.moduleName, (s, r) => {\n let o;\n Array.isArray(s) && (s.length > 1 && (o = s[1]), s = s[0]);\n const a = H.deserialize(s), c = rt(this.wnd.document, new k({\n href: t.location.href,\n type: "text/html",\n text: a,\n locations: o ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", o]\n ])\n }) : void 0\n }));\n if (!c) {\n r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = c.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_start", P.moduleName, (s, r) => {\n if (this.doc().scrollTop === 0) return r(!1);\n this.doc().scrollTop = 0, this.reportProgress(), r(!0);\n }), e.register("go_end", P.moduleName, (s, r) => {\n if (this.doc().scrollTop === this.doc().scrollHeight - this.doc().offsetHeight) return r(!1);\n this.doc().scrollTop = this.doc().scrollHeight - this.doc().offsetHeight, this.reportProgress(), r(!0);\n }), e.register("unfocus", P.moduleName, (s, r) => {\n A(this.wnd), r(!0);\n }), e.register("scroll_protection", P.moduleName, (s, r) => {\n this.enableScrollProtection(), r(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], P.moduleName, (s, r) => r(!1)), e.register("focus", P.moduleName, (s, r) => {\n this.reportProgress(), r(!0);\n }), e.register("first_visible_locator", P.moduleName, (s, r) => {\n const o = yt(t, !0);\n this.comms.send("first_visible_locator", o.serialize()), r(!0);\n }), e.log("ScrollSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(P.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), t.document.getElementById(ve)?.remove(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("ScrollSnapper Unmounted"), !0;\n }\n};\nP.moduleName = "scroll_snapper";\nlet Nt = P;\nconst N = class N extends X {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce = null, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollTop = this.doc().scrollTop, this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = this.doc().scrollTop, i = e - this.lastScrollTop;\n if (this.lastScrollTop = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const s = Date.now(), r = s - (this.lastScrollTime || s);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n i > 0 ? "down" : "up",\n Math.abs(i),\n r\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "down" : "up",\n targetElement: a\n });\n }\n this.lastScrollTime = s;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = Math.ceil(this.doc().scrollTop), e = this.doc().scrollHeight, i = this.wnd.innerHeight, s = Math.max(0, Math.min(1, t / e)), r = Math.max(0, Math.min(1, (t + i) / e));\n this.comms.send("progress", {\n start: s,\n end: r\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new bt($t), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", N.moduleName, () => {\n Ft(this.wnd);\n const i = this.doc().scrollTop;\n i > 1 ? this.doc().scrollTop = i - 1 : this.doc().scrollTop = i + 1, this.doc().scrollTop = i;\n }), e.register("go_progression", N.moduleName, (i, s) => {\n const r = i;\n if (r < 0 || r > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = this.doc().offsetHeight * r, this.reportProgress(), A(this.wnd), s(!0);\n });\n }), e.register("go_id", N.moduleName, (i, s) => {\n const r = t.document.getElementById(i);\n if (!r) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = r.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), A(this.wnd), s(!0);\n });\n }), e.register("go_text", N.moduleName, (i, s) => {\n let r;\n Array.isArray(i) && (i.length > 1 && (r = i[1]), i = i[0]);\n const o = H.deserialize(i), a = rt(this.wnd.document, new k({\n href: t.location.href,\n type: "text/html",\n text: o,\n locations: r ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", r]\n ])\n }) : void 0\n }));\n if (!a) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = a.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), A(this.wnd), s(!0);\n });\n }), e.register("go_start", N.moduleName, (i, s) => {\n if (this.doc().scrollTop === 0) return s(!1);\n this.doc().scrollTop = 0, this.reportProgress(), s(!0);\n }), e.register("go_end", N.moduleName, (i, s) => {\n if (this.doc().scrollTop === this.doc().scrollHeight - this.doc().offsetHeight) return s(!1);\n this.doc().scrollTop = this.doc().scrollHeight - this.doc().offsetHeight, this.reportProgress(), s(!0);\n }), e.register("unfocus", N.moduleName, (i, s) => {\n A(this.wnd), s(!0);\n }), e.register("scroll_protection", N.moduleName, (i, s) => {\n this.enableScrollProtection(), s(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], N.moduleName, (i, s) => s(!1)), e.register("focus", N.moduleName, (i, s) => {\n this.reportProgress(), s(!0);\n }), e.register("first_visible_locator", N.moduleName, (i, s) => {\n const r = yt(t, !0);\n e.send("first_visible_locator", r.serialize()), s(!0);\n }), e.log("WebPubSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(N.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("WebPubSnapper Unmounted"), !0;\n }\n};\nN.moduleName = "webpub_snapper";\nlet Lt = N;\nclass Ai {\n constructor(t, e) {\n this.window = t, this.copyHistory = [], this.lastSelectionLength = 0, this.lastSelectionTime = 0, this.options = e;\n }\n cleanupOldHistory(t) {\n this.copyHistory = this.copyHistory.filter(\n (i) => t - i.timestamp < 1e4\n ), this.copyHistory.length > this.options.historySize && (this.copyHistory = this.copyHistory.slice(-this.options.historySize));\n }\n isSuspiciousPattern(t) {\n return this.copyHistory.length < 3 ? !1 : this.copyHistory.filter(\n (s) => t - s.timestamp < 2e3\n // Last 2 seconds\n ).length >= 3 ? !0 : this.copyHistory.slice().sort((s, r) => s.timestamp - r.timestamp).every((s, r, o) => r === 0 ? !0 : s.length > o[r - 1].length * 1.5);\n }\n shouldAllowCopy(t) {\n if (!this.options.enabled) return !0;\n const e = this.window.getSelection();\n if (!e) return !0;\n const s = e.toString().length, r = this.window.document.body.innerText.length, o = Date.now();\n if (this.cleanupOldHistory(o), s < this.options.minThreshold)\n return this.copyHistory.push({\n timestamp: o,\n length: s,\n wasBlocked: !1\n }), !0;\n const c = o - this.lastSelectionTime < 100 && s > this.lastSelectionLength * 1.5, u = Math.min(\n r * this.options.maxSelectionPercent,\n this.options.absoluteMaxChars\n ), d = this.isSuspiciousPattern(o), f = s > u || c || d;\n return this.copyHistory.push({\n timestamp: o,\n length: s,\n wasBlocked: f\n }), f ? (t?.preventDefault(), !1) : (this.lastSelectionLength = s, this.lastSelectionTime = o, !0);\n }\n destroy() {\n this.lastSelectionLength = 0, this.lastSelectionTime = 0, this.copyHistory = [], this.options.enabled = !1;\n }\n}\nclass Ci {\n constructor(t = ke) {\n this.options = t, this.events = [], this.selectionStartTime = 0, this.lastSelectionTime = 0, this.lastSelectionPosition = 0, this.selectionPatterns = [], this.lastSelectedText = "";\n }\n analyze(t) {\n if (!t)\n return this.clear(), !1;\n const e = t.toString();\n if (e.length === 0)\n return this.clear(), !1;\n if (t.type !== "Range" || !t.rangeCount)\n return !1;\n const i = Date.now();\n if (e.length <= 50 || e === this.lastSelectedText)\n return !1;\n if (this.selectionStartTime === 0)\n return this.selectionStartTime = i, this.lastSelectedText = e, !1;\n if (i - this.selectionStartTime < 500)\n return !1;\n i - this.lastSelectionTime > 1e3 && (this.lastSelectionTime = i), this.selectionStartTime === 0 && (this.selectionStartTime = i), this.lastSelectedText = e;\n const r = this.analyzeSelectionPattern(t, i);\n return this.cleanup(i), r;\n }\n analyzeSelectionPattern(t, e) {\n if (!t.rangeCount) return !1;\n const i = t.getRangeAt(0), s = i.toString(), r = (e - this.selectionStartTime) / 1e3;\n if (s.length / Math.max(1, r) > this.options.maxSelectionsPerSecond) return !0;\n const a = i.startOffset, c = Math.abs(a - this.lastSelectionPosition);\n return this.selectionPatterns.push(c), this.selectionPatterns.length > this.options.historySize && (this.selectionPatterns.shift(), this.calculateVariance(this.selectionPatterns) < this.options.minVariance) ? !0 : (this.lastSelectionPosition = a, !1);\n }\n calculateVariance(t) {\n if (t.length === 0) return 0;\n const e = t.reduce((i, s) => i + s, 0) / t.length;\n return t.reduce((i, s) => i + Math.pow(s - e, 2), 0) / t.length;\n }\n cleanup(t) {\n this.events = this.events.filter((e) => t - e.timestamp <= 1e3);\n }\n clear() {\n this.events = [], this.selectionStartTime = 0, this.lastSelectionTime = 0, this.lastSelectionPosition = 0, this.selectionPatterns = [], this.lastSelectedText = "";\n }\n}\nclass xi {\n /**\n * Checks if the given keyboard event matches any of the provided key combinations\n */\n match(t, e) {\n for (const i of e)\n if (this.matchesCombo(t, i))\n return !0;\n return !1;\n }\n matchesCombo(t, e) {\n return t.keyCode === e.keyCode && this.matchesModifier(t.ctrlKey, e.ctrl) && this.matchesModifier(t.shiftKey, e.shift) && this.matchesModifier(t.altKey, e.alt) && this.matchesModifier(t.metaKey, e.meta);\n }\n matchesModifier(t, e) {\n return e === void 0 ? !t : t === e;\n }\n /**\n * Creates an event handler that will call the provided handler when any of the key combinations match\n */\n createKeyHandler(t, e) {\n return (i) => {\n this.match(i, t) && (i.preventDefault(), i.stopPropagation(), e(i));\n };\n }\n /**\n * Creates a standardized activity event for keyboard shortcuts\n */\n createActivityEvent(t, e, i, s) {\n let r, o;\n if (s) {\n const a = s.getSelection(), c = a?.toString() || "", d = (c && a?.rangeCount ? a.getRangeAt(0)?.getClientRects() : null)?.[0];\n d && c && (r = {\n text: c,\n x: d.x,\n y: d.y,\n width: d.width,\n height: d.height\n });\n const f = s.document.activeElement;\n f && f !== s.document.body && (o = Gt(f)?.outerHTML);\n }\n return {\n type: e,\n timestamp: Date.now(),\n key: t.key,\n code: t.code,\n keyCode: t.keyCode,\n ctrlKey: t.ctrlKey,\n altKey: t.altKey,\n shiftKey: t.shiftKey,\n metaKey: t.metaKey,\n targetFrameSrc: i,\n selectedText: r,\n interactiveElement: o\n };\n }\n /**\n * Creates handlers for keyboard shortcuts with centralized activity event dispatch\n */\n createKeyboardHandlers(t, e, i, s) {\n const r = [];\n return e.forEach((o) => {\n r.push(...o.keyCombos.map((a) => ({\n ...a,\n handler: (c) => {\n const u = o.type, d = this.createActivityEvent(c, u, t, s);\n i(d);\n }\n })));\n }), r;\n }\n /**\n * Creates a unified keyboard event handler that processes all shortcuts\n */\n createUnifiedHandler(t, e, i, s) {\n const r = this.createKeyboardHandlers(t, e, i, s);\n return (o) => {\n for (const a of r)\n if (this.match(o, [a])) {\n const c = a.suppressOnInteractiveElement;\n if (c) {\n const u = (s?.document ?? document).activeElement;\n if (Array.isArray(c) ? c.some((d) => u?.matches(d)) : ze(u)) return;\n }\n o.preventDefault(), o.stopPropagation(), a.handler(o);\n return;\n }\n };\n }\n}\nconst Y = class Y extends K {\n constructor() {\n super(...arguments), this.configApplied = !1, this.cleanupCallbacks = [], this.pointerMoved = !1, this.isContextMenuEnabled = !1, this.isDragAndDropEnabled = !1, this.isSelectionMonitoringEnabled = !1, this.isBulkCopyProtectionEnabled = !1, this.selectionAnalyzer = null, this.currentSelection = null, this.bulkCopyProtector = null, this.keyManager = new xi(), this.keyDownHandler = null, this.preventBulkCopy = (t) => {\n if (!this.isBulkCopyProtectionEnabled || !this.bulkCopyProtector)\n return !0;\n if (!this.bulkCopyProtector.shouldAllowCopy(t)) {\n t.preventDefault();\n const e = this.wnd.getSelection(), i = e?.toString() || "", r = (i ? e?.getRangeAt(0)?.getClientRects() : null)?.[0], o = {\n type: "bulk_copy",\n timestamp: Date.now(),\n clipboardTypes: t.clipboardData?.types ? [...t.clipboardData.types] : [],\n selectedText: r ? {\n text: i,\n x: r.x,\n y: r.y,\n width: r.width,\n height: r.height\n } : void 0,\n selectionLength: i.length,\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", o), !1;\n }\n return !0;\n }, this.handleSelection = (t) => {\n if (!this.isSelectionMonitoringEnabled || !this.wnd || !this.selectionAnalyzer)\n return;\n const e = this.wnd.getSelection();\n if (e) {\n if (this.currentSelection = e.toString(), this.selectionAnalyzer.analyze(e) && this.currentSelection) {\n const s = this.wnd.getSelection(), r = s?.toString() || "", a = (r && s?.rangeCount ? s.getRangeAt(0)?.getClientRects() : null)?.[0], c = {\n type: "suspicious_selection",\n timestamp: Date.now(),\n selectionLength: r.length,\n selectedText: {\n text: r,\n x: a?.x ?? 0,\n y: a?.y ?? 0,\n width: a?.width ?? 0,\n height: a?.height ?? 0\n },\n eventType: t?.type || "selectionchange",\n targetFrameSrc: this.wnd.location.href\n };\n this.comms?.send("content_protection", c);\n }\n } else\n this.currentSelection = null;\n }, this.onDragOver = (t) => {\n this.isDragAndDropEnabled && (t.preventDefault(), t.stopPropagation());\n }, this.onDragStart = (t) => {\n if (this.isDragAndDropEnabled) {\n t.preventDefault();\n const e = {\n type: "drag_detected",\n timestamp: Date.now(),\n dataTransferTypes: t.dataTransfer?.types ? [...t.dataTransfer.types] : [],\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", e), !1;\n } else\n return !0;\n }, this.onDrop = (t) => {\n if (this.isDragAndDropEnabled) {\n t.preventDefault();\n const e = t.dataTransfer, i = {\n type: "drop_detected",\n timestamp: Date.now(),\n dataTransferTypes: e?.types ? [...e.types] : [],\n fileCount: e?.files?.length || 0,\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", i), !1;\n } else\n return !0;\n }, this.onContext = (t) => {\n if (this.isContextMenuEnabled) {\n t.preventDefault();\n const e = this.wnd.getSelection(), i = e?.toString() || "", r = (i && e?.rangeCount ? e.getRangeAt(0)?.getClientRects() : null)?.[0], o = {\n timestamp: Date.now(),\n clientX: t.clientX,\n clientY: t.clientY,\n ...r && {\n selectedText: {\n text: i,\n x: r.x,\n y: r.y,\n width: r.width,\n height: r.height\n }\n },\n targetFrameSrc: this.wnd.location.href\n };\n this.comms?.send("context_menu", o);\n }\n }, this.onPointerUp = this.onPointUp.bind(this), this.onPointerMove = this.onPointMove.bind(this), this.onPointerDown = this.onPointDown.bind(this), this.onClicker = this.onClick.bind(this);\n }\n addContextMenuPrevention() {\n this.isContextMenuEnabled || !this.wnd || (this.wnd.document.addEventListener("contextmenu", this.onContext), this.isContextMenuEnabled = !0);\n }\n removeContextMenuPrevention() {\n !this.isContextMenuEnabled || !this.wnd || (this.wnd.document.removeEventListener("contextmenu", this.onContext), this.isContextMenuEnabled = !1);\n }\n addDragAndDropPrevention() {\n this.isDragAndDropEnabled || !this.wnd || (this.wnd.document.addEventListener("dragstart", this.onDragStart), this.wnd.document.addEventListener("dragover", this.onDragOver), this.wnd.document.addEventListener("drop", this.onDrop), this.isDragAndDropEnabled = !0);\n }\n removeDragAndDropPrevention() {\n !this.isDragAndDropEnabled || !this.wnd || (this.wnd.document.removeEventListener("dragstart", this.onDragStart), this.wnd.document.removeEventListener("dragover", this.onDragOver), this.wnd.document.removeEventListener("drop", this.onDrop), this.isDragAndDropEnabled = !1);\n }\n enableKeyboardPeripherals(t = []) {\n this.disableKeyboardPeripherals();\n const e = (i) => {\n this.comms?.send("keyboard_peripherals", i);\n };\n this.keyDownHandler = this.keyManager.createUnifiedHandler(this.wnd.location.href, t, e, this.wnd), this.wnd && this.wnd.document.addEventListener("keydown", this.keyDownHandler, {\n capture: !0\n });\n }\n disableKeyboardPeripherals() {\n this.wnd && this.keyDownHandler && (this.wnd.document.removeEventListener("keydown", this.keyDownHandler, {\n capture: !0\n }), this.keyDownHandler = null);\n }\n addBulkCopyProtection(t = {}) {\n if (this.isBulkCopyProtectionEnabled || !this.wnd) return;\n const e = Si, i = t ? { ...e, ...t } : e;\n this.bulkCopyProtector = new Ai(this.wnd, i), this.wnd.document.addEventListener("copy", this.preventBulkCopy, !0), this.wnd.document.addEventListener("cut", this.preventBulkCopy, !0), this.isBulkCopyProtectionEnabled = !0;\n }\n removeBulkCopyProtection() {\n !this.isBulkCopyProtectionEnabled || !this.wnd || (this.wnd.document.removeEventListener("copy", this.preventBulkCopy, !0), this.wnd.document.removeEventListener("cut", this.preventBulkCopy, !0), this.bulkCopyProtector?.destroy(), this.bulkCopyProtector = null, this.isBulkCopyProtectionEnabled = !1);\n }\n addSelectionMonitoring(t) {\n if (this.isSelectionMonitoringEnabled || !this.wnd) return;\n const e = t || ke;\n this.selectionAnalyzer = new Ci(e), this.wnd.document.addEventListener("selectionchange", this.handleSelection), this.isSelectionMonitoringEnabled = !0;\n }\n removeSelectionMonitoring() {\n !this.isSelectionMonitoringEnabled || !this.wnd || (this.wnd.document.removeEventListener("selectionchange", this.handleSelection), this.selectionAnalyzer?.clear(), this.selectionAnalyzer = null, this.isSelectionMonitoringEnabled = !1);\n }\n onPointUp(t) {\n const e = this.wnd.getSelection();\n if (e && e.toString()?.length > 0) {\n const s = e.getRangeAt(0)?.getClientRects();\n if (!s || s.length === 0)\n return;\n const r = s[0], o = {\n text: e.toString(),\n x: r.x,\n y: r.y,\n width: r.width,\n height: r.height,\n targetFrameSrc: this.wnd?.location?.href\n };\n this.comms.send("text_selected", o);\n }\n if (this.pointerMoved) {\n this.pointerMoved = !1;\n return;\n }\n if (!e?.isCollapsed || !t.isPrimary) return;\n const i = this.wnd.devicePixelRatio;\n t.preventDefault(), this.comms.send(t.pointerType === "touch" ? "tap" : "click", {\n defaultPrevented: t.defaultPrevented,\n x: t.clientX * i,\n y: t.clientY * i,\n targetFrameSrc: this.wnd.location.href,\n targetElement: t.target.outerHTML,\n interactiveElement: Gt(t.target)?.outerHTML,\n cssSelector: this.wnd._readium_cssSelectorGenerator.getCssSelector(t.target)\n }), this.pointerMoved = !1;\n }\n onPointMove(t) {\n if (t.movementY !== void 0 && t.movementX !== void 0) {\n (Math.abs(t.movementX) > 1 || Math.abs(t.movementY) > 1) && (this.pointerMoved = !0);\n return;\n }\n this.pointerMoved = !0;\n }\n onPointDown() {\n this.pointerMoved = !1;\n }\n onClick(t) {\n if (t.preventDefault(), !t.isTrusted) {\n const e = new PointerEvent("pointerup", {\n isPrimary: !0,\n pointerType: "mouse",\n // Not really a better choice than this\n clientX: t.clientX,\n clientY: t.clientY\n });\n Object.defineProperty(e, "target", { writable: !1, value: t.target }), Object.defineProperty(e, "defaultPrevented", { writable: !1, value: t.defaultPrevented }), this.onPointUp(e);\n }\n }\n registerProtectionHandlers() {\n this.comms?.register("peripherals_protection", Y.moduleName, (t, e) => {\n const i = t;\n if (!this.configApplied) {\n if (this.configApplied = !0, i.monitorSelection) {\n const s = typeof i.monitorSelection == "boolean" ? void 0 : i.monitorSelection;\n this.addSelectionMonitoring(s), this.comms?.log("Selection monitoring enabled");\n }\n typeof i.protectCopy == "object" ? (this.addBulkCopyProtection({\n enabled: !0,\n ...i.protectCopy\n }), this.comms?.log("Copy protection enabled (limited)")) : i.protectCopy === !0 && (this.addBulkCopyProtection({\n enabled: !0,\n maxSelectionPercent: 0,\n minThreshold: 0,\n absoluteMaxChars: 0\n }), this.comms?.log("Copy protection enabled")), i.disableContextMenu && (this.addContextMenuPrevention(), this.comms?.log("Context menu protection enabled")), i.disableDragAndDrop && (this.addDragAndDropPrevention(), this.comms?.log("Drag and drop protection enabled"));\n }\n e(!0);\n }), this.comms?.register("keyboard_peripherals", Y.moduleName, (t, e) => {\n const i = t;\n i && i.length > 0 && (this.enableKeyboardPeripherals(i), this.comms?.log(`Keyboard peripherals enabled: ${i.map((s) => s.type).join(", ")}`)), e(!0);\n });\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.registerProtectionHandlers(), t.document.addEventListener("pointerdown", this.onPointerDown), t.document.addEventListener("pointerup", this.onPointerUp), t.document.addEventListener("pointermove", this.onPointerMove), t.document.addEventListener("click", this.onClicker), e.log("Peripherals Mounted"), !0;\n }\n unmount(t, e) {\n return this.removeBulkCopyProtection(), this.removeSelectionMonitoring(), this.removeContextMenuPrevention(), this.removeDragAndDropPrevention(), this.disableKeyboardPeripherals(), this.cleanupCallbacks.forEach((i) => i()), this.cleanupCallbacks = [], t.document.removeEventListener("pointerdown", this.onPointerDown), t.document.removeEventListener("pointerup", this.onPointerUp), t.document.removeEventListener("pointermove", this.onPointerMove), t.document.removeEventListener("click", this.onClicker), e.unregisterAll(Y.moduleName), this.configApplied = !1, e.log("Peripherals Unmounted"), !0;\n }\n};\nY.moduleName = "peripherals";\nlet Ot = Y;\nconst et = class et extends K {\n constructor() {\n super(...arguments), this.mediaPlayingCount = 0, this.allAnimations = /* @__PURE__ */ new Set();\n }\n wndOnErr(t) {\n this.comms?.send("error", {\n message: t.message,\n filename: t.filename,\n lineno: t.lineno,\n colno: t.colno\n });\n }\n unblock(t) {\n for (t._readium_blockEvents = !1; t._readium_blockedEvents?.length > 0; ) {\n const e = t._readium_blockedEvents.shift();\n switch (e[0]) {\n case 0:\n Reflect.apply(e[1], e[2], e[3]);\n break;\n case 1:\n const i = e[1], s = e[2];\n t.removeEventListener(i.type, t._readium_eventBlocker, !0);\n const r = new Event(i.type, {\n bubbles: i.bubbles,\n cancelable: i.cancelable\n });\n s ? s.dispatchEvent(r) : t.dispatchEvent(r);\n break;\n }\n }\n }\n onMediaPlayEvent() {\n this.mediaPlayingCount++, this.comms?.send("media_play", this.mediaPlayingCount);\n }\n onMediaPauseEvent() {\n this.mediaPlayingCount > 0 && this.mediaPlayingCount--, this.comms?.send("media_pause", this.mediaPlayingCount);\n }\n pauseAllMedia(t) {\n const e = t.document.querySelectorAll("audio,video");\n for (let i = 0; i < e.length; i++)\n e[i].pause();\n }\n mount(t, e) {\n this.comms = e, t.addEventListener(\n "error",\n this.wndOnErr,\n !1\n ), Reflect.defineProperty(t.navigator, "epubReadingSystem", {\n value: {\n name: "readium-ts-toolkit",\n version: "2.4.2",\n hasFeature: (s, r = "") => {\n switch (s) {\n case "dom-manipulation":\n return !0;\n case "layout-changes":\n return !0;\n case "touch-events":\n return !0;\n case "mouse-events":\n return !0;\n case "keyboard-events":\n return !0;\n case "spine-scripting":\n return !0;\n case "embedded-web-content":\n return !0;\n default:\n return !1;\n }\n }\n },\n writable: !1\n }), "getAnimations" in t.document && t.document.getAnimations().forEach((s) => {\n s.cancel(), this.allAnimations.add(s);\n }), e.register("activate", et.moduleName, (s, r) => {\n this.allAnimations.forEach((o) => {\n o.cancel(), o.play();\n }), r(!0);\n }), e.register("unfocus", et.moduleName, (s, r) => {\n this.pauseAllMedia(t), this.allAnimations.forEach((o) => o.pause()), r(!0);\n });\n const i = t.document.querySelectorAll("audio,video");\n for (let s = 0; s < i.length; s++) {\n const r = i[s];\n r.addEventListener("play", this.onMediaPlayEvent, {\n passive: !0\n }), r.addEventListener("pause", this.onMediaPauseEvent, {\n passive: !0\n });\n }\n return e.log("Setup Mounted"), !0;\n }\n unmount(t, e) {\n return t.removeEventListener("error", this.wndOnErr), t.removeEventListener("play", this.onMediaPlayEvent), t.removeEventListener("pause", this.onMediaPauseEvent), this.allAnimations.forEach((i) => i.cancel()), this.allAnimations.clear(), e.log("Setup Unmounted"), !0;\n }\n};\net.moduleName = "setup";\nlet ft = et;\nconst we = "readium-viewport", W = class W extends ft {\n onViewportWidthChanged(t) {\n const e = t.target;\n st(e, "--RS__viewportWidth", `${e.innerWidth}px`);\n }\n mount(t, e) {\n if (!super.mount(t, e)) return !1;\n const i = t.document.createElement("meta");\n return i.dataset.readium = "true", i.setAttribute("name", "viewport"), i.setAttribute("id", we), i.setAttribute(\n "content",\n "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no"\n ), t.document.head.appendChild(i), t.addEventListener("orientationchange", this.onViewportWidthChanged), t.addEventListener("resize", this.onViewportWidthChanged), this.onViewportWidthChanged({\n target: t\n }), e.register("get_properties", W.moduleName, (s, r) => {\n Vt(t), r(!0);\n }), e.register("update_properties", W.moduleName, (s, r) => {\n s["--RS__viewportWidth"] = `${t.innerWidth}px`, De(t, s), r(!0);\n }), e.register("set_property", W.moduleName, (s, r) => {\n const o = s;\n st(t, o[0], o[1]), r(!0);\n }), e.register("remove_property", W.moduleName, (s, r) => {\n gt(t, s), r(!0);\n }), e.register("activate", W.moduleName, (s, r) => {\n this.unblock(t), r(!0);\n }), e.log("ReflowableSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(W.moduleName), t.document.head.querySelector(`#${we}`)?.remove(), t.removeEventListener("orientationchange", this.onViewportWidthChanged), e.log("ReflowableSetup Unmounted"), super.unmount(t, e);\n }\n};\nW.moduleName = "reflowable_setup";\nlet Rt = W;\nconst Se = "readium-fixed-style", z = class z extends ft {\n mount(t, e) {\n if (!super.mount(t, e)) return !1;\n t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "paginated");\n const i = t.document.createElement("style");\n return i.id = Se, i.dataset.readium = "true", i.textContent = `\n html, body {\n text-size-adjust: none;\n -ms-text-size-adjust: none;\n -webkit-text-size-adjust: none;\n -moz-text-size-adjust: none;\n\n /* Fight Safari pinches */\n touch-action: none !important;\n min-height: 100%;\n\n /*cursor: var() TODO*/\n }`, t.document.head.appendChild(i), e.register("set_property", z.moduleName, (s, r) => {\n const o = s;\n st(t, o[0], o[1]), r(!0);\n }), e.register("remove_property", z.moduleName, (s, r) => {\n gt(t, s), r(!0);\n }), e.register("first_visible_locator", z.moduleName, (s, r) => r(!1)), e.register("unfocus", z.moduleName, (s, r) => {\n A(t), r(!0);\n }), e.register([\n "focus",\n "go_next",\n "go_prev",\n "go_id",\n "go_end",\n "go_start",\n "go_text",\n "go_progression"\n ], z.moduleName, (s, r) => r(!0)), e.register("activate", z.moduleName, (s, r) => {\n this.unblock(t), r(!0);\n }), e.log("FixedSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(z.moduleName), t.document.getElementById(Se)?.remove(), e.log("FixedSetup Unmounted"), super.unmount(t, e);\n }\n};\nz.moduleName = "fixed_setup";\nlet Dt = z;\nconst U = class U extends K {\n wndOnErr(t) {\n this.comms?.send("error", {\n message: t.message,\n filename: t.filename,\n lineno: t.lineno,\n colno: t.colno\n });\n }\n mount(t, e) {\n return this.comms = e, t.addEventListener(\n "error",\n this.wndOnErr,\n !1\n ), e.register("get_properties", U.moduleName, (i, s) => {\n Vt(t), s(!0);\n }), e.register("update_properties", U.moduleName, (i, s) => {\n De(t, i), s(!0);\n }), e.register("set_property", U.moduleName, (i, s) => {\n const r = i;\n st(t, r[0], r[1]), s(!0);\n }), e.register("remove_property", U.moduleName, (i, s) => {\n gt(t, i), s(!0);\n }), e.register("activate", U.moduleName, (i, s) => {\n s(!0);\n }), e.log("WebPubSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(U.moduleName), t.removeEventListener("error", this.wndOnErr), e.log("WebPubSetup Unmounted"), !0;\n }\n};\nU.moduleName = "webpub_setup";\nlet It = U;\nconst it = class it extends K {\n constructor() {\n super(...arguments), this.styleElement = null, this.beforePrintHandler = null, this.configApplied = !1;\n }\n setupPrintProtection(t, e) {\n if (!e.disable) return;\n const i = t.document.createElement("style");\n i.textContent = `\n @media print {\n body * {\n display: none !important;\n }\n body::after {\n content: "${e.watermark || "Printing has been disabled"}";\n font-size: 200%;\n display: block;\n text-align: center;\n margin-top: 50vh;\n transform: translateY(-50%);\n }\n }\n `, t.document.head.appendChild(i), this.styleElement = i, this.beforePrintHandler = (s) => (s.preventDefault(), !1), t.addEventListener("beforeprint", this.beforePrintHandler);\n }\n registerPrintHandlers() {\n this.comms?.register("print_protection", it.moduleName, (t) => {\n const e = t;\n return this.configApplied || (this.configApplied = !0, this.setupPrintProtection(this.wnd, e), this.comms?.log("Print protection configuration applied")), !0;\n });\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.registerPrintHandlers(), !0;\n }\n unmount(t, e) {\n return this.beforePrintHandler && (t.removeEventListener("beforeprint", this.beforePrintHandler), this.beforePrintHandler = null), this.styleElement?.parentNode && (this.styleElement.parentNode.removeChild(this.styleElement), this.styleElement = null), this.comms?.unregisterAll(it.moduleName), this.configApplied = !1, !0;\n }\n};\nit.moduleName = "print_protection";\nlet zt = it;\nconst Ee = "readium-cjk-vertical-snapper-style", L = class L extends X {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollLeft = 0, this.isResizing = !1, this.resizeDebounce = null, this.verticalLR = !1, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollLeft = Math.abs(this.doc().scrollLeft), this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = Math.abs(this.doc().scrollLeft), i = e - this.lastScrollLeft;\n if (this.lastScrollLeft = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const s = Date.now(), r = s - (this.lastScrollTime || s);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n // In vertical-rl, norm increases when scrolling forward (toward left/end),\n // so deltaX > 0 = going forward.\n i > 0 ? "down" : "up",\n Math.abs(i),\n r\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "left" : "right",\n targetElement: a\n });\n }\n this.lastScrollTime = s;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n /** Total horizontally scrollable distance (magnitude). */\n scrollable() {\n return Math.max(0, this.doc().scrollWidth - this.wnd.innerWidth);\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = this.doc().scrollWidth, e = this.wnd.innerWidth, i = Math.max(1, t - e), s = Math.abs(this.doc().scrollLeft), r = Math.max(0, Math.min(1, s / i)), o = Math.max(0, Math.min(1, (s + e) / t));\n this.comms.send("progress", {\n start: r,\n end: o\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new bt($t), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollLeft = 0, this.isResizing = !1, this.verticalLR = ui(t), this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "scrolling");\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = Ee, i.textContent = `\n * {\n scrollbar-width: none;\n }\n body::-webkit-scrollbar {\n display: none;\n }\n html {\n overflow-x: auto !important;\n overflow-y: hidden !important;\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", L.moduleName, () => {\n Ft(this.wnd);\n const s = this.doc().scrollLeft;\n this.verticalLR ? this.doc().scrollLeft = s > 1 ? s - 1 : s + 1 : this.doc().scrollLeft = s < -1 ? s + 1 : s - 1, this.doc().scrollLeft = s;\n }), e.register("go_progression", L.moduleName, (s, r) => {\n const o = s;\n if (o < 0 || o > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n const a = this.scrollable() * o;\n this.doc().scrollLeft = this.verticalLR ? a : -a, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_id", L.moduleName, (s, r) => {\n const o = t.document.getElementById(s);\n if (!o) {\n r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollLeft += o.getBoundingClientRect().left - t.innerWidth / 2, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_text", L.moduleName, (s, r) => {\n let o;\n Array.isArray(s) && (s.length > 1 && (o = s[1]), s = s[0]);\n const a = H.deserialize(s), c = rt(this.wnd.document, new k({\n href: t.location.href,\n type: "text/html",\n text: a,\n locations: o ? new C({\n otherLocations: /* @__PURE__ */ new Map([["cssSelector", o]])\n }) : void 0\n }));\n if (!c) {\n r(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollLeft += c.getBoundingClientRect().left - t.innerWidth / 2, this.reportProgress(), A(this.wnd), r(!0);\n });\n }), e.register("go_start", L.moduleName, (s, r) => {\n if (this.doc().scrollLeft === 0) return r(!1);\n this.doc().scrollLeft = 0, this.reportProgress(), r(!0);\n }), e.register("go_end", L.moduleName, (s, r) => {\n if (Math.abs(this.doc().scrollLeft) === this.scrollable()) return r(!1);\n this.doc().scrollLeft = this.verticalLR ? this.scrollable() : -this.scrollable(), this.reportProgress(), r(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], L.moduleName, (s, r) => r(!1)), e.register("unfocus", L.moduleName, (s, r) => {\n A(this.wnd), r(!0);\n }), e.register("scroll_protection", L.moduleName, (s, r) => {\n this.enableScrollProtection(), r(!0);\n }), e.register("focus", L.moduleName, (s, r) => {\n this.reportProgress(), r(!0);\n }), e.register("first_visible_locator", L.moduleName, (s, r) => {\n const o = yt(t, !0);\n this.comms.send("first_visible_locator", o.serialize()), r(!0);\n }), e.log("CJKVerticalSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(L.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), t.document.getElementById(Ee)?.remove(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("CJKVerticalSnapper Unmounted"), !0;\n }\n};\nL.moduleName = "cjk_vertical_snapper";\nlet Mt = L;\nconst Ti = [\n "fixed_setup",\n "decorator",\n "peripherals",\n "print_protection"\n], Pi = [\n "reflowable_setup",\n "decorator",\n "peripherals",\n "column_snapper",\n "scroll_snapper",\n "cjk_vertical_snapper",\n "print_protection"\n], Ni = [\n "webpub_setup",\n "webpub_snapper",\n "decorator",\n "peripherals",\n "print_protection"\n], Ae = new Map([\n // All modules go here\n Dt,\n Rt,\n It,\n Lt,\n Ot,\n Tt,\n Pt,\n Nt,\n Mt,\n zt\n].map((n) => [n.moduleName, n]));\nclass Li {\n /**\n * @param wnd Window instance to operate on\n * @param initialModules List of initial modules to load\n */\n constructor(t = window, e = []) {\n this.loadedModules = [], this.wnd = t, this.comms = new Be(t);\n const i = [...new Set(e)];\n if (i.length) {\n if (typeof t > "u")\n throw Error("Loader is not in a web browser");\n t.parent !== t && this.comms.log("Loader is probably in a frame"), this.loadedModules = i.map((s) => {\n const r = this.loadModule(s);\n if (r)\n return r.mount(this.wnd, this.comms), r;\n }).filter((s) => s !== void 0);\n }\n }\n loadModule(t) {\n const e = Ae.get(t);\n return e === void 0 ? (this.comms.log(`Module "${name}" does not exist in the library`), e) : new e();\n }\n /**\n * Add a module by name\n * @param moduleName Module name\n * @returns Success\n */\n addModule(t) {\n const e = this.loadModule(t);\n return !e || !e.mount(this.wnd, this.comms) ? !1 : (this.loadedModules.push(e), !0);\n }\n /**\n * Remove a module by name\n * @param moduleName Module name\n * @returns Success\n */\n removeModule(t) {\n const e = Ae.get(t);\n if (e === void 0)\n return this.comms.log(`Module "${t}" does not exist in the library`), !1;\n const i = this.loadedModules.findIndex((s) => s instanceof e);\n return i < 0 ? !1 : (this.loadedModules[i].unmount(this.wnd, this.comms), this.loadedModules.splice(i, 1), !0);\n }\n /**\n * Unmount and remove all modules\n */\n destroy() {\n this.comms.destroy(), this.loadedModules.forEach((t) => t.unmount(this.wnd, this.comms)), this.loadedModules = [];\n }\n}\nconst Oi = {\n type: "developer_tools",\n keyCombos: [\n { keyCode: 73, meta: !0, alt: !0 },\n // Cmd+Option+I\n { keyCode: 73, ctrl: !0, shift: !0 },\n // Ctrl+Shift+I\n { keyCode: 74, meta: !0, alt: !0 },\n // Cmd+Option+J\n { keyCode: 74, ctrl: !0, shift: !0 },\n // Ctrl+Shift+J\n { keyCode: 85, meta: !0, alt: !0 },\n // Cmd+Option+U\n { keyCode: 67, meta: !0, alt: !0 },\n // Cmd+Option+C\n { keyCode: 67, meta: !0, shift: !0 },\n // Cmd+Shift+C\n { keyCode: 67, ctrl: !0, shift: !0 },\n // Ctrl+Shift+C\n { keyCode: 65, meta: !0, alt: !0 },\n // Cmd+Option+A\n { keyCode: 84, meta: !0, shift: !0, alt: !0 },\n // Cmd+Shift+Option+T\n { keyCode: 67, shift: !0, alt: !0 },\n // Shift+Option+C\n { keyCode: 123 },\n // F12\n { keyCode: 123, shift: !0 },\n // Shift+F12\n { keyCode: 123, ctrl: !0, shift: !0 },\n // Ctrl+Shift+F12\n { keyCode: 123, meta: !0, alt: !0 }\n // Cmd+Option+F12\n ]\n}, Ri = {\n type: "select_all",\n keyCombos: [\n { keyCode: 65, meta: !0 },\n // Cmd+A\n { keyCode: 65, ctrl: !0 }\n // Ctrl+A\n ]\n}, Di = {\n type: "print",\n keyCombos: [\n { keyCode: 80, meta: !0 },\n // Cmd+P\n { keyCode: 80, ctrl: !0 },\n // Ctrl+P\n { keyCode: 80, meta: !0, shift: !0 },\n // Cmd+Shift+P\n { keyCode: 80, ctrl: !0, shift: !0 },\n // Ctrl+Shift+P\n { keyCode: 80, meta: !0, alt: !0 },\n // Cmd+Alt+P\n { keyCode: 80, ctrl: !0, alt: !0 }\n // Ctrl+Alt+P\n ]\n}, Ii = {\n type: "save",\n keyCombos: [\n { keyCode: 83, meta: !0 },\n // Cmd+S\n { keyCode: 83, ctrl: !0 }\n // Ctrl+S\n ]\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/index.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/it-DFOBoXGy.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ e),\n/* harmony export */ publication: () => (/* binding */ i)\n/* harmony export */ });\nconst i = /* @__PURE__ */ JSON.parse(`{"format":{"audiobook":"Audiolibro","audiobookJSON":"Audiobook Manifest","cbz":"Comic book archive","divina":"Divina Publication","divinaJSON":"Divina Publication Manifest","epub":"EPUB","lcpa":"Audiolibro protetto con LCP","lcpdf":"PDF protetto con LCP","lcpl":"Licenza LCP","pdf":"PDF","rwp":"Readium Web Publication","rwpm":"Readium Web Publication Manifest","zab":"Audiobook Archive","zip":"ZIP Archive"},"kind":{"audiobook_many":"audiolibri","audiobook_one":"audiolibro","audiobook_other":"audiolibri","book_many":"libri","book_one":"libro","book_other":"libri","comic_many":"fumetti","comic_one":"fumetto","comic_other":"fumetti","document_many":"documenti","document_one":"documento","document_other":"documenti"},"metadata":{"accessibility":{"display-guide":{"accessibility-summary":{"no-metadata":"Nessuna informazione disponibile","publisher-contact":"Per ulteriori informazioni sull\'accessibilità di questa risorsa, contattare l\'editore: ","title":"Informazioni aggiuntive sull\'accessibilità fornite dall\'editore"},"additional-accessibility-information":{"aria":{"compact":"Ruoli ARIA inclusi","descriptive":"Il contenuto è semanticamente arricchito con ruoli ARIA per ottimizzare l\'organizzazione e facilitare la navigazione"},"audio-descriptions":"Descrizioni audio","braille":"Braille","color-not-sole-means-of-conveying-information":"Il colore non è l\'unico mezzo per trasmettere informazioni","dyslexia-readability":"Leggibilità adatta alla dislessia","full-ruby-annotations":"Annotazioni complete in Ruby","high-contrast-between-foreground-and-background-audio":"Elevato contrasto tra audio principale e sottofondo","high-contrast-between-text-and-background":"Contrasto elevato tra testo in primo piano e sfondo","large-print":"Stampa a caratteri ingranditi","page-breaks":{"compact":"Interruzioni di pagina incluse","descriptive":"Interruzioni di pagina identiche alla versione originale a stampa"},"ruby-annotations":"Alcune annotazioni in Ruby","sign-language":"Lingua dei segni","tactile-graphics":{"compact":"Grafica tattile inclusa","descriptive":"La grafica tattile è stata integrata per facilitare l\'accesso agli elementi visivi alle persone non vedenti"},"tactile-objects":"Oggetti 3D tattili","text-to-speech-hinting":"Pronuncia migliorata per la sintesi vocale","title":"Ulteriori informazioni sull\'accessibilità","ultra-high-contrast-between-text-and-background":"Contrasto molto elevato tra testo e sfondo","visible-page-numbering":"Numerazione delle pagine visibile","without-background-sounds":"Nessun suono in sottofondo"},"conformance":{"a":{"compact":"Questa pubblicazione soddisfa gli standard minimi di accessibilità","descriptive":"La pubblicazione contiene una dichiarazione di conformità che attesta il rispetto degli standard EPUB Accessibility e WCAG 2 Livello A"},"aa":{"compact":"Questa pubblicazione soddisfa gli standard di accessibilità accettati","descriptive":"La pubblicazione contiene una dichiarazione di conformità che attesta il rispetto degli standard EPUB Accessibility e WCAG 2 Livello AAA"},"aaa":{"compact":"Questa pubblicazione supera gli standard di accessibilità","descriptive":"La pubblicazione contiene una dichiarazione di conformità che attesta il rispetto degli standard EPUB Accessibility e WCAG 2 Livello AAA"},"certifier":"La pubblicazione è stata certificata da ","certifier-credentials":"Le credenziali del certificatore sono ","details":{"certification-info":"La pubblicazione è stata certificata il ","certifier-report":"Per ulteriori informazioni, consultare il report di accessibilità del certificatore","claim":"Questa pubblicazione è conforme ai requisiti di","epub-accessibility-1-0":"EPUB Accessibility 1.0","epub-accessibility-1-1":"EPUB Accessibility 1.1","level-a":"Livello A","level-aa":"Livello AA","level-aaa":"Livello AAA","wcag-2-0":{"compact":"WCAG 2.0","descriptive":"Linee guida per l\'accessibilità dei contenuti web (WCAG) 2.0"},"wcag-2-1":{"compact":"WCAG 2.1","descriptive":"Linee guida per l\'accessibilità dei contenuti web (WCAG) 2.1"},"wcag-2-2":{"compact":"WCAG 2.2","descriptive":"Linee guida per l\'accessibilità dei contenuti web (WCAG) 2.2"}},"details-title":"Informazioni dettagliate sulla conformità","no":"Nessuna informazione disponibile","title":"Conformità","unknown-standard":"Nessuna indicazione sugli standard d\'accessibilità"},"hazards":{"flashing":{"compact":"Contenuto lampeggiante","descriptive":"La pubblicazione contiene contenuti lampeggianti che possono causare crisi d\'epilessia fotosensibile"},"flashing-none":{"compact":"Nessun contenuto lampeggiante","descriptive":"La pubblicazione non presenta contenuti lampeggianti che possono causare crisi d\'epilessia fotosensibile"},"flashing-unknown":{"compact":"Nessuna informazione sulla presenza di contenuti lampeggianti","descriptive":"Non è stato possibile determinare la presenza di contenuti lampeggianti che possono causare crisi d\'epilessia fotosensibile"},"motion":{"compact":"Simulazione del movimento","descriptive":"La pubblicazione contiene simulazioni di movimento che possono provocare cinetosi"},"motion-none":{"compact":"Nessun rischio di simulazione del movimento","descriptive":"La pubblicazione non contiene simulazioni di movimento che possono causare la malattia di movimento"},"motion-unknown":{"compact":"Nessuna informazione relativa alla presenza di simulazioni di movimento","descriptive":"Non è stato possibile determinare la presenza di contenuti che possono provocare cinetosi"},"no-metadata":"Nessuna informazione disponibile","none":{"compact":"Nessuna problematica","descriptive":"La pubblicazione non presenta contenuti a rischio di simulazione di movimento, di suoni, o di contenuti lampeggianti"},"sound":{"compact":"Suoni","descriptive":"La pubblicazione contiene suoni che possono causare problemi di sensibilità"},"sound-none":{"compact":"Nessun rischio acustico","descriptive":"La pubblicazione non contiene suoni che possono causare problemi di sensibilità"},"sound-unknown":{"compact":"Nessuna informazione sulla presenza di suoni","descriptive":"Non è stato possibile determinare la presenza di suoni che potrebbero causare problemi di sensibilità"},"title":"Problematiche","unknown":"La presenza di rischi è sconosciuta"},"legal-considerations":{"exempt":{"compact":"Dichiara di godere dell\'esenzione d\'accessibilità in alcune giurisdizioni","descriptive":"Questa risorsa gode dell\'esenzione d\'accessibilità in alcune giurisdizioni"},"no-metadata":"Nessuna informazione disponibile","title":"Note legali"},"navigation":{"index":{"compact":"Indice analitico interattivo","descriptive":"Indice analitico con link alle voci di riferimento"},"no-metadata":"Nessuna informazione disponibile","page-navigation":{"compact":"Vai alla pagina","descriptive":"Sono presenti i riferimenti ai numeri di pagina della versione a stampa corrispondente"},"structural":{"compact":"Intestazioni","descriptive":"Contiene elementi come titoli, elenchi e tabelle per permettere una navigazione strutturata"},"title":"Navigazione","toc":{"compact":"Indice interattivo","descriptive":"L’indice permette l’accesso diretto a tutti i capitoli tramite link"}},"rich-content":{"accessible-chemistry-as-latex":{"compact":"Formule chimiche in LaTeX","descriptive":"Formule chimiche in formato accessibile (LaTeX)"},"accessible-chemistry-as-mathml":{"compact":"Formule chimiche in MathML","descriptive":"Formule chimiche in formato accessibile (MathML)"},"accessible-math-as-latex":{"compact":"Matematica in LaTeX","descriptive":"Formule matematiche in formato accessibile (LaTeX)"},"accessible-math-described":"Sono disponibili descrizioni testuali per le formule matematiche","closed-captions":{"compact":"Sottotitoli disponibili per i video","descriptive":"Per i video sono disponibili dei sottotitoli"},"extended-descriptions":"Le immagini complesse presentano descrizioni estese","math-as-mathml":{"compact":"Matematica in MathML","descriptive":"Formule matematiche in formato accessibile (MathML)"},"open-captions":{"compact":"I video hanno i sottotitoli","descriptive":"I video inclusi nella pubblicazione hanno i sottotitoli"},"title":"Contenuti arricchiti","transcript":"Trascrizioni fornite","unknown":"Nessuna informazione disponibile"},"ways-of-reading":{"nonvisual-reading":{"alt-text":{"compact":"Immagini descritte","descriptive":"Le immagini sono descritte da un testo"},"no-metadata":"Nessuna informazione sulla lettura non visiva","none":{"compact":"Non leggibile con lettura ad alta voce o in braille","descriptive":"Il contenuto non è leggibile con la lettura ad alta voce o in braille"},"not-fully":{"compact":"Non è interamente leggibile con lettura ad alta voce o in braille","descriptive":"Non tutti i contenuti potranno essere letti con lettura ad alta voce o in braille"},"readable":{"compact":"Interamente leggibile con lettura ad alta voce o in braille","descriptive":"Tutti i contenuti possono essere letti con la lettura ad alta voce o con il display braille"}},"prerecorded-audio":{"complementary":{"compact":"Clip audio preregistrate","descriptive":"Le clip audio preregistrate sono integrate nel contenuto"},"no-metadata":"Non sono disponibili informazioni sull\'audio preregistrato","only":{"compact":"Solo audio preregistrato","descriptive":"Audiolibro senza testi alternativi"},"synchronized":{"compact":"Audio preregistrato sincronizzato con il testo","descriptive":"Tutti i contenuti sono disponibili come audio preregistrato sincronizzato con il testo"}},"title":"Leggibilità","visual-adjustments":{"modifiable":{"compact":"La formattazione del testo e il layout della pagina possono essere modificati","descriptive":"La formattazione del testo e il layout della pagina possono essere modificati in base alle funzionalità presenti nella soluzione di lettura (ingrandimento dei caratteri del testo, modifica dei colori e dei contrasti per il testo e lo sfondo, modifica degli spazi tra lettere, parole, frasi e paragrafi)"},"unknown":"Non sono disponibili informazioni sulla possibilità di formattare il testo","unmodifiable":{"compact":"La formattazione del testo e il display della pagina non possono essere modificati","descriptive":"Il layout di testo e pagina non può essere modificato poiché l\'esperienza di lettura è vicina a una versione di stampa, ma i sistemi di lettura possono ancora fornire opzioni di zoom"}}}}},"altIdentifier_many":"identificatori alternativi","altIdentifier_one":"identificatore alternativo","altIdentifier_other":"identificatori alternativi","artist_many":"","artist_one":"artista","artist_other":"artisti","author_many":"","author_one":"autore","author_other":"autori","collection_many":"","collection_one":"collana","collection_other":"collane","colorist_many":"","colorist_one":"colorista","colorist_other":"coloristi","contributor_many":"","contributor_one":"contributore","contributor_other":"contributori","description":"descrizione","duration":"durata","editor_many":"","editor_one":"editor","editor_other":"editori","identifier_many":"identificatori","identifier_one":"identificatore","identifier_other":"identificatori","illustrator_many":"","illustrator_one":"illustratore","illustrator_other":"illustratori","imprint_many":"","imprint_one":"marca editoriale","imprint_other":"marche editoriali","inker_many":"","inker_one":"inchiostratore","inker_other":"inchiostratori","language_many":"","language_one":"lingua","language_other":"lingue","letterer_many":"letteristi","letterer_one":"letterista","letterer_other":"letteristi","modified":"Data di modifica","narrator_many":"","narrator_one":"narratore","narrator_other":"narratori","numberOfPages":"impaginazione versione cartacea","penciler_many":"","penciler_one":"disegnatore","penciler_other":"disegnatori","published":"Data di pubblicazione","publisher_many":"","publisher_one":"editore","publisher_other":"editori","series_many":"","series_one":"serie","series_other":"serie","subject_many":"","subject_one":"categoria","subject_other":"categorie","subtitle":"sottotitolo","title":"titolo","translator_many":"","translator_one":"traduttore","translator_other":"traduttori"}}`), e = {\n publication: i\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/it-DFOBoXGy.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/pt_PT-Di3sVjze.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ a),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "Sem informação disponível", "publisher-contact": "Para mais informações sobre a acessibilidade deste produto, contacte a editora: ", title: "Resumo de acessibilidade" }, "additional-accessibility-information": { aria: { compact: "Inclui funções ARIA", descriptive: "O conteúdo foi otimizado com funções ARIA para melhorar a organização e facilitar a navegação" }, "audio-descriptions": "Descrições em áudio", braille: "Braille", "color-not-sole-means-of-conveying-information": "A cor não é o único meio de transmitir informação", "dyslexia-readability": "Otimizado para dislexia", "full-ruby-annotations": "Anotações Ruby completas", "high-contrast-between-foreground-and-background-audio": "Alto contraste entre som principal e fundo", "high-contrast-between-text-and-background": "Alto contraste entre texto e fundo", "large-print": "Impressão ampliada", "page-breaks": { compact: "Inclui quebras de página", descriptive: "Inclui quebras de página da fonte impressa original" }, "ruby-annotations": "Algumas anotações Ruby", "sign-language": "Língua gestual", "tactile-graphics": { compact: "Inclui gráficos táteis", descriptive: "Inclui gráficos táteis que facilitam o acesso a elementos visuais para pessoas cegas" }, "tactile-objects": "Objetos táteis 3D", "text-to-speech-hinting": "Sugestões para leitura em voz alta", title: "Informação adicional de acessibilidade", "ultra-high-contrast-between-text-and-background": "Contraste muito elevado entre texto e fundo", "visible-page-numbering": "Numeração de páginas visível", "without-background-sounds": "Sem sons de fundo" }, conformance: { a: { compact: "Cumpre as normas mínimas de acessibilidade", descriptive: "A publicação contém uma declaração de conformidade que indica que cumpre o padrão EPUB Accessibility e WCAG 2 nível A" }, aa: { compact: "Cumpre as normas aceites de acessibilidade", descriptive: "A publicação contém uma declaração de conformidade que indica que cumpre o padrão EPUB Accessibility e WCAG 2 nível AA" }, aaa: { compact: "Excede as normas aceites de acessibilidade", descriptive: "A publicação contém uma declaração de conformidade que indica que cumpre o padrão EPUB Accessibility e WCAG 2 nível AAA" }, certifier: "A publicação foi certificada por ", "certifier-credentials": "As credenciais do certificador são ", details: { "certification-info": "A publicação foi certificada em ", "certifier-report": "Para mais informações, consulte o relatório do certificador", claim: "Esta publicação declara conformidade com", "epub-accessibility-1-0": "EPUB Accessibility 1.0", "epub-accessibility-1-1": "EPUB Accessibility 1.1", "level-a": "Nível A", "level-aa": "Nível AA", "level-aaa": "Nível AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "Diretrizes de Acessibilidade para Conteúdo Web (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "Diretrizes de Acessibilidade para Conteúdo Web (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "Diretrizes de Acessibilidade para Conteúdo Web (WCAG) 2.2" } }, "details-title": "Detalhes de conformidade", no: "Sem informação disponível", title: "Conformidade", "unknown-standard": "Não foi possível determinar a conformidade com as normas de acessibilidade aceites para esta publicação" }, hazards: { flashing: { compact: "Conteúdo intermitente", descriptive: "A publicação contém conteúdo intermitente que pode causar crises fotossensíveis" }, "flashing-none": { compact: "Sem perigos de intermitência", descriptive: "A publicação não contém conteúdo intermitente que possa causar crises fotossensíveis" }, "flashing-unknown": { compact: "Risco de intermitência desconhecido", descriptive: "Não foi possível determinar se existe conteúdo intermitente que possa causar crises fotossensíveis" }, motion: { compact: "Simulação de movimento", descriptive: "A publicação contém simulações de movimento que podem causar enjoo" }, "motion-none": { compact: "Sem simulação de movimento", descriptive: "A publicação não contém simulações de movimento que possam causar enjoo" }, "motion-unknown": { compact: "Risco de movimento desconhecido", descriptive: "Não foi possível determinar se existem simulações de movimento que possam causar enjoo" }, "no-metadata": "Sem informação disponível", none: { compact: "Sem perigos", descriptive: "A publicação não contém perigos conhecidos" }, sound: { compact: "Sons sensíveis", descriptive: "A publicação contém sons que podem causar sensibilidade auditiva" }, "sound-none": { compact: "Sem perigos sonoros", descriptive: "A publicação não contém sons que possam causar sensibilidade auditiva" }, "sound-unknown": { compact: "Risco sonoro desconhecido", descriptive: "Não foi possível determinar se a publicação contém sons que possam causar sensibilidade auditiva" }, title: "Perigos", unknown: "Presença de perigos não determinada" }, "legal-considerations": { exempt: { compact: "Declara isenção de conformidade em algumas jurisdições", descriptive: "Esta publicação declara isenção de conformidade em algumas jurisdições" }, "no-metadata": "Sem informação disponível", title: "Considerações legais" }, navigation: { index: { compact: "Índice remissivo", descriptive: "Índice com ligações para entradas referenciadas" }, "no-metadata": "Sem informação disponível", "page-navigation": { compact: "Ir para página", descriptive: "Lista de páginas que permite aceder às páginas da versão impressa original" }, structural: { compact: "Títulos e estrutura", descriptive: "Elementos como títulos, tabelas, etc., para navegação estruturada" }, title: "Navegação", toc: { compact: "Índice", descriptive: "Índice de conteúdos com ligações para todos os capítulos do texto" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "Fórmulas químicas em LaTeX", descriptive: "Fórmulas químicas em formato acessível (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "Fórmulas químicas em MathML", descriptive: "Fórmulas químicas em formato acessível (MathML)" }, "accessible-math-as-latex": { compact: "Matemática em LaTeX", descriptive: "Fórmulas matemáticas em formato acessível (LaTeX)" }, "accessible-math-described": "Descrição textual das fórmulas matemáticas", "closed-captions": { compact: "Vídeos com legendas ocultas", descriptive: "Os vídeos incluídos na publicação têm legendas ocultas" }, "extended-descriptions": "Imagens complexas com descrições detalhadas", "math-as-mathml": { compact: "Matemática em MathML", descriptive: "Fórmulas matemáticas em formato acessível (MathML)" }, "open-captions": { compact: "Vídeos com legendas abertas", descriptive: "Os vídeos incluídos na publicação têm legendas abertas" }, title: "Conteúdo rico", transcript: "Transcrição fornecida", unknown: "Sem informação disponível" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "Contém texto alternativo", descriptive: "Inclui descrições alternativas de texto para imagens" }, "no-metadata": "Sem informação sobre leitura não visual", none: { compact: "Não legível em leitura em voz alta ou braille dinâmico", descriptive: "O conteúdo não é legível em voz alta ou através de braille dinâmico" }, "not-fully": { compact: "Parcialmente legível em leitura em voz alta ou braille dinâmico", descriptive: "Nem todo o conteúdo é legível em voz alta ou através de braille dinâmico" }, readable: { compact: "Totalmente legível em leitura em voz alta ou braille dinâmico", descriptive: "Todo o conteúdo pode ser lido em voz alta ou através de braille dinâmico" } }, "prerecorded-audio": { complementary: { compact: "Contém clipes de áudio pré-gravados", descriptive: "O conteúdo contém clipes de áudio pré-gravados incorporados" }, "no-metadata": "Sem informação sobre áudio pré-gravado", only: { compact: "Apenas áudio pré-gravado", descriptive: "A publicação é apenas áudio e não possui alternativa em texto" }, synchronized: { compact: "Áudio pré-gravado sincronizado com texto", descriptive: "Todo o conteúdo está disponível como áudio pré-gravado sincronizado com texto" } }, title: "Formas de leitura", "visual-adjustments": { modifiable: { compact: "Aspeto personalizável", descriptive: "O aspeto do texto e o layout da página podem ser modificados de acordo com as capacidades do sistema de leitura (tipo e tamanho de letra, espaçamento entre parágrafos, frases, palavras e letras, bem como a cor de fundo e do texto)" }, unknown: "Sem informação sobre personalização do aspeto", unmodifiable: { compact: "Aspeto não ajustável", descriptive: "O texto e o layout da página não podem ser modificados, uma vez que a experiência de leitura é semelhante à versão impressa, mas os sistemas de leitura ainda podem oferecer opções de ampliação" } } } } }, altIdentifier_one: "identificador alternativo", altIdentifier_other: "identificadores alternativos", artist_one: "artista", artist_other: "artistas", author_one: "autor", author_other: "autores", collection_one: "coleção", collection_other: "coleções", colorist_one: "colorista", colorist_other: "coloristas", contributor_one: "colaborador", contributor_other: "colaboradores", description: "descrição", duration: "duração", editor_one: "editor", editor_other: "editores", identifier_one: "identificador", identifier_other: "identificadores", illustrator_one: "ilustrador", illustrator_other: "ilustradores", imprint_one: "selo editorial", imprint_other: "selos editoriais", inker_one: "arte-finalista", inker_other: "arte-finalistas", language_one: "idioma", language_other: "idiomas", letterer_one: "letrista", letterer_other: "letristas", modified: "data de modificação", narrator_one: "narrador", narrator_other: "narradores", numberOfPages: "número de páginas", penciler_one: "desenhador", penciler_other: "desenhadores", published: "data de publicação", publisher_one: "editora", publisher_other: "editoras", series_one: "série", series_other: "séries", subject_one: "tema", subject_other: "temas", subtitle: "subtítulo", title: "título", translator_one: "tradutor", translator_other: "tradutores" } }, a = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/pt_PT-Di3sVjze.js?\n}')},"./node_modules/@readium/navigator-html-injectables/dist/sv-BfzAFsVN.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ t),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "Information saknas", "publisher-contact": "För mer information om den här publikationens tillgänglighet, kontakta utgivaren: ", title: "Kompletterande information om tillgänglighet" }, "additional-accessibility-information": { aria: { compact: "Innehåller ARIA-roller", descriptive: "Innehållet har försetts med ARIA-roller för att tydliggöra strukturen och underlätta navigering" }, "audio-descriptions": "Syntolkning", braille: "Punktskrift", "color-not-sole-means-of-conveying-information": "Betydelse uttrycks aldrig enbart med färg", "dyslexia-readability": "Förbättrad läsbarhet för personer med dyslexi", "full-ruby-annotations": "Fullständig ruby-annotering", "high-contrast-between-foreground-and-background-audio": "Hög kontrast mellan förgrundsljud och bakgrundsljud", "high-contrast-between-text-and-background": "Hög kontrast mellan text och bakgrund", "large-print": "Storstil", "page-breaks": { compact: "Innehåller sidnummer", descriptive: "Innehåller sidnummer från tryckt förlaga" }, "ruby-annotations": "Viss ruby-annotering", "sign-language": "Teckenspråk", "tactile-graphics": { compact: "Innehåller taktila bilder", descriptive: "Taktila bilder har lagts till för att tillgängliggöra visuella element för personer med synnedsättning" }, "tactile-objects": "Taktila 3D-objekt", "text-to-speech-hinting": "Innehåller uttalsinstruktioner för talsyntes", title: "Ytterligare tillgänglighetsinformation", "ultra-high-contrast-between-text-and-background": "Extra hög kontrast mellan text och bakgrund", "visible-page-numbering": "Synlig sidnumrering", "without-background-sounds": "Utan bakgrundsljud" }, conformance: { a: { compact: "Publikationen uppfyller tillgänglighetskrav på en grundläggande nivå", descriptive: "Publikationen anger att den uppfyller standarderna EPUB Accessibility och WCAG 2 nivå A" }, aa: { compact: "Publikationen uppfyller tillgänglighetskrav på en vedertagen nivå", descriptive: "Publikationen anger att den uppfyller standarderna EPUB Accessibility och WCAG 2 nivå AA" }, aaa: { compact: "Publikationen uppfyller tillgänglighetskrav utöver en vedertagen nivå", descriptive: "Publikationen anger att den uppfyller standarderna EPUB Accessibility och WCAG 2 nivå AAA" }, certifier: "Publikationen är certifierad av ", "certifier-credentials": "Certifierarens märkning är ", details: { "certification-info": "Publikationen certifierades ", "certifier-report": "Se certifieringsrapporten för mer information", claim: "Publikationen anger att den uppfyller kraven enligt", "epub-accessibility-1-0": "EPUB Accessibility 1.0", "epub-accessibility-1-1": "EPUB Accessibility 1.1", "level-a": "nivå A", "level-aa": "nivå AA", "level-aaa": "nivå AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "Web Content Accessibility Guidelines (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "Web Content Accessibility Guidelines (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "Web Content Accessibility Guidelines (WCAG) 2.2" } }, "details-title": "Detaljerad information om tillgänglighetskrav", no: "Information saknas", title: "Tillgänglighetskrav", "unknown-standard": "Det går inte att avgöra om publikationen uppfyller vedertagna tillgänglighetskrav" }, hazards: { flashing: { compact: "Blinkande innehåll", descriptive: "Publikationen har blinkande innehåll som kan vara skadligt för ljuskänsliga personer" }, "flashing-none": { compact: "Inget blinkande innehåll", descriptive: "Publikationen har inget blinkande innehåll" }, "flashing-unknown": { compact: "Förekomst av blinkande innehåll är okänd", descriptive: "Förekomst av blinkande innehåll är okänd" }, motion: { compact: "Rörelsesimulering", descriptive: "Publikationen innehåller rörelsesimulering som skulle kunna orsaka illamående" }, "motion-none": { compact: "Ingen rörelsesimulering", descriptive: "Publikationen innehåller ingen rörelsesimulering" }, "motion-unknown": { compact: "Förekomst av rörelsesimulering är okänd", descriptive: "Förekomst av rörelsesimulering är okänd" }, "no-metadata": "Information saknas", none: { compact: "Inga risker", descriptive: "Publikationen innehåller inga risker" }, sound: { compact: "Ljud", descriptive: "Publikationen innehåller ljud som kan orsaka obehag" }, "sound-none": { compact: "Inget ljud som kan orsaka obehag", descriptive: "Publikationen innehåller inget ljud som kan orsaka obehag" }, "sound-unknown": { compact: "Förekomst av ljud som kan orsaka obehag är okänd", descriptive: "Förekomst av ljud som kan orsaka obehag är okänd" }, title: "Risker", unknown: "Förekomst av risker är okänd" }, "legal-considerations": { exempt: { compact: "Åberopar ett undantag från vissa lagstadgade tillgänglighetskrav", descriptive: "Publikationen åberopar ett undantag från vissa lagstadgade tillgänglighetskrav" }, "no-metadata": "Information saknas", title: "Juridiska aspekter" }, navigation: { index: { compact: "Register", descriptive: "Register med länkar till innehållet" }, "no-metadata": "Information saknas", "page-navigation": { compact: "Gå till sida", descriptive: "Sidindelning för navigering enligt sidnummer i tryckt förlaga" }, structural: { compact: "Rubriker", descriptive: "Navigerbara element såsom rubriker eller tabeller" }, title: "Navigering", toc: { compact: "Innehållsförteckning", descriptive: "Innehållsförteckning med länkar till alla kapitel" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "Kemiska formler i LaTeX", descriptive: "Kemiska formler i tillgängligt format (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "Kemiska formler i MathML", descriptive: "Kemiska formler i tillgängligt format (MathML)" }, "accessible-math-as-latex": { compact: "Matematik som LaTeX", descriptive: "Matematiska formler i tillgängligt format (LaTeX)" }, "accessible-math-described": "Innehåller textbeskrivningar av matematik", "closed-captions": { compact: "Videoklipp har undertext som kan sättas på/stängas av", descriptive: "Videoklipp som ingår i publikationen har undertext som kan sättas på och stängas av (stängda undertexter)" }, "extended-descriptions": "Informationsrika bilder har utökade bildbeskrivningar", "math-as-mathml": { compact: "Matematik som MathML", descriptive: "Matematiska formler i tillgängligt format (MathML)" }, "open-captions": { compact: "Videoklipp har undertext som inte kan stängas av", descriptive: "Videoklipp som ingår i publikationen har undertext som inte kan stängas av (öppna undertexter)" }, title: "Berikat innehåll", transcript: "Innehåller transkriptioner", unknown: "Information saknas" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "Har textalternativ (alt-texter)", descriptive: "Har textalternativ (alt-texter) till bilder" }, "no-metadata": "Information om icke-visuell läsbarhet saknas", none: { compact: "Kan inte läsas med uppläsningsfunktion eller punktskriftsskärm", descriptive: "Innehållet går inte att läsa med uppläsningsfunktion eller punktskriftsskärm" }, "not-fully": { compact: "Inte läsbart i sin helhet med uppläsningsfunktion eller punktskriftsskärm", descriptive: "Allt innehåll går inte att läsa med uppläsningsfunktion eller punktskriftsskärm" }, readable: { compact: "Kan läsas med uppläsningsfunktion eller punktskriftsskärm", descriptive: "Hela innehållet går att läsa med uppläsningsfunktion eller punktskriftsskärm" } }, "prerecorded-audio": { complementary: { compact: "Förinspelade ljudklipp", descriptive: "Innehåller förinspelade ljudklipp" }, "no-metadata": "Information om förinspelat ljud saknas", only: { compact: "Endast förinspelat ljud", descriptive: "Bok med ljud utan textalternativ" }, synchronized: { compact: "Förinspelat ljud synkroniserat med texten", descriptive: "Hela innehållet finns tillgängligt som förinspelat ljud synkroniserat med texten" } }, title: "Olika sätt att läsa", "visual-adjustments": { modifiable: { compact: "Utseendet kan justeras", descriptive: "Det går att justera text och layout i den utsträckning som läsprogrammet tillåter, till exempel typsnitt, storlek på text, avstånd mellan rader och stycken samt färg på text och bakgrund" }, unknown: "Information om möjlighet att justera utseende saknas", unmodifiable: { compact: "Utseendet kan inte justeras", descriptive: "Text- och sidlayout kan inte justeras eftersom presentationen liknar en tryckt version, men läsprogram kan ha funktioner för att zooma in" } } } } }, altIdentifier_one: "alternativ identifierare", altIdentifier_other: "alternativa identifierare", artist_one: "konstnär", artist_other: "konstnärer", author_one: "författare", author_other: "författare", collection_one: "samling", collection_other: "samlingar", colorist_one: "kolorist", colorist_other: "kolorister", contributor_one: "medverkande", contributor_other: "medverkande", description: "beskrivning", duration: "speltid", editor_one: "redaktör", editor_other: "redaktörer", identifier_one: "identifierare", identifier_other: "identifierare", illustrator_one: "illustratör", illustrator_other: "illustratörer", imprint_one: "imprint", imprint_other: "imprint", inker_one: "tuschare", inker_other: "tuschare", language_one: "språk", language_other: "språk", letterer_one: "textare", letterer_other: "textare", modified: "ändringsdatum", narrator_one: "berättarröst", narrator_other: "berättarröster", numberOfPages: "sidantal", penciler_one: "tecknare", penciler_other: "tecknare", published: "publikationsdatum", publisher_one: "förlag", publisher_other: "förlag", series_one: "serie", series_other: "serier", subject_one: "ämne", subject_other: "ämnen", subtitle: "undertitel", title: "titel", translator_one: "översättare", translator_other: "översättare" } }, t = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator-html-injectables/dist/sv-BfzAFsVN.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-after-ClF4TBzj.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__viewportWidth:100%;\n\n --RS__pageGutter:0;\n\n --RS__defaultLineLength:100%;\n\n --RS__colGap:0;\n\n --RS__colCount:1;\n\n --RS__colWidth:100vw;\n}\n\n@page{\n margin:0 !important;\n}\n\n:root{\n position:relative;\n\n -webkit-column-width:var(--RS__colWidth);\n -moz-column-width:var(--RS__colWidth);\n column-width:var(--RS__colWidth);\n -webkit-column-count:var(--RS__colCount);\n -moz-column-count:var(--RS__colCount);\n column-count:var(--RS__colCount);\n\n -webkit-column-gap:var(--RS__colGap);\n -moz-column-gap:var(--RS__colGap);\n column-gap:var(--RS__colGap);\n -moz-column-fill:auto;\n column-fill:auto;\n width:100%;\n height:100vh;\n max-width:100%;\n max-height:100vh;\n min-width:100%;\n min-height:100vh;\n padding:0 !important;\n margin:0 !important;\n font-size:1rem !important;\n box-sizing:border-box;\n\n hanging-punctuation:last allow-end;\n -webkit-touch-callout:none;\n -ms-writing-mode:tb-rl;\n -webkit-writing-mode:vertical-rl;\n writing-mode:vertical-rl;\n}\n\n:root:lang(mn-Mong){\n -ms-writing-mode:tb;\n -webkit-writing-mode:vertical-lr;\n writing-mode:vertical-lr;\n}\n\nbody{\n width:100%;\n max-height:var(--RS__defaultLineLength) !important;\n margin:auto 0 !important;\n box-sizing:border-box;\n}\n\n:root:not([style*="readium-scroll-on"]) body{\n padding:var(--RS__pageGutter) 0 !important;\n}\n\n:root:not([style*="readium-noOverflow-on"]) body{\n overflow:hidden;\n}\n\n@supports (overflow: clip){\n\n :root:not([style*="readium-noOverflow-on"]){\n overflow:clip;\n }\n\n :root:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n overflow-clip-margin:content-box;\n }\n}\n\n:root[style*="readium-scroll-on"],\n:root[style*="readium-noVerticalPagination-on"]{\n -webkit-columns:auto auto !important;\n -moz-columns:auto auto !important;\n columns:auto auto !important;\n width:auto !important;\n max-width:none !important;\n max-height:100vh !important;\n min-width:0 !important;\n}\n\n:root[style*="readium-scroll-on"] body,\n:root[style*="readium-noVerticalPagination-on"] body{\n max-width:var(--RS__defaultLineLength) !important;\n box-sizing:border-box !important;\n}\n\n@supports (overflow: clip){\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]){\n overflow:auto;\n }\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n }\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingTop"] body{\n padding-top:var(--RS__scrollPaddingTop) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingBottom"] body{\n padding-bottom:var(--RS__scrollPaddingBottom) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingLeft"] body{\n padding-left:var(--RS__scrollPaddingLeft) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingRight"] body{\n padding-right:var(--RS__scrollPaddingRight) !important;\n}\n\n:root[style*="--USER__backgroundColor"]{\n background-color:var(--USER__backgroundColor) !important;\n}\n\n:root[style*="--USER__backgroundColor"] *{\n background-color:transparent !important;\n}\n\n:root[style*="--USER__textColor"]{\n color:var(--USER__textColor) !important;\n}\n\n:root[style*="--USER__textColor"] *:not(a){\n color:inherit !important;\n background-color:transparent !important;\n border-color:currentcolor !important;\n}\n\n:root[style*="--USER__textColor"] svg text{\n fill:currentcolor !important;\n stroke:none !important;\n}\n\n:root[style*="--USER__linkColor"] a:link,\n:root[style*="--USER__linkColor"] a:link *{\n color:var(--USER__linkColor) !important;\n}\n\n:root[style*="--USER__visitedColor"] a:visited,\n:root[style*="--USER__visitedColor"] a:visited *{\n color:var(--USER__visitedColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__lineLength"] body{\n max-height:var(--USER__lineLength) !important;\n }\n\n:root[style*="--USER__fontFamily"]{\n font-family:var(--USER__fontFamily) !important;\n}\n\n:root[style*="--USER__fontFamily"] *{\n font-family:revert !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] body{\n zoom:var(--USER__fontSize) !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"])[style*="readium-iOSPatch-on"][style*="--USER__fontSize"] body{\n -webkit-text-size-adjust:var(--USER__fontSize) !important;\n}\n\n@supports selector(figure:has(> img)){\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> img),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> video),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> svg),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> canvas),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> iframe),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> audio),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> img:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> video:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> svg:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> canvas:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> iframe:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> audio:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] table{\n zoom:calc(100% / var(--USER__fontSize)) !important;\n }\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figcaption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] caption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] td,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] th{\n zoom:var(--USER__fontSize) !important;\n }\n}\n\n@supports not (zoom: 1){\n\n :root[style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n }\n}\n\n:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n}\n\n:root[style*="--USER__lineHeight"]{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__lineHeight"] body,\n:root[style*="--USER__lineHeight"] p,\n:root[style*="--USER__lineHeight"] li,\n:root[style*="--USER__lineHeight"] div{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__paraSpacing"] p{\n margin-right:var(--USER__paraSpacing) !important;\n margin-left:var(--USER__paraSpacing) !important;\n}\n\n:root[style*="--USER__fontWeight"] body{\n font-weight:var(--USER__fontWeight) !important;\n}\n\n:root[style*="--USER__fontWeight"] b,\n:root[style*="--USER__fontWeight"] strong{\n font-weight:bolder;\n}\n\n:root[style*="--USER__fontWidth"] body{\n font-stretch:var(--USER__fontWidth) !important;\n}\n\n:root[style*="--USER__fontOpticalSizing"] body{\n font-optical-sizing:var(--USER__fontOpticalSizing) !important;\n}\n\n:root[style*="--USER__letterSpacing"] h1,\n:root[style*="--USER__letterSpacing"] h2,\n:root[style*="--USER__letterSpacing"] h3,\n:root[style*="--USER__letterSpacing"] h4,\n:root[style*="--USER__letterSpacing"] h5,\n:root[style*="--USER__letterSpacing"] h6,\n:root[style*="--USER__letterSpacing"] p,\n:root[style*="--USER__letterSpacing"] li,\n:root[style*="--USER__letterSpacing"] div,\n:root[style*="--USER__letterSpacing"] dt,\n:root[style*="--USER__letterSpacing"] dd{\n letter-spacing:var(--USER__letterSpacing) !important;\n font-variant:none !important;\n}\n\n:root[style*="readium-noRuby-on"] body rt,\n:root[style*="readium-noRuby-on"] body rp{\n display:none;\n}\n\n:root[style*="readium-blend-on"] svg,\n:root[style*="readium-blend-on"] img{\n background-color:transparent !important;\n mix-blend-mode:multiply !important;\n}\n\n:root[style*="--USER__darkenImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) !important;\n filter:brightness(var(--USER__darkenImages)) !important;\n}\n\n:root[style*="readium-darken-on"] img{\n -webkit-filter:brightness(80%) !important;\n filter:brightness(80%) !important;\n}\n\n:root[style*="--USER__invertImages"] img{\n -webkit-filter:invert(var(--USER__invertImages)) !important;\n filter:invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-invert-on"] img{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n}\n\n:root[style*="readium-darken-on"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(80%) invert(100%) !important;\n filter:brightness(80%) invert(100%) !important;\n}\n\n:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{\n -webkit-filter:invert(var(--USER__invertGaiji)) !important;\n filter:invert(var(--USER__invertGaiji)) !important;\n}\n\n:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="readium-normalize-on"]{\n --USER__typeScale:1.2;\n}\n\n:root[style*="readium-normalize-on"] p,\n:root[style*="readium-normalize-on"] li,\n:root[style*="readium-normalize-on"] div,\n:root[style*="readium-normalize-on"] pre,\n:root[style*="readium-normalize-on"] dd{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] h1{\n font-size:1.75rem !important;\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h2{\n font-size:1.5rem !important;\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h3{\n font-size:1.25rem !important;\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h4,\n:root[style*="readium-normalize-on"] h5,\n:root[style*="readium-normalize-on"] h6{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] small{\n font-size:smaller !important;\n}\n\n:root[style*="readium-normalize-on"] sub,\n:root[style*="readium-normalize-on"] sup{\n font-size:67.5% !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-iPadOSPatch-on"] body{\n -webkit-text-size-adjust:none;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p, \n:root[style*="readium-iPadOSPatch-on"] h1, \n:root[style*="readium-iPadOSPatch-on"] h2, \n:root[style*="readium-iPadOSPatch-on"] h3, \n:root[style*="readium-iPadOSPatch-on"] h4, \n:root[style*="readium-iPadOSPatch-on"] h5, \n:root[style*="readium-iPadOSPatch-on"] h6, \n:root[style*="readium-iPadOSPatch-on"] li, \n:root[style*="readium-iPadOSPatch-on"] th, \n:root[style*="readium-iPadOSPatch-on"] td, \n:root[style*="readium-iPadOSPatch-on"] dt, \n:root[style*="readium-iPadOSPatch-on"] dd, \n:root[style*="readium-iPadOSPatch-on"] pre, \n:root[style*="readium-iPadOSPatch-on"] address, \n:root[style*="readium-iPadOSPatch-on"] details, \n:root[style*="readium-iPadOSPatch-on"] summary,\n:root[style*="readium-iPadOSPatch-on"] figcaption,\n:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)),\n:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){\n -webkit-text-zoom:reset;\n}\n\n:root[style*="readium-iPadOSPatch-on"] abbr, \n:root[style*="readium-iPadOSPatch-on"] b, \n:root[style*="readium-iPadOSPatch-on"] bdi, \n:root[style*="readium-iPadOSPatch-on"] bdo, \n:root[style*="readium-iPadOSPatch-on"] cite, \n:root[style*="readium-iPadOSPatch-on"] code, \n:root[style*="readium-iPadOSPatch-on"] dfn, \n:root[style*="readium-iPadOSPatch-on"] em, \n:root[style*="readium-iPadOSPatch-on"] i, \n:root[style*="readium-iPadOSPatch-on"] kbd, \n:root[style*="readium-iPadOSPatch-on"] mark, \n:root[style*="readium-iPadOSPatch-on"] q, \n:root[style*="readium-iPadOSPatch-on"] rp, \n:root[style*="readium-iPadOSPatch-on"] rt, \n:root[style*="readium-iPadOSPatch-on"] ruby, \n:root[style*="readium-iPadOSPatch-on"] s, \n:root[style*="readium-iPadOSPatch-on"] samp, \n:root[style*="readium-iPadOSPatch-on"] small, \n:root[style*="readium-iPadOSPatch-on"] span, \n:root[style*="readium-iPadOSPatch-on"] strong, \n:root[style*="readium-iPadOSPatch-on"] sub, \n:root[style*="readium-iPadOSPatch-on"] sup, \n:root[style*="readium-iPadOSPatch-on"] time, \n:root[style*="readium-iPadOSPatch-on"] u, \n:root[style*="readium-iPadOSPatch-on"] var{\n -webkit-text-zoom:normal;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{\n -webkit-text-zoom:normal;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-after-ClF4TBzj.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-after-D7unrNI9.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__viewportWidth:100%;\n\n --RS__pageGutter:0;\n\n --RS__defaultLineLength:100%;\n\n --RS__colGap:0;\n\n --RS__colCount:1;\n\n --RS__colWidth:100vw;\n}\n\n@page{\n margin:0 !important;\n}\n\n:root{\n position:relative;\n\n -webkit-column-width:var(--RS__colWidth);\n -moz-column-width:var(--RS__colWidth);\n column-width:var(--RS__colWidth);\n -webkit-column-count:var(--RS__colCount);\n -moz-column-count:var(--RS__colCount);\n column-count:var(--RS__colCount);\n\n -webkit-column-gap:var(--RS__colGap);\n -moz-column-gap:var(--RS__colGap);\n column-gap:var(--RS__colGap);\n -moz-column-fill:auto;\n column-fill:auto;\n width:var(--RS__viewportWidth);\n height:100vh;\n max-width:var(--RS__viewportWidth);\n max-height:100vh;\n min-width:var(--RS__viewportWidth);\n min-height:100vh;\n padding:0 !important;\n margin:0 !important;\n font-size:1rem !important;\n box-sizing:border-box;\n -webkit-touch-callout:none;\n}\n\nbody{\n width:100%;\n max-width:var(--RS__defaultLineLength) !important;\n margin:0 auto !important;\n box-sizing:border-box;\n}\n\n:root:not([style*="readium-scroll-on"]) body{\n padding:0 var(--RS__pageGutter) !important;\n}\n\n:root:not([style*="readium-noOverflow-on"]) body{\n overflow:hidden;\n}\n\n@supports (overflow: clip){\n\n :root:not([style*="readium-noOverflow-on"]){\n overflow:clip;\n }\n\n :root:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n overflow-clip-margin:content-box;\n }\n}\n\n:root[style*="readium-scroll-on"]{\n -webkit-columns:auto auto !important;\n -moz-columns:auto auto !important;\n columns:auto auto !important;\n width:auto !important;\n height:auto !important;\n max-width:none !important;\n max-height:none !important;\n min-width:0 !important;\n min-height:0 !important;\n}\n\n:root[style*="readium-scroll-on"] body{\n max-width:var(--RS__defaultLineLength) !important;\n box-sizing:border-box !important;\n}\n\n:root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:auto;\n}\n\n@supports (overflow: clip){\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]){\n overflow:auto;\n }\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n }\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingTop"] body{\n padding-top:var(--RS__scrollPaddingTop) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingBottom"] body{\n padding-bottom:var(--RS__scrollPaddingBottom) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingLeft"] body{\n padding-left:var(--RS__scrollPaddingLeft) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingRight"] body{\n padding-right:var(--RS__scrollPaddingRight) !important;\n}\n\n:root[style*="--USER__backgroundColor"]{\n background-color:var(--USER__backgroundColor) !important;\n}\n\n:root[style*="--USER__backgroundColor"] *{\n background-color:transparent !important;\n}\n\n:root[style*="--USER__textColor"]{\n color:var(--USER__textColor) !important;\n}\n\n:root[style*="--USER__textColor"] *:not(a){\n color:inherit !important;\n background-color:transparent !important;\n border-color:currentcolor !important;\n}\n\n:root[style*="--USER__textColor"] svg text{\n fill:currentcolor !important;\n stroke:none !important;\n}\n\n:root[style*="--USER__linkColor"] a:link,\n:root[style*="--USER__linkColor"] a:link *{\n color:var(--USER__linkColor) !important;\n}\n\n:root[style*="--USER__visitedColor"] a:visited,\n:root[style*="--USER__visitedColor"] a:visited *{\n color:var(--USER__visitedColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__colCount"]{\n -webkit-column-count:var(--USER__colCount);\n -moz-column-count:var(--USER__colCount);\n column-count:var(--USER__colCount);\n\n --RS__colWidth:auto;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"]{\n -webkit-column-count:1;\n -moz-column-count:1;\n column-count:1;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"],\n:root[style*="--USER__colCount: 1"],\n:root[style*="--USER__colCount:1"]{\n --RS__colWidth:100vw;\n}\n\n:root[style*="--USER__lineLength"] body{\n max-width:var(--USER__lineLength) !important;\n }\n\n:root[style*="--USER__textAlign"]{\n text-align:var(--USER__textAlign);\n}\n\n:root[style*="--USER__textAlign"] body,\n:root[style*="--USER__textAlign"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n),\n:root[style*="--USER__textAlign"] li,\n:root[style*="--USER__textAlign"] dd{\n text-align:var(--USER__textAlign) !important;\n -moz-text-align-last:auto !important;\n -epub-text-align-last:auto !important;\n text-align-last:auto !important;\n}\n\n:root[style*="--USER__bodyHyphens"]{\n -webkit-hyphens:var(--USER__bodyHyphens) !important;\n -moz-hyphens:var(--USER__bodyHyphens) !important;\n -ms-hyphens:var(--USER__bodyHyphens) !important;\n -epub-hyphens:var(--USER__bodyHyphens) !important;\n hyphens:var(--USER__bodyHyphens) !important;\n}\n\n:root[style*="--USER__bodyHyphens"] body,\n:root[style*="--USER__bodyHyphens"] p,\n:root[style*="--USER__bodyHyphens"] li,\n:root[style*="--USER__bodyHyphens"] div,\n:root[style*="--USER__bodyHyphens"] dd{\n -webkit-hyphens:var(--USER__bodyHyphens) !important;\n -moz-hyphens:var(--USER__bodyHyphens) !important;\n -ms-hyphens:var(--USER__bodyHyphens) !important;\n -epub-hyphens:var(--USER__bodyHyphens) !important;\n hyphens:var(--USER__bodyHyphens) !important;\n}\n\n:root[style*="--USER__fontFamily"]{\n font-family:var(--USER__fontFamily) !important;\n}\n\n:root[style*="--USER__fontFamily"] *{\n font-family:revert !important;\n}\n\n:root[style*="readium-a11y-on"]{\n font-style:normal !important;\n font-weight:normal !important;\n}\n\n:root[style*="readium-a11y-on"] body *:not(code):not(var):not(kbd):not(samp){\n font-family:inherit !important;\n font-style:inherit !important;\n font-weight:inherit !important;\n}\n\n:root[style*="readium-a11y-on"] body *:not(a){\n text-decoration:none !important;\n}\n\n:root[style*="readium-a11y-on"] body *{\n font-variant-caps:normal !important;\n font-variant-numeric:normal !important;\n font-variant-position:normal !important;\n}\n\n:root[style*="readium-a11y-on"] sup,\n:root[style*="readium-a11y-on"] sub{\n font-size:1rem !important;\n vertical-align:baseline !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] body{\n zoom:var(--USER__fontSize) !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"])[style*="readium-iOSPatch-on"][style*="--USER__fontSize"] body{\n -webkit-text-size-adjust:var(--USER__fontSize) !important;\n}\n\n@supports selector(figure:has(> img)){\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> img),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> video),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> svg),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> canvas),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> iframe),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> audio),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> img:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> video:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> svg:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> canvas:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> iframe:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> audio:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] table{\n zoom:calc(100% / var(--USER__fontSize)) !important;\n }\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figcaption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] caption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] td,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] th{\n zoom:var(--USER__fontSize) !important;\n }\n}\n\n@supports not (zoom: 1){\n\n :root[style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n }\n}\n\n:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n}\n\n:root[style*="--USER__lineHeight"]{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__lineHeight"] body,\n:root[style*="--USER__lineHeight"] p,\n:root[style*="--USER__lineHeight"] li,\n:root[style*="--USER__lineHeight"] div{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__paraSpacing"] p{\n margin-top:var(--USER__paraSpacing) !important;\n margin-bottom:var(--USER__paraSpacing) !important;\n}\n\n:root[style*="--USER__paraIndent"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n){\n text-indent:var(--USER__paraIndent) !important;\n}\n\n:root[style*="--USER__paraIndent"] p *{\n text-indent:0 !important;\n}\n\n:root[style*="--USER__wordSpacing"] h1,\n:root[style*="--USER__wordSpacing"] h2,\n:root[style*="--USER__wordSpacing"] h3,\n:root[style*="--USER__wordSpacing"] h4,\n:root[style*="--USER__wordSpacing"] h5,\n:root[style*="--USER__wordSpacing"] h6,\n:root[style*="--USER__wordSpacing"] p,\n:root[style*="--USER__wordSpacing"] li,\n:root[style*="--USER__wordSpacing"] div,\n:root[style*="--USER__wordSpacing"] dt,\n:root[style*="--USER__wordSpacing"] dd{\n word-spacing:var(--USER__wordSpacing) !important;\n}\n\n:root[style*="--USER__letterSpacing"] h1,\n:root[style*="--USER__letterSpacing"] h2,\n:root[style*="--USER__letterSpacing"] h3,\n:root[style*="--USER__letterSpacing"] h4,\n:root[style*="--USER__letterSpacing"] h5,\n:root[style*="--USER__letterSpacing"] h6,\n:root[style*="--USER__letterSpacing"] p,\n:root[style*="--USER__letterSpacing"] li,\n:root[style*="--USER__letterSpacing"] div,\n:root[style*="--USER__letterSpacing"] dt,\n:root[style*="--USER__letterSpacing"] dd{\n letter-spacing:var(--USER__letterSpacing) !important;\n font-variant:none !important;\n}\n\n:root[style*="--USER__ligatures"]{\n font-variant-ligatures:var(--USER__ligatures) !important;\n}\n\n:root[style*="--USER__ligatures"] *{\n font-variant-ligatures:inherit !important;\n}\n\n:root[style*="--USER__fontWeight"] body{\n font-weight:var(--USER__fontWeight) !important;\n}\n\n:root[style*="--USER__fontWeight"] b,\n:root[style*="--USER__fontWeight"] strong{\n font-weight:bolder;\n}\n\n:root[style*="--USER__fontWidth"] body{\n font-stretch:var(--USER__fontWidth) !important;\n}\n\n:root[style*="--USER__fontOpticalSizing"] body{\n font-optical-sizing:var(--USER__fontOpticalSizing) !important;\n}\n\n:root[style*="readium-blend-on"] svg,\n:root[style*="readium-blend-on"] img{\n background-color:transparent !important;\n mix-blend-mode:multiply !important;\n}\n\n:root[style*="--USER__darkenImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) !important;\n filter:brightness(var(--USER__darkenImages)) !important;\n}\n\n:root[style*="readium-darken-on"] img{\n -webkit-filter:brightness(80%) !important;\n filter:brightness(80%) !important;\n}\n\n:root[style*="--USER__invertImages"] img{\n -webkit-filter:invert(var(--USER__invertImages)) !important;\n filter:invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-invert-on"] img{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n}\n\n:root[style*="readium-darken-on"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(80%) invert(100%) !important;\n filter:brightness(80%) invert(100%) !important;\n}\n\n:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{\n -webkit-filter:invert(var(--USER__invertGaiji)) !important;\n filter:invert(var(--USER__invertGaiji)) !important;\n}\n\n:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="readium-normalize-on"]{\n --USER__typeScale:1.2;\n}\n\n:root[style*="readium-normalize-on"] p,\n:root[style*="readium-normalize-on"] li,\n:root[style*="readium-normalize-on"] div,\n:root[style*="readium-normalize-on"] pre,\n:root[style*="readium-normalize-on"] dd{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] h1{\n font-size:1.75rem !important;\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h2{\n font-size:1.5rem !important;\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h3{\n font-size:1.25rem !important;\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h4,\n:root[style*="readium-normalize-on"] h5,\n:root[style*="readium-normalize-on"] h6{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] small{\n font-size:smaller !important;\n}\n\n:root[style*="readium-normalize-on"] sub,\n:root[style*="readium-normalize-on"] sup{\n font-size:67.5% !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-iPadOSPatch-on"] body{\n -webkit-text-size-adjust:none;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p, \n:root[style*="readium-iPadOSPatch-on"] h1, \n:root[style*="readium-iPadOSPatch-on"] h2, \n:root[style*="readium-iPadOSPatch-on"] h3, \n:root[style*="readium-iPadOSPatch-on"] h4, \n:root[style*="readium-iPadOSPatch-on"] h5, \n:root[style*="readium-iPadOSPatch-on"] h6, \n:root[style*="readium-iPadOSPatch-on"] li, \n:root[style*="readium-iPadOSPatch-on"] th, \n:root[style*="readium-iPadOSPatch-on"] td, \n:root[style*="readium-iPadOSPatch-on"] dt, \n:root[style*="readium-iPadOSPatch-on"] dd, \n:root[style*="readium-iPadOSPatch-on"] pre, \n:root[style*="readium-iPadOSPatch-on"] address, \n:root[style*="readium-iPadOSPatch-on"] details, \n:root[style*="readium-iPadOSPatch-on"] summary,\n:root[style*="readium-iPadOSPatch-on"] figcaption,\n:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)),\n:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){\n -webkit-text-zoom:reset;\n}\n\n:root[style*="readium-iPadOSPatch-on"] abbr, \n:root[style*="readium-iPadOSPatch-on"] b, \n:root[style*="readium-iPadOSPatch-on"] bdi, \n:root[style*="readium-iPadOSPatch-on"] bdo, \n:root[style*="readium-iPadOSPatch-on"] cite, \n:root[style*="readium-iPadOSPatch-on"] code, \n:root[style*="readium-iPadOSPatch-on"] dfn, \n:root[style*="readium-iPadOSPatch-on"] em, \n:root[style*="readium-iPadOSPatch-on"] i, \n:root[style*="readium-iPadOSPatch-on"] kbd, \n:root[style*="readium-iPadOSPatch-on"] mark, \n:root[style*="readium-iPadOSPatch-on"] q, \n:root[style*="readium-iPadOSPatch-on"] rp, \n:root[style*="readium-iPadOSPatch-on"] rt, \n:root[style*="readium-iPadOSPatch-on"] ruby, \n:root[style*="readium-iPadOSPatch-on"] s, \n:root[style*="readium-iPadOSPatch-on"] samp, \n:root[style*="readium-iPadOSPatch-on"] small, \n:root[style*="readium-iPadOSPatch-on"] span, \n:root[style*="readium-iPadOSPatch-on"] strong, \n:root[style*="readium-iPadOSPatch-on"] sub, \n:root[style*="readium-iPadOSPatch-on"] sup, \n:root[style*="readium-iPadOSPatch-on"] time, \n:root[style*="readium-iPadOSPatch-on"] u, \n:root[style*="readium-iPadOSPatch-on"] var{\n -webkit-text-zoom:normal;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{\n -webkit-text-zoom:normal;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-after-D7unrNI9.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-after-XUKPAxfT.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ t)\n/* harmony export */ });\nconst t = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__viewportWidth:100%;\n\n --RS__pageGutter:0;\n\n --RS__defaultLineLength:100%;\n\n --RS__colGap:0;\n\n --RS__colCount:1;\n\n --RS__colWidth:100vw;\n}\n\n@page{\n margin:0 !important;\n}\n\n:root{\n position:relative;\n\n -webkit-column-width:var(--RS__colWidth);\n -moz-column-width:var(--RS__colWidth);\n column-width:var(--RS__colWidth);\n -webkit-column-count:var(--RS__colCount);\n -moz-column-count:var(--RS__colCount);\n column-count:var(--RS__colCount);\n\n -webkit-column-gap:var(--RS__colGap);\n -moz-column-gap:var(--RS__colGap);\n column-gap:var(--RS__colGap);\n -moz-column-fill:auto;\n column-fill:auto;\n width:var(--RS__viewportWidth);\n height:100vh;\n max-width:var(--RS__viewportWidth);\n max-height:100vh;\n min-width:var(--RS__viewportWidth);\n min-height:100vh;\n padding:0 !important;\n margin:0 !important;\n font-size:1rem !important;\n box-sizing:border-box;\n -webkit-touch-callout:none;\n}\n\nbody{\n width:100%;\n max-width:var(--RS__defaultLineLength) !important;\n margin:0 auto !important;\n box-sizing:border-box;\n}\n\n:root:not([style*="readium-scroll-on"]) body{\n padding:0 var(--RS__pageGutter) !important;\n}\n\n:root:not([style*="readium-noOverflow-on"]) body{\n overflow:hidden;\n}\n\n@supports (overflow: clip){\n\n :root:not([style*="readium-noOverflow-on"]){\n overflow:clip;\n }\n\n :root:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n overflow-clip-margin:content-box;\n }\n}\n\n:root[style*="readium-scroll-on"]{\n -webkit-columns:auto auto !important;\n -moz-columns:auto auto !important;\n columns:auto auto !important;\n width:auto !important;\n height:auto !important;\n max-width:none !important;\n max-height:none !important;\n min-width:0 !important;\n min-height:0 !important;\n}\n\n:root[style*="readium-scroll-on"] body{\n max-width:var(--RS__defaultLineLength) !important;\n box-sizing:border-box !important;\n}\n\n:root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:auto;\n}\n\n@supports (overflow: clip){\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]){\n overflow:auto;\n }\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n }\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingTop"] body{\n padding-top:var(--RS__scrollPaddingTop) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingBottom"] body{\n padding-bottom:var(--RS__scrollPaddingBottom) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingLeft"] body{\n padding-left:var(--RS__scrollPaddingLeft) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingRight"] body{\n padding-right:var(--RS__scrollPaddingRight) !important;\n}\n\n:root[style*="--USER__backgroundColor"]{\n background-color:var(--USER__backgroundColor) !important;\n}\n\n:root[style*="--USER__backgroundColor"] *{\n background-color:transparent !important;\n}\n\n:root[style*="--USER__textColor"]{\n color:var(--USER__textColor) !important;\n}\n\n:root[style*="--USER__textColor"] *:not(a){\n color:inherit !important;\n background-color:transparent !important;\n border-color:currentcolor !important;\n}\n\n:root[style*="--USER__textColor"] svg text{\n fill:currentcolor !important;\n stroke:none !important;\n}\n\n:root[style*="--USER__linkColor"] a:link,\n:root[style*="--USER__linkColor"] a:link *{\n color:var(--USER__linkColor) !important;\n}\n\n:root[style*="--USER__visitedColor"] a:visited,\n:root[style*="--USER__visitedColor"] a:visited *{\n color:var(--USER__visitedColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__colCount"]{\n -webkit-column-count:var(--USER__colCount);\n -moz-column-count:var(--USER__colCount);\n column-count:var(--USER__colCount);\n\n --RS__colWidth:auto;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"]{\n -webkit-column-count:1;\n -moz-column-count:1;\n column-count:1;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"],\n:root[style*="--USER__colCount: 1"],\n:root[style*="--USER__colCount:1"]{\n --RS__colWidth:100vw;\n}\n\n:root[style*="--USER__lineLength"] body{\n max-width:var(--USER__lineLength) !important;\n }\n\n:root[style*="--USER__fontFamily"]{\n font-family:var(--USER__fontFamily) !important;\n}\n\n:root[style*="--USER__fontFamily"] *{\n font-family:revert !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] body{\n zoom:var(--USER__fontSize) !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"])[style*="readium-iOSPatch-on"][style*="--USER__fontSize"] body{\n -webkit-text-size-adjust:var(--USER__fontSize) !important;\n}\n\n@supports selector(figure:has(> img)){\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> img),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> video),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> svg),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> canvas),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> iframe),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> audio),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> img:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> video:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> svg:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> canvas:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> iframe:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> audio:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] table{\n zoom:calc(100% / var(--USER__fontSize)) !important;\n }\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figcaption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] caption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] td,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] th{\n zoom:var(--USER__fontSize) !important;\n }\n}\n\n@supports not (zoom: 1){\n\n :root[style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n }\n}\n\n:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n}\n\n:root[style*="--USER__lineHeight"]{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__lineHeight"] body,\n:root[style*="--USER__lineHeight"] p,\n:root[style*="--USER__lineHeight"] li,\n:root[style*="--USER__lineHeight"] div{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__paraSpacing"] p{\n margin-top:var(--USER__paraSpacing) !important;\n margin-bottom:var(--USER__paraSpacing) !important;\n}\n\n:root[style*="--USER__fontWeight"] body{\n font-weight:var(--USER__fontWeight) !important;\n}\n\n:root[style*="--USER__fontWeight"] b,\n:root[style*="--USER__fontWeight"] strong{\n font-weight:bolder;\n}\n\n:root[style*="--USER__fontWidth"] body{\n font-stretch:var(--USER__fontWidth) !important;\n}\n\n:root[style*="--USER__fontOpticalSizing"] body{\n font-optical-sizing:var(--USER__fontOpticalSizing) !important;\n}\n\n:root[style*="--USER__letterSpacing"] h1,\n:root[style*="--USER__letterSpacing"] h2,\n:root[style*="--USER__letterSpacing"] h3,\n:root[style*="--USER__letterSpacing"] h4,\n:root[style*="--USER__letterSpacing"] h5,\n:root[style*="--USER__letterSpacing"] h6,\n:root[style*="--USER__letterSpacing"] p,\n:root[style*="--USER__letterSpacing"] li,\n:root[style*="--USER__letterSpacing"] div,\n:root[style*="--USER__letterSpacing"] dt,\n:root[style*="--USER__letterSpacing"] dd{\n letter-spacing:var(--USER__letterSpacing) !important;\n font-variant:none !important;\n}\n\n:root[style*="readium-noRuby-on"] body rt,\n:root[style*="readium-noRuby-on"] body rp{\n display:none;\n}\n\n:root[style*="readium-blend-on"] svg,\n:root[style*="readium-blend-on"] img{\n background-color:transparent !important;\n mix-blend-mode:multiply !important;\n}\n\n:root[style*="--USER__darkenImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) !important;\n filter:brightness(var(--USER__darkenImages)) !important;\n}\n\n:root[style*="readium-darken-on"] img{\n -webkit-filter:brightness(80%) !important;\n filter:brightness(80%) !important;\n}\n\n:root[style*="--USER__invertImages"] img{\n -webkit-filter:invert(var(--USER__invertImages)) !important;\n filter:invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-invert-on"] img{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n}\n\n:root[style*="readium-darken-on"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(80%) invert(100%) !important;\n filter:brightness(80%) invert(100%) !important;\n}\n\n:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{\n -webkit-filter:invert(var(--USER__invertGaiji)) !important;\n filter:invert(var(--USER__invertGaiji)) !important;\n}\n\n:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="readium-normalize-on"]{\n --USER__typeScale:1.2;\n}\n\n:root[style*="readium-normalize-on"] p,\n:root[style*="readium-normalize-on"] li,\n:root[style*="readium-normalize-on"] div,\n:root[style*="readium-normalize-on"] pre,\n:root[style*="readium-normalize-on"] dd{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] h1{\n font-size:1.75rem !important;\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h2{\n font-size:1.5rem !important;\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h3{\n font-size:1.25rem !important;\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h4,\n:root[style*="readium-normalize-on"] h5,\n:root[style*="readium-normalize-on"] h6{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] small{\n font-size:smaller !important;\n}\n\n:root[style*="readium-normalize-on"] sub,\n:root[style*="readium-normalize-on"] sup{\n font-size:67.5% !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-iPadOSPatch-on"] body{\n -webkit-text-size-adjust:none;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p, \n:root[style*="readium-iPadOSPatch-on"] h1, \n:root[style*="readium-iPadOSPatch-on"] h2, \n:root[style*="readium-iPadOSPatch-on"] h3, \n:root[style*="readium-iPadOSPatch-on"] h4, \n:root[style*="readium-iPadOSPatch-on"] h5, \n:root[style*="readium-iPadOSPatch-on"] h6, \n:root[style*="readium-iPadOSPatch-on"] li, \n:root[style*="readium-iPadOSPatch-on"] th, \n:root[style*="readium-iPadOSPatch-on"] td, \n:root[style*="readium-iPadOSPatch-on"] dt, \n:root[style*="readium-iPadOSPatch-on"] dd, \n:root[style*="readium-iPadOSPatch-on"] pre, \n:root[style*="readium-iPadOSPatch-on"] address, \n:root[style*="readium-iPadOSPatch-on"] details, \n:root[style*="readium-iPadOSPatch-on"] summary,\n:root[style*="readium-iPadOSPatch-on"] figcaption,\n:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)),\n:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){\n -webkit-text-zoom:reset;\n}\n\n:root[style*="readium-iPadOSPatch-on"] abbr, \n:root[style*="readium-iPadOSPatch-on"] b, \n:root[style*="readium-iPadOSPatch-on"] bdi, \n:root[style*="readium-iPadOSPatch-on"] bdo, \n:root[style*="readium-iPadOSPatch-on"] cite, \n:root[style*="readium-iPadOSPatch-on"] code, \n:root[style*="readium-iPadOSPatch-on"] dfn, \n:root[style*="readium-iPadOSPatch-on"] em, \n:root[style*="readium-iPadOSPatch-on"] i, \n:root[style*="readium-iPadOSPatch-on"] kbd, \n:root[style*="readium-iPadOSPatch-on"] mark, \n:root[style*="readium-iPadOSPatch-on"] q, \n:root[style*="readium-iPadOSPatch-on"] rp, \n:root[style*="readium-iPadOSPatch-on"] rt, \n:root[style*="readium-iPadOSPatch-on"] ruby, \n:root[style*="readium-iPadOSPatch-on"] s, \n:root[style*="readium-iPadOSPatch-on"] samp, \n:root[style*="readium-iPadOSPatch-on"] small, \n:root[style*="readium-iPadOSPatch-on"] span, \n:root[style*="readium-iPadOSPatch-on"] strong, \n:root[style*="readium-iPadOSPatch-on"] sub, \n:root[style*="readium-iPadOSPatch-on"] sup, \n:root[style*="readium-iPadOSPatch-on"] time, \n:root[style*="readium-iPadOSPatch-on"] u, \n:root[style*="readium-iPadOSPatch-on"] var{\n -webkit-text-zoom:normal;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{\n -webkit-text-zoom:normal;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-after-XUKPAxfT.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-after-d5mC4cme.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__viewportWidth:100%;\n\n --RS__pageGutter:0;\n\n --RS__defaultLineLength:100%;\n\n --RS__colGap:0;\n\n --RS__colCount:1;\n\n --RS__colWidth:100vw;\n}\n\n@page{\n margin:0 !important;\n}\n\n:root{\n position:relative;\n\n -webkit-column-width:var(--RS__colWidth);\n -moz-column-width:var(--RS__colWidth);\n column-width:var(--RS__colWidth);\n -webkit-column-count:var(--RS__colCount);\n -moz-column-count:var(--RS__colCount);\n column-count:var(--RS__colCount);\n\n -webkit-column-gap:var(--RS__colGap);\n -moz-column-gap:var(--RS__colGap);\n column-gap:var(--RS__colGap);\n -moz-column-fill:auto;\n column-fill:auto;\n width:var(--RS__viewportWidth);\n height:100vh;\n max-width:var(--RS__viewportWidth);\n max-height:100vh;\n min-width:var(--RS__viewportWidth);\n min-height:100vh;\n padding:0 !important;\n margin:0 !important;\n font-size:1rem !important;\n box-sizing:border-box;\n -webkit-touch-callout:none;\n}\n\nbody{\n width:100%;\n max-width:var(--RS__defaultLineLength) !important;\n margin:0 auto !important;\n box-sizing:border-box;\n}\n\n:root:not([style*="readium-scroll-on"]) body{\n padding:0 var(--RS__pageGutter) !important;\n}\n\n:root:not([style*="readium-noOverflow-on"]) body{\n overflow:hidden;\n}\n\n@supports (overflow: clip){\n\n :root:not([style*="readium-noOverflow-on"]){\n overflow:clip;\n }\n\n :root:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n overflow-clip-margin:content-box;\n }\n}\n\n:root[style*="readium-scroll-on"]{\n -webkit-columns:auto auto !important;\n -moz-columns:auto auto !important;\n columns:auto auto !important;\n width:auto !important;\n height:auto !important;\n max-width:none !important;\n max-height:none !important;\n min-width:0 !important;\n min-height:0 !important;\n}\n\n:root[style*="readium-scroll-on"] body{\n max-width:var(--RS__defaultLineLength) !important;\n box-sizing:border-box !important;\n}\n\n:root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:auto;\n}\n\n@supports (overflow: clip){\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]){\n overflow:auto;\n }\n\n :root[style*="readium-scroll-on"]:not([style*="readium-noOverflow-on"]) body{\n overflow:clip;\n }\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingTop"] body{\n padding-top:var(--RS__scrollPaddingTop) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingBottom"] body{\n padding-bottom:var(--RS__scrollPaddingBottom) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingLeft"] body{\n padding-left:var(--RS__scrollPaddingLeft) !important;\n}\n\n:root[style*="readium-scroll-on"][style*="--RS__scrollPaddingRight"] body{\n padding-right:var(--RS__scrollPaddingRight) !important;\n}\n\n:root[style*="--USER__backgroundColor"]{\n background-color:var(--USER__backgroundColor) !important;\n}\n\n:root[style*="--USER__backgroundColor"] *{\n background-color:transparent !important;\n}\n\n:root[style*="--USER__textColor"]{\n color:var(--USER__textColor) !important;\n}\n\n:root[style*="--USER__textColor"] *:not(a){\n color:inherit !important;\n background-color:transparent !important;\n border-color:currentcolor !important;\n}\n\n:root[style*="--USER__textColor"] svg text{\n fill:currentcolor !important;\n stroke:none !important;\n}\n\n:root[style*="--USER__linkColor"] a:link,\n:root[style*="--USER__linkColor"] a:link *{\n color:var(--USER__linkColor) !important;\n}\n\n:root[style*="--USER__visitedColor"] a:visited,\n:root[style*="--USER__visitedColor"] a:visited *{\n color:var(--USER__visitedColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{\n color:var(--USER__selectionTextColor) !important;\n background-color:var(--USER__selectionBackgroundColor) !important;\n}\n\n:root[style*="--USER__colCount"]{\n -webkit-column-count:var(--USER__colCount);\n -moz-column-count:var(--USER__colCount);\n column-count:var(--USER__colCount);\n\n --RS__colWidth:auto;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"]{\n -webkit-column-count:1;\n -moz-column-count:1;\n column-count:1;\n}\n\n:root[style*="--USER__colCount: 0"],\n:root[style*="--USER__colCount:0"],\n:root[style*="--USER__colCount: 1"],\n:root[style*="--USER__colCount:1"]{\n --RS__colWidth:100vw;\n}\n\n:root[style*="--USER__lineLength"] body{\n max-width:var(--USER__lineLength) !important;\n }\n\n:root[style*="--USER__textAlign"]{\n text-align:var(--USER__textAlign);\n}\n\n:root[style*="--USER__textAlign"] body,\n:root[style*="--USER__textAlign"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n),\n:root[style*="--USER__textAlign"] li,\n:root[style*="--USER__textAlign"] dd{\n text-align:var(--USER__textAlign) !important;\n -moz-text-align-last:auto !important;\n -epub-text-align-last:auto !important;\n text-align-last:auto !important;\n}\n\n:root[style*="--USER__fontFamily"]{\n font-family:var(--USER__fontFamily) !important;\n}\n\n:root[style*="--USER__fontFamily"] *{\n font-family:revert !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] body{\n zoom:var(--USER__fontSize) !important;\n}\n\n:root:not([style*="readium-deprecatedFontSize-on"])[style*="readium-iOSPatch-on"][style*="--USER__fontSize"] body{\n -webkit-text-size-adjust:var(--USER__fontSize) !important;\n}\n\n@supports selector(figure:has(> img)){\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> img),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> video),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> svg),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> canvas),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> iframe),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figure:has(> audio),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> img:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> video:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> svg:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> canvas:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> iframe:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] div:has(> audio:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] table{\n zoom:calc(100% / var(--USER__fontSize)) !important;\n }\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] figcaption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] caption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] td,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-deprecatedFontSize-on"]):not([style*="readium-iOSPatch-on"])[style*="--USER__fontSize"] th{\n zoom:var(--USER__fontSize) !important;\n }\n}\n\n@supports not (zoom: 1){\n\n :root[style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n }\n}\n\n:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{\n font-size:var(--USER__fontSize) !important;\n}\n\n:root[style*="--USER__lineHeight"]{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__lineHeight"] body,\n:root[style*="--USER__lineHeight"] p,\n:root[style*="--USER__lineHeight"] li,\n:root[style*="--USER__lineHeight"] div{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__paraSpacing"] p{\n margin-top:var(--USER__paraSpacing) !important;\n margin-bottom:var(--USER__paraSpacing) !important;\n}\n\n:root[style*="--USER__paraIndent"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n){\n text-indent:var(--USER__paraIndent) !important;\n}\n\n:root[style*="--USER__paraIndent"] p *{\n text-indent:0 !important;\n}\n\n:root[style*="--USER__wordSpacing"] h1,\n:root[style*="--USER__wordSpacing"] h2,\n:root[style*="--USER__wordSpacing"] h3,\n:root[style*="--USER__wordSpacing"] h4,\n:root[style*="--USER__wordSpacing"] h5,\n:root[style*="--USER__wordSpacing"] h6,\n:root[style*="--USER__wordSpacing"] p,\n:root[style*="--USER__wordSpacing"] li,\n:root[style*="--USER__wordSpacing"] div,\n:root[style*="--USER__wordSpacing"] dt,\n:root[style*="--USER__wordSpacing"] dd{\n word-spacing:var(--USER__wordSpacing) !important;\n}\n\n:root[style*="--USER__ligatures"]{\n font-variant-ligatures:var(--USER__ligatures) !important;\n}\n\n:root[style*="--USER__ligatures"] *{\n font-variant-ligatures:inherit !important;\n}\n\n:root[style*="--USER__fontWeight"] body{\n font-weight:var(--USER__fontWeight) !important;\n}\n\n:root[style*="--USER__fontWeight"] b,\n:root[style*="--USER__fontWeight"] strong{\n font-weight:bolder;\n}\n\n:root[style*="--USER__fontWidth"] body{\n font-stretch:var(--USER__fontWidth) !important;\n}\n\n:root[style*="--USER__fontOpticalSizing"] body{\n font-optical-sizing:var(--USER__fontOpticalSizing) !important;\n}\n\n:root[style*="readium-blend-on"] svg,\n:root[style*="readium-blend-on"] img{\n background-color:transparent !important;\n mix-blend-mode:multiply !important;\n}\n\n:root[style*="--USER__darkenImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) !important;\n filter:brightness(var(--USER__darkenImages)) !important;\n}\n\n:root[style*="readium-darken-on"] img{\n -webkit-filter:brightness(80%) !important;\n filter:brightness(80%) !important;\n}\n\n:root[style*="--USER__invertImages"] img{\n -webkit-filter:invert(var(--USER__invertImages)) !important;\n filter:invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-invert-on"] img{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{\n -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n filter:brightness(80%) invert(var(--USER__invertImages)) !important;\n}\n\n:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n filter:brightness(var(--USER__darkenImages)) invert(100%) !important;\n}\n\n:root[style*="readium-darken-on"][style*="readium-invert-on"] img{\n -webkit-filter:brightness(80%) invert(100%) !important;\n filter:brightness(80%) invert(100%) !important;\n}\n\n:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{\n -webkit-filter:invert(var(--USER__invertGaiji)) !important;\n filter:invert(var(--USER__invertGaiji)) !important;\n}\n\n:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{\n -webkit-filter:invert(100%) !important;\n filter:invert(100%) !important;\n}\n\n:root[style*="readium-normalize-on"]{\n --USER__typeScale:1.2;\n}\n\n:root[style*="readium-normalize-on"] p,\n:root[style*="readium-normalize-on"] li,\n:root[style*="readium-normalize-on"] div,\n:root[style*="readium-normalize-on"] pre,\n:root[style*="readium-normalize-on"] dd{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] h1{\n font-size:1.75rem !important;\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h2{\n font-size:1.5rem !important;\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h3{\n font-size:1.25rem !important;\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"] h4,\n:root[style*="readium-normalize-on"] h5,\n:root[style*="readium-normalize-on"] h6{\n font-size:1rem !important;\n}\n\n:root[style*="readium-normalize-on"] small{\n font-size:smaller !important;\n}\n\n:root[style*="readium-normalize-on"] sub,\n:root[style*="readium-normalize-on"] sup{\n font-size:67.5% !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{\n font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{\n font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{\n font-size:calc(1rem * var(--USER__typeScale)) !important;\n}\n\n:root[style*="readium-iPadOSPatch-on"] body{\n -webkit-text-size-adjust:none;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p, \n:root[style*="readium-iPadOSPatch-on"] h1, \n:root[style*="readium-iPadOSPatch-on"] h2, \n:root[style*="readium-iPadOSPatch-on"] h3, \n:root[style*="readium-iPadOSPatch-on"] h4, \n:root[style*="readium-iPadOSPatch-on"] h5, \n:root[style*="readium-iPadOSPatch-on"] h6, \n:root[style*="readium-iPadOSPatch-on"] li, \n:root[style*="readium-iPadOSPatch-on"] th, \n:root[style*="readium-iPadOSPatch-on"] td, \n:root[style*="readium-iPadOSPatch-on"] dt, \n:root[style*="readium-iPadOSPatch-on"] dd, \n:root[style*="readium-iPadOSPatch-on"] pre, \n:root[style*="readium-iPadOSPatch-on"] address, \n:root[style*="readium-iPadOSPatch-on"] details, \n:root[style*="readium-iPadOSPatch-on"] summary,\n:root[style*="readium-iPadOSPatch-on"] figcaption,\n:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)),\n:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){\n -webkit-text-zoom:reset;\n}\n\n:root[style*="readium-iPadOSPatch-on"] abbr, \n:root[style*="readium-iPadOSPatch-on"] b, \n:root[style*="readium-iPadOSPatch-on"] bdi, \n:root[style*="readium-iPadOSPatch-on"] bdo, \n:root[style*="readium-iPadOSPatch-on"] cite, \n:root[style*="readium-iPadOSPatch-on"] code, \n:root[style*="readium-iPadOSPatch-on"] dfn, \n:root[style*="readium-iPadOSPatch-on"] em, \n:root[style*="readium-iPadOSPatch-on"] i, \n:root[style*="readium-iPadOSPatch-on"] kbd, \n:root[style*="readium-iPadOSPatch-on"] mark, \n:root[style*="readium-iPadOSPatch-on"] q, \n:root[style*="readium-iPadOSPatch-on"] rp, \n:root[style*="readium-iPadOSPatch-on"] rt, \n:root[style*="readium-iPadOSPatch-on"] ruby, \n:root[style*="readium-iPadOSPatch-on"] s, \n:root[style*="readium-iPadOSPatch-on"] samp, \n:root[style*="readium-iPadOSPatch-on"] small, \n:root[style*="readium-iPadOSPatch-on"] span, \n:root[style*="readium-iPadOSPatch-on"] strong, \n:root[style*="readium-iPadOSPatch-on"] sub, \n:root[style*="readium-iPadOSPatch-on"] sup, \n:root[style*="readium-iPadOSPatch-on"] time, \n:root[style*="readium-iPadOSPatch-on"] u, \n:root[style*="readium-iPadOSPatch-on"] var{\n -webkit-text-zoom:normal;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{\n -webkit-text-zoom:normal;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-after-d5mC4cme.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-before-8FMq19-x.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url(\"http://www.w3.org/1999/xhtml\");\n\n@namespace epub url(\"http://www.idpf.org/2007/ops\");\n\n@namespace m url(\"http://www.w3.org/1998/Math/MathML\");\n\n@namespace svg url(\"http://www.w3.org/2000/svg\");\n\n@-ms-viewport{\n width:device-width;\n}\n\n@viewport{\n width:device-width;\n zoom:1;\n}\n\n:root{\n\n --RS__sans-serif-ja-v:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDGothic', 'Yu Gothic', 'MSゴシック', 'MS Gothic', sans-serif;\n\n --RS__serif-ja-v:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDMincho', 'Yu Mincho', 'MS明朝', 'MS Mincho', serif;\n\n --RS__sans-serif-ja:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDPGothic', 'Yu Gothic', 'MS Pゴシック', 'MS PGothic', sans-serif;\n\n --RS__serif-ja:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDPMincho', 'Yu Mincho', 'MS P明朝', 'MS PMincho', serif;\n\n --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n\n --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif;\n\n --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif;\n\n --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif;\n\n --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif;\n\n --RS__zh-HK-lineHeightCompensation:1.167;\n\n --RS__zh-HK-baseFontFamily:'方體', 'PingFang HK', '方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-TW-lineHeightCompensation:1.167;\n\n --RS__zh-TW-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-Hant-lineHeightCompensation:1.167;\n\n --RS__zh-Hant-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-lineHeightCompensation:1.167;\n\n --RS__zh-baseFontFamily:'方体', 'PingFang SC', '黑体', 'Heiti SC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK SC', sans-serif;\n\n --RS__th-lineHeightCompensation:1.067;\n\n --RS__th-baseFontFamily:Thonburi, 'Leelawadee UI', 'Cordia New', Roboto, Noto, 'Noto Sans Thai', sans-serif;\n\n --RS__te-baseFontFamily:'Kohinoor Telugu', 'Telugu Sangam MN', 'Nirmala UI', Gautami, Roboto, Noto, 'Noto Sans Telugu', sans-serif;\n\n --RS__ta-lineHeightCompensation:1.067;\n\n --RS__ta-baseFontFamily:'Tamil Sangam MN', 'Nirmala UI', Latha, Roboto, Noto, 'Noto Sans Tamil', sans-serif;\n\n --RS__si-lineHeightCompensation:1.167;\n\n --RS__si-baseFontFamily:'Sinhala Sangam MN', 'Nirmala UI', 'Iskoola Pota', Roboto, Noto, 'Noto Sans Sinhala', sans-serif;\n\n --RS__pa-lineHeightCompensation:1.1;\n\n --RS__pa-baseFontFamily:'Gurmukhi MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Gurmukhi', sans-serif;\n\n --RS__or-lineHeightCompensation:1.167;\n\n --RS__or-baseFontFamily:'Oriya Sangam MN', 'Nirmala UI', Kalinga, Roboto, Noto, 'Noto Sans Oriya', sans-serif;\n\n --RS__ml-lineHeightCompensation:1.067;\n\n --RS__ml-baseFontFamily:'Malayalam Sangam MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Malayalam', sans-serif;\n\n --RS__lo-baseFontFamily:'Lao Sangam MN', 'Leelawadee UI', 'Lao UI', Roboto, Noto, 'Noto Sans Lao', sans-serif;\n\n --RS__ko-lineHeightCompensation:1.167;\n\n --RS__ko-baseFontFamily:'Nanum Gothic', 'Apple SD Gothic Neo', 'Malgun Gothic', Roboto, Noto, 'Noto Sans CJK KR', sans-serif;\n\n --RS__kn-lineHeightCompensation:1.1;\n\n --RS__kn-baseFontFamily:'Kannada Sangam MN', 'Nirmala UI', Tunga, Roboto, Noto, 'Noto Sans Kannada', sans-serif;\n\n --RS__km-lineHeightCompensation:1.067;\n\n --RS__km-baseFontFamily:'Khmer Sangam MN', 'Leelawadee UI', 'Khmer UI', Roboto, Noto, 'Noto Sans Khmer', sans-serif;\n\n --RS__ja-lineHeightCompensation:1.167;\n\n --RS__ja-baseFontFamily:YuGothic, 'Hiragino Maru Gothic ProN', 'Hiragino Sans', 'Yu Gothic UI', 'Meiryo UI', 'MS Gothic', Roboto, Noto, 'Noto Sans CJK JP', sans-serif;\n\n --RS__iu-baseFontFamily:'Euphemia UCAS', Euphemia, Roboto, Noto, 'Noto Sans Canadian Aboriginal', sans-serif;\n\n --RS__hy-baseFontFamily:Mshtakan, Sylfaen, Roboto, Noto, 'Noto Serif Armenian', serif;\n\n --RS__hi-lineHeightCompensation:1.1;\n\n --RS__hi-baseFontFamily:'Kohinoor Devanagari', 'Devanagari Sangam MN', Kokila, 'Nirmala UI', Roboto, Noto, 'Noto Sans Devanagari', sans-serif;\n\n --RS__he-lineHeightCompensation:1.1;\n\n --RS__he-baseFontFamily:'New Peninim MT', 'Arial Hebrew', Gisha, 'Times New Roman', Roboto, Noto, 'Noto Sans Hebrew', sans-serif;\n\n --RS__gu-lineHeightCompensation:1.167;\n\n --RS__gu-baseFontFamily:'Gujarati Sangam MN', 'Nirmala UI', Shruti, Roboto, Noto, 'Noto Sans Gujarati', sans-serif;\n\n --RS__fa-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__chr-lineHeightCompensation:1.167;\n\n --RS__chr-baseFontFamily:'Plantagenet Cherokee', Roboto, Noto, 'Noto Sans Cherokee';\n\n --RS__bo-baseFontFamily:Kailasa, 'Microsoft Himalaya', Roboto, Noto, 'Noto Sans Tibetan', sans-serif;\n\n --RS__bn-lineHeightCompensation:1.067;\n\n --RS__bn-baseFontFamily:'Kohinoor Bangla', 'Bangla Sangam MN', Vrinda, Roboto, Noto, 'Noto Sans Bengali', sans-serif;\n\n --RS__ar-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__am-lineHeightCompensation:1.167;\n\n --RS__am-baseFontFamily:Kefa, Nyala, Roboto, Noto, 'Noto Sans Ethiopic', serif;\n\n --RS__latin-lineHeightCompensation:1;\n\n --RS__latin-baseFontFamily:var(--RS__oldStyleTf);\n --RS__baseFontFamily:var(--RS__latin-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__latin-lineHeightCompensation);\n --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation));\n\n --RS__selectionTextColor:inherit;\n\n --RS__selectionBackgroundColor:#b4d8fe;\n\n --RS__visitedColor:#551A8B;\n\n --RS__linkColor:#0000EE;\n\n --RS__textColor:#121212;\n\n --RS__backgroundColor:#FFFFFF;\n color:var(--RS__textColor) !important;\n\n background-color:var(--RS__backgroundColor) !important;\n}\n\n::-moz-selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\n::selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\nhtml{\n font-family:var(--RS__baseFontFamily);\n line-height:1.6;\n line-height:var(--RS__baseLineHeight);\n text-rendering:optimizelegibility;\n}\n\nh1, h2, h3{\n line-height:normal;\n}\n\n:lang(ja),\n:lang(zh),\n:lang(ko){\n word-wrap:break-word;\n -webkit-line-break:strict;\n -epub-line-break:strict;\n line-break:strict;\n}\n\nmath{\n font-family:\"Latin Modern Math\", \"STIX Two Math\", \"XITS Math\", \"STIX Math\", \"Libertinus Math\", \"TeX Gyre Termes Math\", \"TeX Gyre Bonum Math\", \"TeX Gyre Schola\", \"DejaVu Math TeX Gyre\", \"TeX Gyre Pagella Math\", \"Asana Math\", \"Cambria Math\", \"Lucida Bright Math\", \"Minion Math\", STIXGeneral, STIXSizeOneSym, Symbol, \"Times New Roman\", serif;\n}\n\n:lang(am){\n --RS__baseFontFamily:var(--RS__am-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__am-lineHeightCompensation);\n}\n\n:lang(ar){\n --RS__baseFontFamily:var(--RS__ar-baseFontFamily);\n}\n\n:lang(bn){\n --RS__baseFontFamily:var(--RS__bn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__bn-lineHeightCompensation);\n}\n\n:lang(bo){\n --RS__baseFontFamily:var(--RS__bo-baseFontFamily);\n}\n\n:lang(chr){\n --RS__baseFontFamily:var(--RS__chr-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__chr-lineHeightCompensation);\n}\n\n:lang(fa){\n --RS__baseFontFamily:var(--RS__fa-baseFontFamily);\n}\n\n:lang(gu){\n --RS__baseFontFamily:var(--RS__gu-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__gu-lineHeightCompensation);\n}\n\n:lang(he){\n --RS__baseFontFamily:var(--RS__he-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__he-lineHeightCompensation);\n}\n\n:lang(hi){\n --RS__baseFontFamily:var(--RS__hi-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__hi-lineHeightCompensation);\n}\n\n:lang(hy){\n --RS__baseFontFamily:var(--RS__hy-baseFontFamily);\n}\n\n:lang(iu){\n --RS__baseFontFamily:var(--RS__iu-baseFontFamily);\n}\n\n:lang(ja){\n --RS__baseFontFamily:var(--RS__ja-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ja-lineHeightCompensation);\n}\n\n:lang(km){\n --RS__baseFontFamily:var(--RS__km-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__km-lineHeightCompensation);\n}\n\n:lang(kn){\n --RS__baseFontFamily:var(--RS__kn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__kn-lineHeightCompensation);\n}\n\n:lang(ko){\n --RS__baseFontFamily:var(--RS__ko-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ko-lineHeightCompensation);\n}\n\n:lang(lo){\n --RS__baseFontFamily:var(--RS__lo-baseFontFamily);\n}\n\n:lang(ml){\n --RS__baseFontFamily:var(--RS__ml-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ml-lineHeightCompensation);\n}\n\n:lang(or){\n --RS__baseFontFamily:var(--RS__or-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__or-lineHeightCompensation);\n}\n\n:lang(pa){\n --RS__baseFontFamily:var(--RS__pa-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__pa-lineHeightCompensation);\n}\n\n:lang(si){\n --RS__baseFontFamily:var(--RS__si-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__si-lineHeightCompensation);\n}\n\n:lang(ta){\n --RS__baseFontFamily:var(--RS__ta-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ta-lineHeightCompensation);\n}\n\n:lang(te){\n --RS__baseFontFamily:var(--RS__te-baseFontFamily);\n}\n\n:lang(th){\n --RS__baseFontFamily:var(--RS__th-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__th-lineHeightCompensation);\n}\n\n:lang(zh){\n --RS__baseFontFamily:var(--RS__zh-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-lineHeightCompensation);\n}\n\n:lang(zh-Hant){\n --RS__baseFontFamily:var(--RS__zh-Hant-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-Hant-lineHeightCompensation);\n}\n\n:lang(zh-TW){\n --RS__baseFontFamily:var(--RS__zh-TW-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-TW-lineHeightCompensation);\n}\n\n:lang(zh-HK){\n --RS__baseFontFamily:var(--RS__zh-HK-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-HK-lineHeightCompensation);\n}\n\nbody{\n widows:2;\n orphans:2;\n}\n\nfigcaption, th, td{\n widows:1;\n orphans:1;\n}\n\nh2, h3, h4, h5, h6, dt,\nhr, caption{\n -webkit-column-break-after:avoid;\n page-break-after:avoid;\n break-after:avoid;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigure, tr{\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\nbody{\n -webkit-hyphenate-character:\"\\\\002D\";\n -moz-hyphenate-character:\"\\\\002D\";\n -ms-hyphenate-character:\"\\\\002D\";\n hyphenate-character:\"\\\\002D\";\n -webkit-hyphenate-limit-lines:3;\n -ms-hyphenate-limit-lines:3;\n hyphenate-limit-lines:3;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigcaption, pre, caption, address,\ncenter, code, var{\n -ms-hyphens:none;\n -moz-hyphens:none;\n -webkit-hyphens:none;\n -epub-hyphens:none;\n hyphens:none;\n}\n\nbody{\n font-variant-numeric:oldstyle-nums proportional-nums;\n}\n\n:lang(ja) body,\n:lang(zh) body,\n:lang(ko) body{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\nh1, h2, h3, h4, h5, h6, dt{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\ntable{\n font-variant-numeric:lining-nums tabular-nums;\n}\n\ncode, var{\n font-variant-ligatures:none;\n font-variant-numeric:lining-nums tabular-nums slashed-zero;\n}\n\nrt{\n font-variant-east-asian:ruby;\n}\n\n:lang(ar){\n font-variant-ligatures:common-ligatures;\n}\n\n:lang(ko){\n font-kerning:normal;\n}\n\nhr{\n color:inherit;\n border-color:currentcolor;\n}\n\ntable, th, td{\n border-color:currentcolor;\n}\n\nfigure, blockquote{\n margin:1em 5%;\n}\n\nul, ol{\n padding-left:5%;\n}\n\ndd{\n margin-left:5%;\n}\n\npre{\n white-space:pre-wrap;\n -ms-tab-size:2;\n -moz-tab-size:2;\n -webkit-tab-size:2;\n tab-size:2;\n}\n\nabbr[title], acronym[title]{\n text-decoration:dotted underline;\n}\n\nnobr wbr{\n white-space:normal;\n}\n\nruby > rt, ruby > rp{\n -webkit-user-select:none;\n -moz-user-select:none;\n -ms-user-select:none;\n user-select:none;\n}\n\n*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)),\n*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)),\n*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)),\n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i,\n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i,\n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{\n font-style:normal;\n}\n\n:lang(ja) a,\n:lang(zh) a,\n:lang(ko) a{\n text-decoration:none;\n}\n\n:root{\n --RS__maxMediaWidth:100%;\n --RS__maxMediaHeight:95vh;\n --RS__boxSizingMedia:border-box;\n --RS__boxSizingTable:border-box;\n}\n\na, a span, span a, h1, h2, h3, h4, h5, h6{\n word-wrap:break-word;\n}\n\ndiv{\n max-width:var(--RS__maxMediaWidth);\n}\n\nimg, svg|svg, video{\n object-fit:contain;\n\n width:auto;\n height:auto;\n max-width:var(--RS__maxMediaWidth);\n max-height:var(--RS__maxMediaHeight) !important;\n box-sizing:var(--RS__boxSizingMedia);\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\n@supports (zoom: 1) and (not ((-webkit-column-axis: horizontal) and (-webkit-column-progression: normal))){\n\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] img,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] svg|svg,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] video{\n zoom:calc(100% / var(--USER__fontSize));\n }\n}\n\naudio{\n max-width:100%;\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n }\n\ntable{\n max-width:var(--RS__maxMediaWidth);\n box-sizing:var(--RS__boxSizingTable);\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-before-8FMq19-x.js?\n}")},"./node_modules/@readium/navigator/dist/ReadiumCSS-before-BNTwR8Qm.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url(\"http://www.w3.org/1999/xhtml\");\n\n@namespace epub url(\"http://www.idpf.org/2007/ops\");\n\n@namespace m url(\"http://www.w3.org/1998/Math/MathML\");\n\n@namespace svg url(\"http://www.w3.org/2000/svg\");\n\n@-ms-viewport{\n width:device-width;\n}\n\n@viewport{\n width:device-width;\n zoom:1;\n}\n\n:root{\n\n --RS__sans-serif-ja-v:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDGothic', 'Yu Gothic', 'MSゴシック', 'MS Gothic', sans-serif;\n\n --RS__serif-ja-v:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDMincho', 'Yu Mincho', 'MS明朝', 'MS Mincho', serif;\n\n --RS__sans-serif-ja:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDPGothic', 'Yu Gothic', 'MS Pゴシック', 'MS PGothic', sans-serif;\n\n --RS__serif-ja:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDPMincho', 'Yu Mincho', 'MS P明朝', 'MS PMincho', serif;\n\n --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n\n --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif;\n\n --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif;\n\n --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif;\n\n --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif;\n\n --RS__zh-HK-lineHeightCompensation:1.167;\n\n --RS__zh-HK-baseFontFamily:'方體', 'PingFang HK', '方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-TW-lineHeightCompensation:1.167;\n\n --RS__zh-TW-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-Hant-lineHeightCompensation:1.167;\n\n --RS__zh-Hant-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-lineHeightCompensation:1.167;\n\n --RS__zh-baseFontFamily:'方体', 'PingFang SC', '黑体', 'Heiti SC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK SC', sans-serif;\n\n --RS__th-lineHeightCompensation:1.067;\n\n --RS__th-baseFontFamily:Thonburi, 'Leelawadee UI', 'Cordia New', Roboto, Noto, 'Noto Sans Thai', sans-serif;\n\n --RS__te-baseFontFamily:'Kohinoor Telugu', 'Telugu Sangam MN', 'Nirmala UI', Gautami, Roboto, Noto, 'Noto Sans Telugu', sans-serif;\n\n --RS__ta-lineHeightCompensation:1.067;\n\n --RS__ta-baseFontFamily:'Tamil Sangam MN', 'Nirmala UI', Latha, Roboto, Noto, 'Noto Sans Tamil', sans-serif;\n\n --RS__si-lineHeightCompensation:1.167;\n\n --RS__si-baseFontFamily:'Sinhala Sangam MN', 'Nirmala UI', 'Iskoola Pota', Roboto, Noto, 'Noto Sans Sinhala', sans-serif;\n\n --RS__pa-lineHeightCompensation:1.1;\n\n --RS__pa-baseFontFamily:'Gurmukhi MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Gurmukhi', sans-serif;\n\n --RS__or-lineHeightCompensation:1.167;\n\n --RS__or-baseFontFamily:'Oriya Sangam MN', 'Nirmala UI', Kalinga, Roboto, Noto, 'Noto Sans Oriya', sans-serif;\n\n --RS__ml-lineHeightCompensation:1.067;\n\n --RS__ml-baseFontFamily:'Malayalam Sangam MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Malayalam', sans-serif;\n\n --RS__lo-baseFontFamily:'Lao Sangam MN', 'Leelawadee UI', 'Lao UI', Roboto, Noto, 'Noto Sans Lao', sans-serif;\n\n --RS__ko-lineHeightCompensation:1.167;\n\n --RS__ko-baseFontFamily:'Nanum Gothic', 'Apple SD Gothic Neo', 'Malgun Gothic', Roboto, Noto, 'Noto Sans CJK KR', sans-serif;\n\n --RS__kn-lineHeightCompensation:1.1;\n\n --RS__kn-baseFontFamily:'Kannada Sangam MN', 'Nirmala UI', Tunga, Roboto, Noto, 'Noto Sans Kannada', sans-serif;\n\n --RS__km-lineHeightCompensation:1.067;\n\n --RS__km-baseFontFamily:'Khmer Sangam MN', 'Leelawadee UI', 'Khmer UI', Roboto, Noto, 'Noto Sans Khmer', sans-serif;\n\n --RS__ja-lineHeightCompensation:1.167;\n\n --RS__ja-baseFontFamily:YuGothic, 'Hiragino Maru Gothic ProN', 'Hiragino Sans', 'Yu Gothic UI', 'Meiryo UI', 'MS Gothic', Roboto, Noto, 'Noto Sans CJK JP', sans-serif;\n\n --RS__iu-baseFontFamily:'Euphemia UCAS', Euphemia, Roboto, Noto, 'Noto Sans Canadian Aboriginal', sans-serif;\n\n --RS__hy-baseFontFamily:Mshtakan, Sylfaen, Roboto, Noto, 'Noto Serif Armenian', serif;\n\n --RS__hi-lineHeightCompensation:1.1;\n\n --RS__hi-baseFontFamily:'Kohinoor Devanagari', 'Devanagari Sangam MN', Kokila, 'Nirmala UI', Roboto, Noto, 'Noto Sans Devanagari', sans-serif;\n\n --RS__he-lineHeightCompensation:1.1;\n\n --RS__he-baseFontFamily:'New Peninim MT', 'Arial Hebrew', Gisha, 'Times New Roman', Roboto, Noto, 'Noto Sans Hebrew', sans-serif;\n\n --RS__gu-lineHeightCompensation:1.167;\n\n --RS__gu-baseFontFamily:'Gujarati Sangam MN', 'Nirmala UI', Shruti, Roboto, Noto, 'Noto Sans Gujarati', sans-serif;\n\n --RS__fa-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__chr-lineHeightCompensation:1.167;\n\n --RS__chr-baseFontFamily:'Plantagenet Cherokee', Roboto, Noto, 'Noto Sans Cherokee';\n\n --RS__bo-baseFontFamily:Kailasa, 'Microsoft Himalaya', Roboto, Noto, 'Noto Sans Tibetan', sans-serif;\n\n --RS__bn-lineHeightCompensation:1.067;\n\n --RS__bn-baseFontFamily:'Kohinoor Bangla', 'Bangla Sangam MN', Vrinda, Roboto, Noto, 'Noto Sans Bengali', sans-serif;\n\n --RS__ar-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__am-lineHeightCompensation:1.167;\n\n --RS__am-baseFontFamily:Kefa, Nyala, Roboto, Noto, 'Noto Sans Ethiopic', serif;\n\n --RS__latin-lineHeightCompensation:1;\n\n --RS__latin-baseFontFamily:var(--RS__oldStyleTf);\n --RS__baseFontFamily:var(--RS__latin-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__latin-lineHeightCompensation);\n --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation));\n\n --RS__selectionTextColor:inherit;\n\n --RS__selectionBackgroundColor:#b4d8fe;\n\n --RS__visitedColor:#551A8B;\n\n --RS__linkColor:#0000EE;\n\n --RS__textColor:#121212;\n\n --RS__backgroundColor:#FFFFFF;\n color:var(--RS__textColor) !important;\n\n background-color:var(--RS__backgroundColor) !important;\n}\n\n::-moz-selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\n::selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\nhtml{\n font-family:var(--RS__baseFontFamily);\n line-height:1.6;\n line-height:var(--RS__baseLineHeight);\n text-rendering:optimizelegibility;\n}\n\nh1, h2, h3{\n line-height:normal;\n}\n\n:lang(ja),\n:lang(zh),\n:lang(ko){\n word-wrap:break-word;\n -webkit-line-break:strict;\n -epub-line-break:strict;\n line-break:strict;\n}\n\nmath{\n font-family:\"Latin Modern Math\", \"STIX Two Math\", \"XITS Math\", \"STIX Math\", \"Libertinus Math\", \"TeX Gyre Termes Math\", \"TeX Gyre Bonum Math\", \"TeX Gyre Schola\", \"DejaVu Math TeX Gyre\", \"TeX Gyre Pagella Math\", \"Asana Math\", \"Cambria Math\", \"Lucida Bright Math\", \"Minion Math\", STIXGeneral, STIXSizeOneSym, Symbol, \"Times New Roman\", serif;\n}\n\n:lang(am){\n --RS__baseFontFamily:var(--RS__am-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__am-lineHeightCompensation);\n}\n\n:lang(ar){\n --RS__baseFontFamily:var(--RS__ar-baseFontFamily);\n}\n\n:lang(bn){\n --RS__baseFontFamily:var(--RS__bn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__bn-lineHeightCompensation);\n}\n\n:lang(bo){\n --RS__baseFontFamily:var(--RS__bo-baseFontFamily);\n}\n\n:lang(chr){\n --RS__baseFontFamily:var(--RS__chr-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__chr-lineHeightCompensation);\n}\n\n:lang(fa){\n --RS__baseFontFamily:var(--RS__fa-baseFontFamily);\n}\n\n:lang(gu){\n --RS__baseFontFamily:var(--RS__gu-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__gu-lineHeightCompensation);\n}\n\n:lang(he){\n --RS__baseFontFamily:var(--RS__he-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__he-lineHeightCompensation);\n}\n\n:lang(hi){\n --RS__baseFontFamily:var(--RS__hi-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__hi-lineHeightCompensation);\n}\n\n:lang(hy){\n --RS__baseFontFamily:var(--RS__hy-baseFontFamily);\n}\n\n:lang(iu){\n --RS__baseFontFamily:var(--RS__iu-baseFontFamily);\n}\n\n:lang(ja){\n --RS__baseFontFamily:var(--RS__ja-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ja-lineHeightCompensation);\n}\n\n:lang(km){\n --RS__baseFontFamily:var(--RS__km-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__km-lineHeightCompensation);\n}\n\n:lang(kn){\n --RS__baseFontFamily:var(--RS__kn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__kn-lineHeightCompensation);\n}\n\n:lang(ko){\n --RS__baseFontFamily:var(--RS__ko-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ko-lineHeightCompensation);\n}\n\n:lang(lo){\n --RS__baseFontFamily:var(--RS__lo-baseFontFamily);\n}\n\n:lang(ml){\n --RS__baseFontFamily:var(--RS__ml-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ml-lineHeightCompensation);\n}\n\n:lang(or){\n --RS__baseFontFamily:var(--RS__or-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__or-lineHeightCompensation);\n}\n\n:lang(pa){\n --RS__baseFontFamily:var(--RS__pa-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__pa-lineHeightCompensation);\n}\n\n:lang(si){\n --RS__baseFontFamily:var(--RS__si-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__si-lineHeightCompensation);\n}\n\n:lang(ta){\n --RS__baseFontFamily:var(--RS__ta-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ta-lineHeightCompensation);\n}\n\n:lang(te){\n --RS__baseFontFamily:var(--RS__te-baseFontFamily);\n}\n\n:lang(th){\n --RS__baseFontFamily:var(--RS__th-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__th-lineHeightCompensation);\n}\n\n:lang(zh){\n --RS__baseFontFamily:var(--RS__zh-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-lineHeightCompensation);\n}\n\n:lang(zh-Hant){\n --RS__baseFontFamily:var(--RS__zh-Hant-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-Hant-lineHeightCompensation);\n}\n\n:lang(zh-TW){\n --RS__baseFontFamily:var(--RS__zh-TW-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-TW-lineHeightCompensation);\n}\n\n:lang(zh-HK){\n --RS__baseFontFamily:var(--RS__zh-HK-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-HK-lineHeightCompensation);\n}\n\nbody{\n widows:2;\n orphans:2;\n}\n\nfigcaption, th, td{\n widows:1;\n orphans:1;\n}\n\nh2, h3, h4, h5, h6, dt,\nhr, caption{\n -webkit-column-break-after:avoid;\n page-break-after:avoid;\n break-after:avoid;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigure, tr{\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\nbody{\n -webkit-hyphenate-character:\"\\\\002D\";\n -moz-hyphenate-character:\"\\\\002D\";\n -ms-hyphenate-character:\"\\\\002D\";\n hyphenate-character:\"\\\\002D\";\n -webkit-hyphenate-limit-lines:3;\n -ms-hyphenate-limit-lines:3;\n hyphenate-limit-lines:3;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigcaption, pre, caption, address,\ncenter, code, var{\n -ms-hyphens:none;\n -moz-hyphens:none;\n -webkit-hyphens:none;\n -epub-hyphens:none;\n hyphens:none;\n}\n\nbody{\n font-variant-numeric:oldstyle-nums proportional-nums;\n}\n\n:lang(ja) body,\n:lang(zh) body,\n:lang(ko) body{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\nh1, h2, h3, h4, h5, h6, dt{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\ntable{\n font-variant-numeric:lining-nums tabular-nums;\n}\n\ncode, var{\n font-variant-ligatures:none;\n font-variant-numeric:lining-nums tabular-nums slashed-zero;\n}\n\nrt{\n font-variant-east-asian:ruby;\n}\n\n:lang(ar){\n font-variant-ligatures:common-ligatures;\n}\n\n:lang(ko){\n font-kerning:normal;\n}\n\nhr{\n color:inherit;\n border-color:currentcolor;\n}\n\ntable, th, td{\n border-color:currentcolor;\n}\n\nfigure, blockquote{\n margin:1em 5%;\n}\n\nul, ol{\n padding-left:5%;\n}\n\ndd{\n margin-left:5%;\n}\n\npre{\n white-space:pre-wrap;\n -ms-tab-size:2;\n -moz-tab-size:2;\n -webkit-tab-size:2;\n tab-size:2;\n}\n\nabbr[title], acronym[title]{\n text-decoration:dotted underline;\n}\n\nnobr wbr{\n white-space:normal;\n}\n\nruby > rt, ruby > rp{\n -webkit-user-select:none;\n -moz-user-select:none;\n -ms-user-select:none;\n user-select:none;\n}\n\n*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)),\n*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)),\n*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)),\n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i,\n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i,\n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{\n font-style:normal;\n}\n\n:lang(ja) a,\n:lang(zh) a,\n:lang(ko) a{\n text-decoration:none;\n}\n\n:root{\n --RS__maxMediaWidth:100%;\n --RS__maxMediaHeight:100vw;\n --RS__boxSizingMedia:border-box;\n --RS__boxSizingTable:border-box;\n}\n\na, a span, span a, h1, h2, h3, h4, h5, h6{\n word-wrap:break-word;\n}\n\ndiv{\n max-width:var(--RS__maxMediaHeight);\n}\n\nimg, svg|svg, video{\n object-fit:contain;\n\n width:auto;\n height:auto;\n max-width:var(--RS__maxMediaHeight);\n max-height:var(--RS__maxMediaWidth) !important;\n box-sizing:var(--RS__boxSizingMedia);\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\n@supports (zoom: 1) and (not ((-webkit-column-axis: horizontal) and (-webkit-column-progression: normal))){\n\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] img,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] svg|svg,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] video,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] div{\n zoom:calc(100% / var(--USER__fontSize));\n }\n}\n\naudio{\n max-width:100%;\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\ntable{\n max-height:var(--RS__maxMediaWidth);\n box-sizing:var(--RS__boxSizingTable);\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-before-BNTwR8Qm.js?\n}")},"./node_modules/@readium/navigator/dist/ReadiumCSS-before-CG-KmDa3.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url(\"http://www.w3.org/1999/xhtml\");\n\n@namespace epub url(\"http://www.idpf.org/2007/ops\");\n\n@namespace m url(\"http://www.w3.org/1998/Math/MathML\");\n\n@namespace svg url(\"http://www.w3.org/2000/svg\");\n\n@-ms-viewport{\n width:device-width;\n}\n\n@viewport{\n width:device-width;\n zoom:1;\n}\n\n:root{\n\n --RS__sans-serif-ja-v:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDGothic', 'Yu Gothic', 'MSゴシック', 'MS Gothic', sans-serif;\n\n --RS__serif-ja-v:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDMincho', 'Yu Mincho', 'MS明朝', 'MS Mincho', serif;\n\n --RS__sans-serif-ja:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDPGothic', 'Yu Gothic', 'MS Pゴシック', 'MS PGothic', sans-serif;\n\n --RS__serif-ja:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDPMincho', 'Yu Mincho', 'MS P明朝', 'MS PMincho', serif;\n\n --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n\n --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif;\n\n --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif;\n\n --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif;\n\n --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif;\n\n --RS__zh-HK-lineHeightCompensation:1.167;\n\n --RS__zh-HK-baseFontFamily:'方體', 'PingFang HK', '方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-TW-lineHeightCompensation:1.167;\n\n --RS__zh-TW-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-Hant-lineHeightCompensation:1.167;\n\n --RS__zh-Hant-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-lineHeightCompensation:1.167;\n\n --RS__zh-baseFontFamily:'方体', 'PingFang SC', '黑体', 'Heiti SC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK SC', sans-serif;\n\n --RS__th-lineHeightCompensation:1.067;\n\n --RS__th-baseFontFamily:Thonburi, 'Leelawadee UI', 'Cordia New', Roboto, Noto, 'Noto Sans Thai', sans-serif;\n\n --RS__te-baseFontFamily:'Kohinoor Telugu', 'Telugu Sangam MN', 'Nirmala UI', Gautami, Roboto, Noto, 'Noto Sans Telugu', sans-serif;\n\n --RS__ta-lineHeightCompensation:1.067;\n\n --RS__ta-baseFontFamily:'Tamil Sangam MN', 'Nirmala UI', Latha, Roboto, Noto, 'Noto Sans Tamil', sans-serif;\n\n --RS__si-lineHeightCompensation:1.167;\n\n --RS__si-baseFontFamily:'Sinhala Sangam MN', 'Nirmala UI', 'Iskoola Pota', Roboto, Noto, 'Noto Sans Sinhala', sans-serif;\n\n --RS__pa-lineHeightCompensation:1.1;\n\n --RS__pa-baseFontFamily:'Gurmukhi MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Gurmukhi', sans-serif;\n\n --RS__or-lineHeightCompensation:1.167;\n\n --RS__or-baseFontFamily:'Oriya Sangam MN', 'Nirmala UI', Kalinga, Roboto, Noto, 'Noto Sans Oriya', sans-serif;\n\n --RS__ml-lineHeightCompensation:1.067;\n\n --RS__ml-baseFontFamily:'Malayalam Sangam MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Malayalam', sans-serif;\n\n --RS__lo-baseFontFamily:'Lao Sangam MN', 'Leelawadee UI', 'Lao UI', Roboto, Noto, 'Noto Sans Lao', sans-serif;\n\n --RS__ko-lineHeightCompensation:1.167;\n\n --RS__ko-baseFontFamily:'Nanum Gothic', 'Apple SD Gothic Neo', 'Malgun Gothic', Roboto, Noto, 'Noto Sans CJK KR', sans-serif;\n\n --RS__kn-lineHeightCompensation:1.1;\n\n --RS__kn-baseFontFamily:'Kannada Sangam MN', 'Nirmala UI', Tunga, Roboto, Noto, 'Noto Sans Kannada', sans-serif;\n\n --RS__km-lineHeightCompensation:1.067;\n\n --RS__km-baseFontFamily:'Khmer Sangam MN', 'Leelawadee UI', 'Khmer UI', Roboto, Noto, 'Noto Sans Khmer', sans-serif;\n\n --RS__ja-lineHeightCompensation:1.167;\n\n --RS__ja-baseFontFamily:YuGothic, 'Hiragino Maru Gothic ProN', 'Hiragino Sans', 'Yu Gothic UI', 'Meiryo UI', 'MS Gothic', Roboto, Noto, 'Noto Sans CJK JP', sans-serif;\n\n --RS__iu-baseFontFamily:'Euphemia UCAS', Euphemia, Roboto, Noto, 'Noto Sans Canadian Aboriginal', sans-serif;\n\n --RS__hy-baseFontFamily:Mshtakan, Sylfaen, Roboto, Noto, 'Noto Serif Armenian', serif;\n\n --RS__hi-lineHeightCompensation:1.1;\n\n --RS__hi-baseFontFamily:'Kohinoor Devanagari', 'Devanagari Sangam MN', Kokila, 'Nirmala UI', Roboto, Noto, 'Noto Sans Devanagari', sans-serif;\n\n --RS__he-lineHeightCompensation:1.1;\n\n --RS__he-baseFontFamily:'New Peninim MT', 'Arial Hebrew', Gisha, 'Times New Roman', Roboto, Noto, 'Noto Sans Hebrew', sans-serif;\n\n --RS__gu-lineHeightCompensation:1.167;\n\n --RS__gu-baseFontFamily:'Gujarati Sangam MN', 'Nirmala UI', Shruti, Roboto, Noto, 'Noto Sans Gujarati', sans-serif;\n\n --RS__fa-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__chr-lineHeightCompensation:1.167;\n\n --RS__chr-baseFontFamily:'Plantagenet Cherokee', Roboto, Noto, 'Noto Sans Cherokee';\n\n --RS__bo-baseFontFamily:Kailasa, 'Microsoft Himalaya', Roboto, Noto, 'Noto Sans Tibetan', sans-serif;\n\n --RS__bn-lineHeightCompensation:1.067;\n\n --RS__bn-baseFontFamily:'Kohinoor Bangla', 'Bangla Sangam MN', Vrinda, Roboto, Noto, 'Noto Sans Bengali', sans-serif;\n\n --RS__ar-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__am-lineHeightCompensation:1.167;\n\n --RS__am-baseFontFamily:Kefa, Nyala, Roboto, Noto, 'Noto Sans Ethiopic', serif;\n\n --RS__latin-lineHeightCompensation:1;\n\n --RS__latin-baseFontFamily:var(--RS__oldStyleTf);\n --RS__baseFontFamily:var(--RS__latin-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__latin-lineHeightCompensation);\n --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation));\n\n --RS__selectionTextColor:inherit;\n\n --RS__selectionBackgroundColor:#b4d8fe;\n\n --RS__visitedColor:#551A8B;\n\n --RS__linkColor:#0000EE;\n\n --RS__textColor:#121212;\n\n --RS__backgroundColor:#FFFFFF;\n color:var(--RS__textColor) !important;\n\n background-color:var(--RS__backgroundColor) !important;\n}\n\n::-moz-selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\n::selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\nhtml{\n font-family:var(--RS__baseFontFamily);\n line-height:1.6;\n line-height:var(--RS__baseLineHeight);\n text-rendering:optimizelegibility;\n}\n\nh1, h2, h3{\n line-height:normal;\n}\n\n:lang(ja),\n:lang(zh),\n:lang(ko){\n word-wrap:break-word;\n -webkit-line-break:strict;\n -epub-line-break:strict;\n line-break:strict;\n}\n\nmath{\n font-family:\"Latin Modern Math\", \"STIX Two Math\", \"XITS Math\", \"STIX Math\", \"Libertinus Math\", \"TeX Gyre Termes Math\", \"TeX Gyre Bonum Math\", \"TeX Gyre Schola\", \"DejaVu Math TeX Gyre\", \"TeX Gyre Pagella Math\", \"Asana Math\", \"Cambria Math\", \"Lucida Bright Math\", \"Minion Math\", STIXGeneral, STIXSizeOneSym, Symbol, \"Times New Roman\", serif;\n}\n\n:lang(am){\n --RS__baseFontFamily:var(--RS__am-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__am-lineHeightCompensation);\n}\n\n:lang(ar){\n --RS__baseFontFamily:var(--RS__ar-baseFontFamily);\n}\n\n:lang(bn){\n --RS__baseFontFamily:var(--RS__bn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__bn-lineHeightCompensation);\n}\n\n:lang(bo){\n --RS__baseFontFamily:var(--RS__bo-baseFontFamily);\n}\n\n:lang(chr){\n --RS__baseFontFamily:var(--RS__chr-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__chr-lineHeightCompensation);\n}\n\n:lang(fa){\n --RS__baseFontFamily:var(--RS__fa-baseFontFamily);\n}\n\n:lang(gu){\n --RS__baseFontFamily:var(--RS__gu-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__gu-lineHeightCompensation);\n}\n\n:lang(he){\n --RS__baseFontFamily:var(--RS__he-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__he-lineHeightCompensation);\n}\n\n:lang(hi){\n --RS__baseFontFamily:var(--RS__hi-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__hi-lineHeightCompensation);\n}\n\n:lang(hy){\n --RS__baseFontFamily:var(--RS__hy-baseFontFamily);\n}\n\n:lang(iu){\n --RS__baseFontFamily:var(--RS__iu-baseFontFamily);\n}\n\n:lang(ja){\n --RS__baseFontFamily:var(--RS__ja-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ja-lineHeightCompensation);\n}\n\n:lang(km){\n --RS__baseFontFamily:var(--RS__km-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__km-lineHeightCompensation);\n}\n\n:lang(kn){\n --RS__baseFontFamily:var(--RS__kn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__kn-lineHeightCompensation);\n}\n\n:lang(ko){\n --RS__baseFontFamily:var(--RS__ko-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ko-lineHeightCompensation);\n}\n\n:lang(lo){\n --RS__baseFontFamily:var(--RS__lo-baseFontFamily);\n}\n\n:lang(ml){\n --RS__baseFontFamily:var(--RS__ml-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ml-lineHeightCompensation);\n}\n\n:lang(or){\n --RS__baseFontFamily:var(--RS__or-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__or-lineHeightCompensation);\n}\n\n:lang(pa){\n --RS__baseFontFamily:var(--RS__pa-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__pa-lineHeightCompensation);\n}\n\n:lang(si){\n --RS__baseFontFamily:var(--RS__si-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__si-lineHeightCompensation);\n}\n\n:lang(ta){\n --RS__baseFontFamily:var(--RS__ta-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ta-lineHeightCompensation);\n}\n\n:lang(te){\n --RS__baseFontFamily:var(--RS__te-baseFontFamily);\n}\n\n:lang(th){\n --RS__baseFontFamily:var(--RS__th-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__th-lineHeightCompensation);\n}\n\n:lang(zh){\n --RS__baseFontFamily:var(--RS__zh-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-lineHeightCompensation);\n}\n\n:lang(zh-Hant){\n --RS__baseFontFamily:var(--RS__zh-Hant-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-Hant-lineHeightCompensation);\n}\n\n:lang(zh-TW){\n --RS__baseFontFamily:var(--RS__zh-TW-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-TW-lineHeightCompensation);\n}\n\n:lang(zh-HK){\n --RS__baseFontFamily:var(--RS__zh-HK-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-HK-lineHeightCompensation);\n}\n\nbody{\n widows:2;\n orphans:2;\n}\n\nfigcaption, th, td{\n widows:1;\n orphans:1;\n}\n\nh2, h3, h4, h5, h6, dt,\nhr, caption{\n -webkit-column-break-after:avoid;\n page-break-after:avoid;\n break-after:avoid;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigure, tr{\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\nbody{\n -webkit-hyphenate-character:\"\\\\002D\";\n -moz-hyphenate-character:\"\\\\002D\";\n -ms-hyphenate-character:\"\\\\002D\";\n hyphenate-character:\"\\\\002D\";\n -webkit-hyphenate-limit-lines:3;\n -ms-hyphenate-limit-lines:3;\n hyphenate-limit-lines:3;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigcaption, pre, caption, address,\ncenter, code, var{\n -ms-hyphens:none;\n -moz-hyphens:none;\n -webkit-hyphens:none;\n -epub-hyphens:none;\n hyphens:none;\n}\n\nbody{\n font-variant-numeric:oldstyle-nums proportional-nums;\n}\n\n:lang(ja) body,\n:lang(zh) body,\n:lang(ko) body{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\nh1, h2, h3, h4, h5, h6, dt{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\ntable{\n font-variant-numeric:lining-nums tabular-nums;\n}\n\ncode, var{\n font-variant-ligatures:none;\n font-variant-numeric:lining-nums tabular-nums slashed-zero;\n}\n\nrt{\n font-variant-east-asian:ruby;\n}\n\n:lang(ar){\n font-variant-ligatures:common-ligatures;\n}\n\n:lang(ko){\n font-kerning:normal;\n}\n\nhr{\n color:inherit;\n border-color:currentcolor;\n}\n\ntable, th, td{\n border-color:currentcolor;\n}\n\nfigure, blockquote{\n margin:1em 5%;\n}\n\nul, ol{\n padding-left:5%;\n}\n\ndd{\n margin-left:5%;\n}\n\npre{\n white-space:pre-wrap;\n -ms-tab-size:2;\n -moz-tab-size:2;\n -webkit-tab-size:2;\n tab-size:2;\n}\n\nabbr[title], acronym[title]{\n text-decoration:dotted underline;\n}\n\nnobr wbr{\n white-space:normal;\n}\n\nruby > rt, ruby > rp{\n -webkit-user-select:none;\n -moz-user-select:none;\n -ms-user-select:none;\n user-select:none;\n}\n\n*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)),\n*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)),\n*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)),\n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i,\n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i,\n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{\n font-style:normal;\n}\n\n:lang(ja) a,\n:lang(zh) a,\n:lang(ko) a{\n text-decoration:none;\n}\n\n:root{\n --RS__maxMediaWidth:100%;\n --RS__maxMediaHeight:95vh;\n --RS__boxSizingMedia:border-box;\n --RS__boxSizingTable:border-box;\n}\n\na, a span, span a, h1, h2, h3, h4, h5, h6{\n word-wrap:break-word;\n}\n\ndiv{\n max-width:var(--RS__maxMediaWidth);\n}\n\nimg, svg|svg, video{\n object-fit:contain;\n\n width:auto;\n height:auto;\n max-width:var(--RS__maxMediaWidth);\n max-height:var(--RS__maxMediaHeight) !important;\n box-sizing:var(--RS__boxSizingMedia);\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\n@supports (zoom: 1) and (not ((-webkit-column-axis: horizontal) and (-webkit-column-progression: normal))){\n\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] img,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] svg|svg,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] video{\n zoom:calc(100% / var(--USER__fontSize));\n }\n}\n\naudio{\n max-width:100%;\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n }\n\ntable{\n max-width:var(--RS__maxMediaWidth);\n box-sizing:var(--RS__boxSizingTable);\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-before-CG-KmDa3.js?\n}")},"./node_modules/@readium/navigator/dist/ReadiumCSS-before-DwBLxUVH.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url(\"http://www.w3.org/1999/xhtml\");\n\n@namespace epub url(\"http://www.idpf.org/2007/ops\");\n\n@namespace m url(\"http://www.w3.org/1998/Math/MathML\");\n\n@namespace svg url(\"http://www.w3.org/2000/svg\");\n\n@-ms-viewport{\n width:device-width;\n}\n\n@viewport{\n width:device-width;\n zoom:1;\n}\n\n:root{\n\n --RS__sans-serif-ja-v:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDGothic', 'Yu Gothic', 'MSゴシック', 'MS Gothic', sans-serif;\n\n --RS__serif-ja-v:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDMincho', 'Yu Mincho', 'MS明朝', 'MS Mincho', serif;\n\n --RS__sans-serif-ja:'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ W3', 'YuGothic', 'Yu Gothic Medium', 'BIZ UDPGothic', 'Yu Gothic', 'MS Pゴシック', 'MS PGothic', sans-serif;\n\n --RS__serif-ja:'Hiragino Mincho ProN', 'Hiragino Mincho Pro', 'YuMincho', 'BIZ UDPMincho', 'Yu Mincho', 'MS P明朝', 'MS PMincho', serif;\n\n --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n\n --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif;\n\n --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif;\n\n --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif;\n\n --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif;\n\n --RS__zh-HK-lineHeightCompensation:1.167;\n\n --RS__zh-HK-baseFontFamily:'方體', 'PingFang HK', '方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-TW-lineHeightCompensation:1.167;\n\n --RS__zh-TW-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-Hant-lineHeightCompensation:1.167;\n\n --RS__zh-Hant-baseFontFamily:'方體', 'PingFang TC', '黑體', 'Heiti TC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK TC', sans-serif;\n\n --RS__zh-lineHeightCompensation:1.167;\n\n --RS__zh-baseFontFamily:'方体', 'PingFang SC', '黑体', 'Heiti SC', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Roboto, Noto, 'Noto Sans CJK SC', sans-serif;\n\n --RS__th-lineHeightCompensation:1.067;\n\n --RS__th-baseFontFamily:Thonburi, 'Leelawadee UI', 'Cordia New', Roboto, Noto, 'Noto Sans Thai', sans-serif;\n\n --RS__te-baseFontFamily:'Kohinoor Telugu', 'Telugu Sangam MN', 'Nirmala UI', Gautami, Roboto, Noto, 'Noto Sans Telugu', sans-serif;\n\n --RS__ta-lineHeightCompensation:1.067;\n\n --RS__ta-baseFontFamily:'Tamil Sangam MN', 'Nirmala UI', Latha, Roboto, Noto, 'Noto Sans Tamil', sans-serif;\n\n --RS__si-lineHeightCompensation:1.167;\n\n --RS__si-baseFontFamily:'Sinhala Sangam MN', 'Nirmala UI', 'Iskoola Pota', Roboto, Noto, 'Noto Sans Sinhala', sans-serif;\n\n --RS__pa-lineHeightCompensation:1.1;\n\n --RS__pa-baseFontFamily:'Gurmukhi MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Gurmukhi', sans-serif;\n\n --RS__or-lineHeightCompensation:1.167;\n\n --RS__or-baseFontFamily:'Oriya Sangam MN', 'Nirmala UI', Kalinga, Roboto, Noto, 'Noto Sans Oriya', sans-serif;\n\n --RS__ml-lineHeightCompensation:1.067;\n\n --RS__ml-baseFontFamily:'Malayalam Sangam MN', 'Nirmala UI', Kartika, Roboto, Noto, 'Noto Sans Malayalam', sans-serif;\n\n --RS__lo-baseFontFamily:'Lao Sangam MN', 'Leelawadee UI', 'Lao UI', Roboto, Noto, 'Noto Sans Lao', sans-serif;\n\n --RS__ko-lineHeightCompensation:1.167;\n\n --RS__ko-baseFontFamily:'Nanum Gothic', 'Apple SD Gothic Neo', 'Malgun Gothic', Roboto, Noto, 'Noto Sans CJK KR', sans-serif;\n\n --RS__kn-lineHeightCompensation:1.1;\n\n --RS__kn-baseFontFamily:'Kannada Sangam MN', 'Nirmala UI', Tunga, Roboto, Noto, 'Noto Sans Kannada', sans-serif;\n\n --RS__km-lineHeightCompensation:1.067;\n\n --RS__km-baseFontFamily:'Khmer Sangam MN', 'Leelawadee UI', 'Khmer UI', Roboto, Noto, 'Noto Sans Khmer', sans-serif;\n\n --RS__ja-lineHeightCompensation:1.167;\n\n --RS__ja-baseFontFamily:YuGothic, 'Hiragino Maru Gothic ProN', 'Hiragino Sans', 'Yu Gothic UI', 'Meiryo UI', 'MS Gothic', Roboto, Noto, 'Noto Sans CJK JP', sans-serif;\n\n --RS__iu-baseFontFamily:'Euphemia UCAS', Euphemia, Roboto, Noto, 'Noto Sans Canadian Aboriginal', sans-serif;\n\n --RS__hy-baseFontFamily:Mshtakan, Sylfaen, Roboto, Noto, 'Noto Serif Armenian', serif;\n\n --RS__hi-lineHeightCompensation:1.1;\n\n --RS__hi-baseFontFamily:'Kohinoor Devanagari', 'Devanagari Sangam MN', Kokila, 'Nirmala UI', Roboto, Noto, 'Noto Sans Devanagari', sans-serif;\n\n --RS__he-lineHeightCompensation:1.1;\n\n --RS__he-baseFontFamily:'New Peninim MT', 'Arial Hebrew', Gisha, 'Times New Roman', Roboto, Noto, 'Noto Sans Hebrew', sans-serif;\n\n --RS__gu-lineHeightCompensation:1.167;\n\n --RS__gu-baseFontFamily:'Gujarati Sangam MN', 'Nirmala UI', Shruti, Roboto, Noto, 'Noto Sans Gujarati', sans-serif;\n\n --RS__fa-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__chr-lineHeightCompensation:1.167;\n\n --RS__chr-baseFontFamily:'Plantagenet Cherokee', Roboto, Noto, 'Noto Sans Cherokee';\n\n --RS__bo-baseFontFamily:Kailasa, 'Microsoft Himalaya', Roboto, Noto, 'Noto Sans Tibetan', sans-serif;\n\n --RS__bn-lineHeightCompensation:1.067;\n\n --RS__bn-baseFontFamily:'Kohinoor Bangla', 'Bangla Sangam MN', Vrinda, Roboto, Noto, 'Noto Sans Bengali', sans-serif;\n\n --RS__ar-baseFontFamily:'Geeza Pro', 'Arabic Typesetting', Roboto, Noto, 'Noto Naskh Arabic', 'Times New Roman', serif;\n\n --RS__am-lineHeightCompensation:1.167;\n\n --RS__am-baseFontFamily:Kefa, Nyala, Roboto, Noto, 'Noto Sans Ethiopic', serif;\n\n --RS__latin-lineHeightCompensation:1;\n\n --RS__latin-baseFontFamily:var(--RS__oldStyleTf);\n --RS__baseFontFamily:var(--RS__latin-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__latin-lineHeightCompensation);\n --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation));\n\n --RS__selectionTextColor:inherit;\n\n --RS__selectionBackgroundColor:#b4d8fe;\n\n --RS__visitedColor:#551A8B;\n\n --RS__linkColor:#0000EE;\n\n --RS__textColor:#121212;\n\n --RS__backgroundColor:#FFFFFF;\n color:var(--RS__textColor) !important;\n\n background-color:var(--RS__backgroundColor) !important;\n}\n\n::-moz-selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\n::selection{\n color:var(--RS__selectionTextColor);\n background-color:var(--RS__selectionBackgroundColor);\n}\n\nhtml{\n font-family:var(--RS__baseFontFamily);\n line-height:1.6;\n line-height:var(--RS__baseLineHeight);\n text-rendering:optimizelegibility;\n}\n\nh1, h2, h3{\n line-height:normal;\n}\n\n:lang(ja),\n:lang(zh),\n:lang(ko){\n word-wrap:break-word;\n -webkit-line-break:strict;\n -epub-line-break:strict;\n line-break:strict;\n}\n\nmath{\n font-family:\"Latin Modern Math\", \"STIX Two Math\", \"XITS Math\", \"STIX Math\", \"Libertinus Math\", \"TeX Gyre Termes Math\", \"TeX Gyre Bonum Math\", \"TeX Gyre Schola\", \"DejaVu Math TeX Gyre\", \"TeX Gyre Pagella Math\", \"Asana Math\", \"Cambria Math\", \"Lucida Bright Math\", \"Minion Math\", STIXGeneral, STIXSizeOneSym, Symbol, \"Times New Roman\", serif;\n}\n\n:lang(am){\n --RS__baseFontFamily:var(--RS__am-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__am-lineHeightCompensation);\n}\n\n:lang(ar){\n --RS__baseFontFamily:var(--RS__ar-baseFontFamily);\n}\n\n:lang(bn){\n --RS__baseFontFamily:var(--RS__bn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__bn-lineHeightCompensation);\n}\n\n:lang(bo){\n --RS__baseFontFamily:var(--RS__bo-baseFontFamily);\n}\n\n:lang(chr){\n --RS__baseFontFamily:var(--RS__chr-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__chr-lineHeightCompensation);\n}\n\n:lang(fa){\n --RS__baseFontFamily:var(--RS__fa-baseFontFamily);\n}\n\n:lang(gu){\n --RS__baseFontFamily:var(--RS__gu-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__gu-lineHeightCompensation);\n}\n\n:lang(he){\n --RS__baseFontFamily:var(--RS__he-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__he-lineHeightCompensation);\n}\n\n:lang(hi){\n --RS__baseFontFamily:var(--RS__hi-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__hi-lineHeightCompensation);\n}\n\n:lang(hy){\n --RS__baseFontFamily:var(--RS__hy-baseFontFamily);\n}\n\n:lang(iu){\n --RS__baseFontFamily:var(--RS__iu-baseFontFamily);\n}\n\n:lang(ja){\n --RS__baseFontFamily:var(--RS__ja-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ja-lineHeightCompensation);\n}\n\n:lang(km){\n --RS__baseFontFamily:var(--RS__km-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__km-lineHeightCompensation);\n}\n\n:lang(kn){\n --RS__baseFontFamily:var(--RS__kn-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__kn-lineHeightCompensation);\n}\n\n:lang(ko){\n --RS__baseFontFamily:var(--RS__ko-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ko-lineHeightCompensation);\n}\n\n:lang(lo){\n --RS__baseFontFamily:var(--RS__lo-baseFontFamily);\n}\n\n:lang(ml){\n --RS__baseFontFamily:var(--RS__ml-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ml-lineHeightCompensation);\n}\n\n:lang(or){\n --RS__baseFontFamily:var(--RS__or-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__or-lineHeightCompensation);\n}\n\n:lang(pa){\n --RS__baseFontFamily:var(--RS__pa-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__pa-lineHeightCompensation);\n}\n\n:lang(si){\n --RS__baseFontFamily:var(--RS__si-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__si-lineHeightCompensation);\n}\n\n:lang(ta){\n --RS__baseFontFamily:var(--RS__ta-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__ta-lineHeightCompensation);\n}\n\n:lang(te){\n --RS__baseFontFamily:var(--RS__te-baseFontFamily);\n}\n\n:lang(th){\n --RS__baseFontFamily:var(--RS__th-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__th-lineHeightCompensation);\n}\n\n:lang(zh){\n --RS__baseFontFamily:var(--RS__zh-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-lineHeightCompensation);\n}\n\n:lang(zh-Hant){\n --RS__baseFontFamily:var(--RS__zh-Hant-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-Hant-lineHeightCompensation);\n}\n\n:lang(zh-TW){\n --RS__baseFontFamily:var(--RS__zh-TW-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-TW-lineHeightCompensation);\n}\n\n:lang(zh-HK){\n --RS__baseFontFamily:var(--RS__zh-HK-baseFontFamily);\n --RS__lineHeightCompensation:var(--RS__zh-HK-lineHeightCompensation);\n}\n\nbody{\n widows:2;\n orphans:2;\n}\n\nfigcaption, th, td{\n widows:1;\n orphans:1;\n}\n\nh2, h3, h4, h5, h6, dt,\nhr, caption{\n -webkit-column-break-after:avoid;\n page-break-after:avoid;\n break-after:avoid;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigure, tr{\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\nbody{\n -webkit-hyphenate-character:\"\\\\002D\";\n -moz-hyphenate-character:\"\\\\002D\";\n -ms-hyphenate-character:\"\\\\002D\";\n hyphenate-character:\"\\\\002D\";\n -webkit-hyphenate-limit-lines:3;\n -ms-hyphenate-limit-lines:3;\n hyphenate-limit-lines:3;\n}\n\nh1, h2, h3, h4, h5, h6, dt,\nfigcaption, pre, caption, address,\ncenter, code, var{\n -ms-hyphens:none;\n -moz-hyphens:none;\n -webkit-hyphens:none;\n -epub-hyphens:none;\n hyphens:none;\n}\n\nbody{\n font-variant-numeric:oldstyle-nums proportional-nums;\n}\n\n:lang(ja) body,\n:lang(zh) body,\n:lang(ko) body{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\nh1, h2, h3, h4, h5, h6, dt{\n font-variant-numeric:lining-nums proportional-nums;\n}\n\ntable{\n font-variant-numeric:lining-nums tabular-nums;\n}\n\ncode, var{\n font-variant-ligatures:none;\n font-variant-numeric:lining-nums tabular-nums slashed-zero;\n}\n\nrt{\n font-variant-east-asian:ruby;\n}\n\n:lang(ar){\n font-variant-ligatures:common-ligatures;\n}\n\n:lang(ko){\n font-kerning:normal;\n}\n\nhr{\n color:inherit;\n border-color:currentcolor;\n}\n\ntable, th, td{\n border-color:currentcolor;\n}\n\nfigure, blockquote{\n margin:1em 5%;\n}\n\nul, ol{\n padding-left:5%;\n}\n\ndd{\n margin-left:5%;\n}\n\npre{\n white-space:pre-wrap;\n -ms-tab-size:2;\n -moz-tab-size:2;\n -webkit-tab-size:2;\n tab-size:2;\n}\n\nabbr[title], acronym[title]{\n text-decoration:dotted underline;\n}\n\nnobr wbr{\n white-space:normal;\n}\n\nruby > rt, ruby > rp{\n -webkit-user-select:none;\n -moz-user-select:none;\n -ms-user-select:none;\n user-select:none;\n}\n\n*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)),\n*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)),\n*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)),\n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, \n:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i,\n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, \n:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i,\n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, \n:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{\n font-style:normal;\n}\n\n:lang(ja) a,\n:lang(zh) a,\n:lang(ko) a{\n text-decoration:none;\n}\n\n:root{\n --RS__maxMediaWidth:100%;\n --RS__maxMediaHeight:95vh;\n --RS__boxSizingMedia:border-box;\n --RS__boxSizingTable:border-box;\n}\n\na, a span, span a, h1, h2, h3, h4, h5, h6{\n word-wrap:break-word;\n}\n\ndiv{\n max-width:var(--RS__maxMediaWidth);\n}\n\nimg, svg|svg, video{\n object-fit:contain;\n\n width:auto;\n height:auto;\n max-width:var(--RS__maxMediaWidth);\n max-height:var(--RS__maxMediaHeight) !important;\n box-sizing:var(--RS__boxSizingMedia);\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n}\n\n@supports (zoom: 1) and (not ((-webkit-column-axis: horizontal) and (-webkit-column-progression: normal))){\n\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] img,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] svg|svg,\n :root[style*=\"readium-experimentalZoom-on\"]:not([style*=\"readium-deprecatedFontSize-on\"]):not([style*=\"readium-iOSPatch-on\"])[style*=\"--USER__fontSize\"] video{\n zoom:calc(100% / var(--USER__fontSize));\n }\n}\n\naudio{\n max-width:100%;\n -webkit-column-break-inside:avoid;\n page-break-inside:avoid;\n break-inside:avoid;\n }\n\ntable{\n max-width:var(--RS__maxMediaWidth);\n box-sizing:var(--RS__boxSizingTable);\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-before-DwBLxUVH.js?\n}")},"./node_modules/@readium/navigator/dist/ReadiumCSS-default-AIAk8uwU.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n --RS__compFontFamily:var(--RS__baseFontFamily);\n --RS__codeFontFamily:var(--RS__monospaceTf);\n\n --RS__typeScale:1.125;\n --RS__baseFontSize:100%;\n\n --RS__flowSpacing:1.5rem;\n --RS__paraSpacing:0;\n --RS__paraIndent:1em;\n\n --RS__linkColor:#0000EE;\n --RS__visitedColor:#551A8B;\n\n --RS__primaryColor:;\n --RS__secondaryColor:;\n}\n\nbody{\n font-size:var(--RS__baseFontSize);\n}\n\nh1, h2, h3, h4, h5, h6{\n font-family:var(--RS__compFontFamily);\n}\n\nblockquote, figure, p, pre,\naside, footer, form, hr{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\np{\n margin-top:var(--RS__paraSpacing);\n margin-bottom:var(--RS__paraSpacing);\n text-indent:var(--RS__paraIndent);\n}\n\nh1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p,\nhr + p{\n text-indent:0;\n}\n\npre{\n font-family:var(--RS__codeFontFamily);\n}\n\ncode, kbd, samp, tt{\n font-family:var(--RS__codeFontFamily);\n}\n\nsub, sup{\n position:relative;\n font-size:67.5%;\n line-height:1;\n}\n\nsub{\n bottom:-0.2ex;\n}\n\nsup{\n bottom:0;\n}\n\n:link{\n color:var(--RS__linkColor);\n}\n\n:visited{\n color:var(--RS__visitedColor);\n}\n\nh1{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:calc(var(--RS__flowSpacing) * 2);\n font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));\n}\n\nh2{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));\n}\n\nh3{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc(1em * var(--RS__typeScale));\n}\n\nh4{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:1em;\n}\n\nh5{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:1em;\n font-variant:small-caps;\n}\n\nh6{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:0;\n font-size:1em;\n text-transform:lowercase;\n font-variant:small-caps;\n}\n\ndl, ol, ul{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\ntable{\n margin:var(--RS__flowSpacing) 0;\n border:1px solid currentcolor;\n border-collapse:collapse;\n empty-cells:show;\n}\n\nthead, tbody, tfoot, table > tr{\n vertical-align:top;\n}\n\nth{\n text-align:left;\n}\n\nth, td{\n padding:4px;\n border:1px solid currentcolor;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-default-AIAk8uwU.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-default-BesyZHRU.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__compFontFamily:var(--RS__baseFontFamily);\n --RS__codeFontFamily:var(--RS__monospaceTf);\n\n --RS__typeScale:1.125;\n --RS__baseFontSize:87.5%;\n\n --RS__flowSpacing:1.5rem;\n --RS__paraSpacing:0;\n --RS__paraIndent:1em;\n\n --RS__linkColor:#0000EE;\n --RS__visitedColor:#551A8B;\n\n --RS__primaryColor:;\n --RS__secondaryColor:;\n}\n\n:root:lang(zh){\n --RS__paraIndent:2em;\n}\n\n:lang("mn-Mong"){\n --RS__baseFontSize:100%;\n}\n\nbody{\n font-size:var(--RS__baseFontSize);\n text-align:justify;\n text-justify:inter-character;\n}\n\nh1, h2, h3, h4, h5, h6{\n font-family:var(--RS__baseFontFamily);\n text-align:left;\n text-align:start;\n}\n\nblockquote, figure, p, pre,\naside, footer, form, hr{\n margin-right:var(--RS__flowSpacing);\n margin-left:var(--RS__flowSpacing);\n}\n\np{\n margin-right:var(--RS__paraSpacing);\n margin-left:var(--RS__paraSpacing);\n text-indent:var(--RS__paraIndent);\n}\n\npre{\n font-family:var(--RS__codeFontFamily);\n}\n\ncode, kbd, samp, tt{\n font-family:var(--RS__codeFontFamily);\n}\n\nsub, sup{\n position:relative;\n font-size:67.5%;\n line-height:1;\n}\n\nsub{\n left:-0.2ex;\n}\n\nsup{\n right:0;\n}\n\nem{\n -webkit-text-emphasis:sesame;\n -epub-text-emphasis:sesame;\n text-emphasis:sesame;\n}\n\n:link{\n color:var(--RS__linkColor);\n}\n\n:visited{\n color:var(--RS__visitedColor);\n}\n\nh1{\n margin-right:calc(var(--RS__flowSpacing) * 2);\n margin-left:calc(var(--RS__flowSpacing) * 2);\n font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));\n text-indent:2rem;\n}\n\nh2{\n margin-right:calc(var(--RS__flowSpacing) * 2);\n margin-left:var(--RS__flowSpacing);\n font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));\n text-indent:3rem;\n}\n\nh3{\n margin-right:var(--RS__flowSpacing);\n margin-left:var(--RS__flowSpacing);\n font-size:calc(1em * var(--RS__typeScale));\n text-indent:4rem;\n}\n\nh4{\n margin-right:var(--RS__flowSpacing);\n margin-left:var(--RS__flowSpacing);\n font-family:var(--RS__compFontFamily);\n font-size:1em;\n text-indent:4rem;\n}\n\nh5{\n margin-right:var(--RS__flowSpacing);\n margin-left:var(--RS__flowSpacing);\n font-family:var(--RS__compFontFamily);\n font-size:smaller;\n text-indent:4rem;\n}\n\nh6{\n margin-right:var(--RS__flowSpacing);\n margin-left:0;\n font-family:var(--RS__compFontFamily);\n font-size:smaller;\n font-weight:normal;\n text-indent:4rem;\n}\n\ndl, ol, ul{\n margin-right:var(--RS__flowSpacing);\n margin-left:var(--RS__flowSpacing);\n}\n\ntable{\n margin:0 var(--RS__flowSpacing);\n border:1px solid currentcolor;\n border-collapse:collapse;\n empty-cells:show;\n}\n\nthead, tbody, tfoot, table > tr{\n vertical-align:top;\n}\n\nth{\n text-align:left;\n}\n\nth, td{\n padding:4px;\n border:1px solid currentcolor;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-default-BesyZHRU.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-default-BhdLiyWp.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n --RS__compFontFamily:var(--RS__baseFontFamily);\n --RS__codeFontFamily:var(--RS__monospaceTf);\n\n --RS__typeScale:1.125;\n --RS__baseFontSize:100%;\n\n --RS__flowSpacing:1.5rem;\n --RS__paraSpacing:0;\n --RS__paraIndent:1em;\n\n --RS__linkColor:#0000EE;\n --RS__visitedColor:#551A8B;\n\n --RS__primaryColor:;\n --RS__secondaryColor:;\n}\n\nbody{\n font-size:var(--RS__baseFontSize);\n text-align:justify;\n}\n\nh1, h2, h3, h4, h5, h6{\n font-family:var(--RS__compFontFamily);\n text-align:right;\n}\n\nblockquote, figure, p, pre,\naside, footer, form, hr{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\np{\n margin-top:var(--RS__paraSpacing);\n margin-bottom:var(--RS__paraSpacing);\n text-indent:var(--RS__paraIndent);\n}\n\nh1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p,\nhr + p{\n text-indent:0;\n}\n\npre{\n font-family:var(--RS__codeFontFamily);\n}\n\ncode, kbd, samp, tt{\n font-family:var(--RS__codeFontFamily);\n}\n\nsub, sup{\n position:relative;\n font-size:67.5%;\n line-height:1;\n}\n\nsub{\n bottom:-0.2ex;\n}\n\nsup{\n bottom:0;\n}\n\n:link{\n color:var(--RS__linkColor);\n}\n\n:visited{\n color:var(--RS__visitedColor);\n}\n\nh1{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:calc(var(--RS__flowSpacing) * 2);\n font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));\n}\n\nh2{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));\n}\n\nh3{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc(1em * var(--RS__typeScale));\n}\n\nh4{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:1em;\n}\n\nh5{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:smaller;\n}\n\nh6{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:0;\n font-size:smaller;\n font-weight:normal;\n}\n\ndl, ol, ul{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\ntable{\n margin:var(--RS__flowSpacing) 0;\n border:1px solid currentcolor;\n border-collapse:collapse;\n empty-cells:show;\n}\n\nthead, tbody, tfoot, table > tr{\n vertical-align:top;\n}\n\nth{\n text-align:initial;\n}\n\nth, td{\n padding:4px;\n border:1px solid currentcolor;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-default-BhdLiyWp.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-default-N65xNiIp.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ n)\n/* harmony export */ });\nconst n = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n@namespace url("http://www.w3.org/1999/xhtml");\n\n@namespace epub url("http://www.idpf.org/2007/ops");\n\n@namespace m url("http://www.w3.org/1998/Math/MathML");\n\n@namespace svg url("http://www.w3.org/2000/svg");\n\n:root{\n\n --RS__compFontFamily:var(--RS__baseFontFamily);\n --RS__codeFontFamily:var(--RS__monospaceTf);\n\n --RS__typeScale:1.125;\n --RS__baseFontSize:87.5%;\n\n --RS__flowSpacing:1.5rem;\n --RS__paraSpacing:0;\n --RS__paraIndent:1em;\n\n --RS__linkColor:#0000EE;\n --RS__visitedColor:#551A8B;\n\n --RS__primaryColor:;\n --RS__secondaryColor:;\n}\n\n:root:lang(zh){\n --RS__paraIndent:2em;\n}\n\n:root{\n quotes:"\\\\201c" "\\\\201d" "\\\\2018" "\\\\2019";\n}\n\nbody{\n font-size:var(--RS__baseFontSize);\n text-align:justify;\n text-justify:inter-character;\n}\n\nh1, h2, h3, h4, h5, h6{\n font-family:var(--RS__baseFontFamily);\n text-align:left;\n text-align:start;\n}\n\nblockquote, figure, p, pre,\naside, footer, form, hr{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\np{\n margin-top:var(--RS__paraSpacing);\n margin-bottom:var(--RS__paraSpacing);\n text-indent:var(--RS__paraIndent);\n}\n\npre{\n font-family:var(--RS__codeFontFamily);\n}\n\ncode, kbd, samp, tt{\n font-family:var(--RS__codeFontFamily);\n}\n\nsub, sup{\n position:relative;\n font-size:67.5%;\n line-height:1;\n}\n\nsub{\n bottom:-0.2ex;\n}\n\nsup{\n bottom:0;\n}\n\nem{\n -webkit-text-emphasis:dot;\n -epub-text-emphasis:dot;\n text-emphasis:dot;\n}\n\n:link{\n color:var(--RS__linkColor);\n}\n\n:visited{\n color:var(--RS__visitedColor);\n}\n\nh1{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:calc(var(--RS__flowSpacing) * 2);\n font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));\n text-align:center;\n}\n\nh2{\n margin-top:calc(var(--RS__flowSpacing) * 2);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));\n text-align:center;\n}\n\nh3{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-size:calc(1em * var(--RS__typeScale));\n text-align:center;\n}\n\nh4{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-family:var(--RS__compFontFamily);\n font-size:1em;\n}\n\nh5{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n font-family:var(--RS__compFontFamily);\n font-size:smaller;\n}\n\nh6{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:0;\n font-family:var(--RS__compFontFamily);\n font-size:smaller;\n font-weight:normal;\n}\n\ndl, ol, ul{\n margin-top:var(--RS__flowSpacing);\n margin-bottom:var(--RS__flowSpacing);\n}\n\ntable{\n margin:var(--RS__flowSpacing) 0;\n border:1px solid currentcolor;\n border-collapse:collapse;\n empty-cells:show;\n}\n\nthead, tbody, tfoot, table > tr{\n vertical-align:top;\n}\n\nth{\n text-align:left;\n}\n\nth, td{\n padding:4px;\n border:1px solid currentcolor;\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-default-N65xNiIp.js?\n}')},"./node_modules/@readium/navigator/dist/ReadiumCSS-ebpaj_fonts_patch-Dt2XliTg.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ o)\n/* harmony export */ });\nconst o = `/* Readium CSS\n EBPAJ Fonts Patch module\n\n A stylesheet improving EBPAJ @font-face declarations to cover all platforms\n\n Repo: https://github.com/readium/css */\n\n/* EBPAJ template only references fonts from MS Windows…\n so we must reference fonts from other platforms\n and override authors’ stylesheets.\n What we do there is keeping their default value and providing fallbacks.\n\n /!\\\\ /!\\\\ /!\\\\ /!\\\\ /!\\\\\n FYI, you might want to load this polyfill only if you find\n one of the following metadata items in the OPF package:\n - version 1:\n ebpaj-guide-1.0\n - version 1.1:\n 1.1\n*/\n\n/* \n Hiragino PostScript Font name lists:\n https://www.screen.co.jp/ga_product/sento/support/QA/ss_psname.html\n*/\n\n/* 横組み用 (horizontal writing) */\n\n@font-face {\n font-family: "serif-ja";\n src: local("MS P明朝"), /* for IE */\n local("MS PMincho"), /* MS P明朝 */\n local("HiraMinProN-W3"), local("Hiragino Mincho ProN"), /* ヒラギノ明朝 ProN W3 */\n local("HiraMinPro-W3"), local("Hiragino Mincho Pro"), /* ヒラギノ明朝 Pro W3 */\n local("YuMin-Medium"), local("YuMincho"), /* 游明朝体(macOS) */\n local("Yu Mincho"), /* 游明朝(Windows) */\n local("BIZ UDPMincho"); /* BIZ UDP明朝 */\n}\n\n@font-face {\n font-family: "sans-serif-ja";\n src: local("MS Pゴシック"), /* for IE */\n local("MS PGothic"), /* MS Pゴシック */\n local("HiraginoSans-W3"), local("Hiragino Sans"), /* ヒラギノ角ゴシック */\n local("HiraKakuProN-W3"), local("Hiragino Kaku Gothic ProN"), /* ヒラギノ角ゴ ProN W3 */\n local("HiraKakuPro-W3"), local("Hiragino Kaku Gothic Pro"), /* ヒラギノ角ゴ Pro W3 */\n local("ヒラギノ角ゴ W3"), /* for old Safari */\n local("HiraginoKaku-W3-90msp-RKSJ-H"), /* ヒラギノ角ゴ W3(TrueType) */\n local("YuGothic-Medium"), local("YuGothic"), /* 游ゴシック体(macOS) */\n local("Yu Gothic Medium"), local("Yu Gothic"), /* 游ゴシック(Windows) "Yu Gothic" is a fallback. */\n local("BIZ UDPGothic"); /* BIZ UDPゴシック */\n}\n\n/* 縦組み用 (vertical writing) */\n\n@font-face {\n font-family: "serif-ja-v";\n src: local("MS 明朝"), /* for IE */\n local("MS Mincho"), /* MS 明朝 */\n local("HiraMinProN-W3"), local("Hiragino Mincho ProN"), /* ヒラギノ明朝 ProN W3 */\n local("HiraMinPro-W3"), local("Hiragino Mincho Pro"), /* ヒラギノ明朝 Pro W3 */\n local("YuMin-Medium"), local("YuMincho"), /* 游明朝体(macOS) */\n local("Yu Mincho"), /* 游明朝(Windows) */\n local("BIZ UDMincho"); /* BIZ UD明朝 */\n}\n\n@font-face {\n font-family: "sans-serif-ja-v";\n src: local("MS ゴシック"), /* for IE */\n local("MS Gothic"), /* MS ゴシック */\n local("HiraginoSans-W3"), local("Hiragino Sans"), /* ヒラギノ角ゴシック */\n local("HiraKakuProN-W3"), local("Hiragino Kaku Gothic ProN"), /* ヒラギノ角ゴ ProN W3 */\n local("HiraKakuPro-W3"), local("Hiragino Kaku Gothic Pro"), /* ヒラギノ角ゴ Pro W3 */\n local("ヒラギノ角ゴ W3"), /* for old Safari */\n local("HiraKakuDS-W3-83pv-RKSJ-H"), /* ヒラギノ角ゴ W3(TrueType) */\n local("YuGothic-Medium"), local("YuGothic"), /* 游ゴシック体(macOS) */\n local("Yu Gothic Medium"), local("Yu Gothic"), /* 游ゴシック(Windows) "Yu Gothic" is a fallback. */\n local("BIZ UDGothic"); /* BIZ UDゴシック */\n}`;\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ReadiumCSS-ebpaj_fonts_patch-Dt2XliTg.js?\n}')},"./node_modules/@readium/navigator/dist/ar-DyHX_uy2.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ t),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "لا تتوفر أي معلومات", "publisher-contact": "لمزيد من المعلومات حول إمكانية الوصول إلى هذا المنتج، يُرجى التواصل مع الناشر: ", title: "ملخص إمكانية الوصول" }, "additional-accessibility-information": { aria: { compact: "أدوار ARIA مدرَجة", descriptive: "يتم تعزيز المحتوى باستخدام أدوار ARIA لتحسين التنظيم وتيسير التنقّل" }, "audio-descriptions": "الوصف الصوتي", braille: "برايل", "color-not-sole-means-of-conveying-information": "اللون ليس الوسيلة الوحيدة لنقل المعلومات", "dyslexia-readability": "سهولة القراءة لذوي عُسر القراءة", "full-ruby-annotations": "شروح روبي كاملة", "high-contrast-between-foreground-and-background-audio": "تباين عالٍ بين الصوت الرئيسي وصوت الخلفية", "high-contrast-between-text-and-background": "تباين عالٍ بين النص والخلفية", "large-print": "خط كبير", "page-breaks": { compact: "فواصل الصفحات متضمَّنة", descriptive: "فواصل الصفحات متضمَّنة من المصدر المطبوع الأصلي" }, "ruby-annotations": "بعض شروح الروبي", "sign-language": "لغة الإشارة", "tactile-graphics": { compact: "الرسوم اللمسية مدرجة", descriptive: "تم دمج الرسوم اللمسية لتيسير الوصول إلى العناصر البصرية للأشخاص المكفوفين" }, "tactile-objects": "مجسمات لمسية ثلاثية الأبعاد", "text-to-speech-hinting": "إرشادات تحويل النص إلى كلام (TTS)متوفرة", title: "معلومات إضافية عن إمكانية الوصول", "ultra-high-contrast-between-text-and-background": "تباين عالٍ جدًا بين النص والخلفية", "visible-page-numbering": "ترقيم صفحات مرئي", "without-background-sounds": "من دون أصوات في خلفية" }, conformance: { a: { compact: "هذا المنشور يفي بالمعايير الدنيا لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى A من معيار WCAG 2" }, aa: { compact: "هذا المنشور يفي بالمعايير المعتمدة لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى AA من معيار WCAG 2" }, aaa: { compact: "هذا المنشور يفوق المعايير المقبولة لإمكانية الوصول", descriptive: "يحتوي هذا المنشور على بيان مطابقة يفيد بأنه يفي بمعيار إمكانية الوصول في EPUB وبمستوى AAA من معيار WCAG 2" }, certifier: "تم اعتماد هذا المنشور من قبل ", "certifier-credentials": "بيانات اعتماد جهة التصديق ", details: { "certification-info": "تم اعتماد هذا المنشور في تاريخ ", "certifier-report": "لمزيد من المعلومات، يرجى الرجوع إلى تقرير جهة التصديق", claim: "يدّعي هذا المنشور أنه يستوفي", "epub-accessibility-1-0": "معيار إمكانية الوصول لـ EPUB إصدار 1.0", "epub-accessibility-1-1": "معيار إمكانية الوصول لـ EPUB إصدار 1.1", "level-a": "المستوى A", "level-aa": "المستوى AA", "level-aaa": "المستوى AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "مبادئ النفاذ إلى محتوى الويب (WCAG) 2.2" } }, "details-title": "معلومات تفصيلية عن مدى المطابقة", no: "لا تتوفر أي معلومات", title: "المطابقة", "unknown-standard": "لا يمكن التأكد من مدى مطابقة هذا المنشور للمعايير المقبولة لإمكانية الوصول" }, hazards: { flashing: { compact: "محتوى وامض", descriptive: "يحتوي هذا المنشور على محتوى وامض قد يسبب نوبات حساسة للضوء" }, "flashing-none": { compact: "لا توجد مخاطر وميض", descriptive: "لا يحتوي هذا المنشور على محتوى وامض قد يسبب نوبات حساسة للضوء" }, "flashing-unknown": { compact: "مخاطر الوميض غير معروفة", descriptive: "لم يُمكن التأكد من وجود محتوى وامض قد يسبب نوبات حساسية للضوء" }, motion: { compact: "محاكاة الحركة", descriptive: "يحتوي المنشور على محاكاة حركة قد تسبّب دوار الحركة" }, "motion-none": { compact: "لا توجد مخاطر محاكاة الحركة", descriptive: "لا يحتوي المنشور على محاكاة حركة قد تسبّب دوار الحركة" }, "motion-unknown": { compact: "مخاطر محاكاة الحركة غير معروفة", descriptive: "تعذّر تحديد ما إذا كانت هناك محاكاة للحركة قد تُسبب دوار الحركة" }, "no-metadata": "لا تتوفر أي معلومات", none: { compact: "لا توجد مخاطر", descriptive: "لا يحتوي المنشور على أي مخاطر" }, sound: { compact: "أصوات", descriptive: "يحتوي المنشور على أصوات قد تؤدي إلى مشاكل حساسية صوتية" }, "sound-none": { compact: "لا توجد مخاطر صوتية", descriptive: "لا يحتوي المنشور على أصوات قد تؤدي إلى مشاكل حساسية صوتية" }, "sound-unknown": { compact: "مخاطر الصوت غير معروفة", descriptive: "تعذّر تحديد ما إذا كانت هناك أصوات قد تُسبب مشكلات في الحساسية" }, title: "مخاطر", unknown: "وجود المخاطر غير معروف" }, "legal-considerations": { exempt: { compact: "يُعلن عن استثناء من متطلبات إمكانية الوصول من بعض السلطات القضائية", descriptive: "يُصرّح هذا المنشور بوجود استثناء من متطلبات إمكانية الوصول من بعض السلطات القضائية" }, "no-metadata": "لا تتوفر أي معلومات", title: "اعتبارات قانونية" }, navigation: { index: { compact: "كشاف", descriptive: "كشاف يحتوي على روابط إلى الإدخالات المشار إليها" }, "no-metadata": "لا تتوفر أي معلومات", "page-navigation": { compact: "الانتقال إلى صفحة", descriptive: "قائمة الصفحات للانتقال إلى صفحات من النسخة المطبوعة الأصلية" }, structural: { compact: "العناوين", descriptive: "عناصر مثل العناوين والجداول وغيرها للتنقل المنظّم" }, title: "التنقل", toc: { compact: "جدول المحتويات", descriptive: "جدول المحتويات لكل فصول النص عبر روابط" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "الصيغ الكيميائية بصيغة LaTeX", descriptive: "الصيغ الكيميائية بشكل ميسر (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "الصيغ الكيميائية بصيغة MathML", descriptive: "الصيغ الكيميائية بشكل ميسر (MathML)" }, "accessible-math-as-latex": { compact: "الرياضيات بصيغة LaTeX", descriptive: "الصيغ الرياضية بشكل ميسر (LaTeX)" }, "accessible-math-described": "تتوفر أوصاف نصية للصيغ الرياضية", "closed-captions": { compact: "تحتوي الفيديوهات على شروح مغلقة", descriptive: "الفيديوهات الموجودة في المنشورات تحتوي على شروح مغلقة" }, "extended-descriptions": "يتم وصف الصور الغنية بالمعلومات بأوصاف مفصّلة", "math-as-mathml": { compact: "الرياضيات بصيغة MathML", descriptive: "الصيغ الرياضية بشكل ميسر(MathML)" }, "open-captions": { compact: "تحتوي الفيديوهات على شروح مدمجة", descriptive: "الفيديوهات الموجودة في المنشورات تحتوي على شروح مدمجة" }, title: "محتوى غني", transcript: "يتوفر نص(نصوص)", unknown: "لا تتوفر أي معلومات" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "يحتوي على نص بديل", descriptive: "يحتوي على أوصاف نصية بديلة للصور" }, "no-metadata": "لا تتوفر معلومات عن القراءة غير البصرية", none: { compact: "غير قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "المحتوى غير قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية" }, "not-fully": { compact: "غير قابل للقراءة بالكامل بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "لن يكون كل المحتوى قابلًا للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية" }, readable: { compact: "قابل للقراءة بصوتٍ عالٍ أو بطريقة برايل الديناميكية", descriptive: "يمكن قراءة كل المحتوى بصوتٍ عالٍ أو بطريقة برايل الديناميكية" } }, "prerecorded-audio": { complementary: { compact: "مقاطع الصوت المسجّلة مسبقًا", descriptive: "مقاطع الصوت المسجّلة مسبقًا مدمجة في المحتوى" }, "no-metadata": "لا توجد معلومات عن الصوت المسجّل مسبقًا", only: { compact: "الصوت المسجّل مسبقًا فقط", descriptive: "كتاب صوتي بدون بديل نصي" }, synchronized: { compact: "صوت مسجّل مسبقًا متزامن مع النص", descriptive: "كل المحتوى متوفر كصوت مسجّل مسبقًا متزامن مع النص" } }, title: "طرق القراءة", "visual-adjustments": { modifiable: { compact: "يمكن تعديل المظهر", descriptive: "يمكن تعديل مظهر النص وتخطيط الصفحة وفقاً لإمكانات نظام القراءة (اسم الخط وحجمه، والمسافات بين الفقرات والجمل والكلمات والأحرف، بالإضافة إلى لون الخلفية والنص)" }, unknown: "لا توجد معلومات عن إمكانية تعديل المظهر", unmodifiable: { compact: "لا يمكن تعديل المظهر", descriptive: "لا يمكن تعديل مظهر النص وتخطيط الصفحات لأن تجربة القراءة قريبة من النسخة المطبوعة، ولكن تطبيقات القراءة ما زالت تتيح خيارات التكبير" } } } } }, altIdentifier_one: "رمز تعريفي بديل", altIdentifier_other: "رموز تعريفية بديلة", artist_one: "فنان", artist_other: "فنانون", author_one: "مؤلف", author_other: "مؤلفون", collection_one: "سلسلة تحريرية", collection_other: "سلاسل تحريرية", colorist_one: "ملوّن الألوان", colorist_other: "ملوّنو الألوان", contributor_one: "مساهم", contributor_other: "مساهمون", description: "وصف", duration: "مدة", editor_one: "محرر", editor_other: "محررون", identifier_one: "رمز تعريفي", identifier_other: "رموز تعريفية", illustrator_one: "رسًام", illustrator_other: "رسامون", imprint_one: "العلامة التجارية للنشر", imprint_other: "العلامات التجارية للنشر", inker_one: "مُحَبِّر", inker_other: "مُحَبِّرون", language_one: "اللغة", language_other: "اللغات", letterer_one: "خطّاط", letterer_other: "خطّاطون", modified: "تاريخ التعديل", narrator_one: "قارئ صوتي", narrator_other: "قرّاء صوتيون", numberOfPages: "عدد الصفحات في النسخة المطبوعة", penciler_one: "رسّام أولي", penciler_other: "رسّامون أوّليون", published: "تاريخ النشر", publisher_one: "ناشر", publisher_other: "ناشرون", series_one: "سلسلة", series_other: "سلاسل", subject_one: "موضوع", subject_other: "مواضيع", subtitle: "عنوان فرعي", title: "العنوان", translator_one: "مترجم", translator_other: "مترجمون" } }, t = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/ar-DyHX_uy2.js?\n}')},"./node_modules/@readium/navigator/dist/da-Dct0PS3E.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ i),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = { metadata: { accessibility: { "display-guide": { "accessibility-summary": { "no-metadata": "Ingen information tilgængelig", "publisher-contact": "For mere information om tilgængeligheden af denne bog, kontakt venligst udgiveren: ", title: "Tilgængeligheds-oversigt" }, "additional-accessibility-information": { aria: { compact: "Indeholder ARIA roller", descriptive: "Indhold forbedres med ARIA-roller for at optimere organisering og gøre navigation lettere" }, "audio-descriptions": "Lydbeskrivelser", braille: "Punktskrift (braille)", "color-not-sole-means-of-conveying-information": "Information gives ikke udelukkende via farver", "dyslexia-readability": "Læsbarhed for ordblinde", "full-ruby-annotations": \'Indeholder såkalde "ruby" notationer (til asiatiske sprog)\', "high-contrast-between-foreground-and-background-audio": "Høj kontrast imellem forgrunds- og baggrunds-lyd", "high-contrast-between-text-and-background": "Høj kontrast imellem tekst og baggrunden", "large-print": "Forstørret tekst", "page-breaks": { compact: "Indeholder sideskift", descriptive: "Indeholder sideskift fra den trykte version af bogen" }, "ruby-annotations": \'Nogle "ruby" annotationer (til asiatiske sprog)\', "sign-language": "Tegnsprog", "tactile-graphics": { compact: "Indeholder taktil grafik", descriptive: "Indeholder taktil grafik for at muliggøre adgang til visuel information for blinde" }, "tactile-objects": "Taktile 3D objekter", "text-to-speech-hinting": "Udtaleforbedringer til syntetisk tale", title: "Yderligere information om tilgængelighed", "ultra-high-contrast-between-text-and-background": "Ultra høj kontrast imellem tekst og baggrund", "visible-page-numbering": "Synlige sidenumre", "without-background-sounds": "Uden baggrundslyd" }, conformance: { a: { compact: "Denne bog overholder minimum-tilgængelighedskravene", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau A" }, aa: { compact: "Denne bog lever op til de accepterede tilgængelighedskrav", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau AA" }, aaa: { compact: "Denne bog mere end opfylder de accepterede tilgængelighedskrav", descriptive: "Denne bog en overensstemmelseserklæring om, at den opfylder EPUB Tilgængelighedskrav og WCAG 2 standarden på niveau AAA" }, certifier: "Denne bog blev certificeret af ", "certifier-credentials": "Certificeringsorganets legitimationsoplysninger er ", details: { "certification-info": "Bogen blev certificeret den ", "certifier-report": "Se certificeringsorganets rapport for mere information", claim: "Denne bog hævder at opfylde", "epub-accessibility-1-0": "EPUB Tilgængelighed 1.0", "epub-accessibility-1-1": "EPUB Tilgængelighed 1.1", "level-a": "Niveau A", "level-aa": "Niveau AA", "level-aaa": "Niveau AAA", "wcag-2-0": { compact: "WCAG 2.0", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.0" }, "wcag-2-1": { compact: "WCAG 2.1", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.1" }, "wcag-2-2": { compact: "WCAG 2.2", descriptive: "Retningslinjer for tilgængeligt webindhold (WCAG) 2.2" } }, "details-title": "Detaljeret overholdelses-information", no: "Ingen information tilgængelig", title: "Overholdelse", "unknown-standard": "Overholdelse af de accepterede tilgængelighedskrav kan ikke vurderes for denne bog" }, hazards: { flashing: { compact: "Blinkende indhold", descriptive: "Bogen indeholder blinkende indhold der kan forårsage epileptiske anfald" }, "flashing-none": { compact: "Ingen blinkende indhold", descriptive: "Bogen indeholder ikke noget blinkende indhold, der kunne forårsage epileptiske anfald" }, "flashing-unknown": { compact: "Ingen information om bogen har blinkende indhold", descriptive: "Det kunne ikke afgøres om bogen indeholder blinkende indhold der kan lede til epileptiske anfald" }, motion: { compact: "Simuleret bevægelse", descriptive: "Bogen indeholder simuleret bevægelse, der kan forårsage en følelse af køresyge" }, "motion-none": { compact: "Indeholder ikke simuleret bevægelse", descriptive: "Denne bog indeholder ikke noget indhold med simuleret bevægelse, der kunne lede til en følelse af køresyge" }, "motion-unknown": { compact: "Ingen information om simuleret bevægelse", descriptive: "Det kunne ikke vurderes om bogen indeholder simuleret bevægelse, der kan lede til en følelse af køresyge" }, "no-metadata": "Ingen information tilgængelig", none: { compact: "Ingen farer", descriptive: "Bogen indeholder ikke noget indhold der kategoriseres som farligt" }, sound: { compact: "Lyde", descriptive: "Bogen indeholder lyde der kan være ubehagelige hvis man er sensitiv overfor lyde" }, "sound-none": { compact: "Ingen ubehagelige lyde", descriptive: "Bogen indeholder ikke lyde der kunne opleves som ubehagelige hvis man er sensitiv overfor lyde" }, "sound-unknown": { compact: "Ingen information om ubehagelige lyde", descriptive: "Det kunne ikke afgøres om bogen indeholder ubehagelige lyde" }, title: "Farer", unknown: "Ingen information om farligt indhold" }, "legal-considerations": { exempt: { compact: "Gør krav på undtagelser fra tilgængelighedskrav", descriptive: "Denne bog gør krav på en tilgængelighedsundtagelse i en eller flere jurisdiktioner" }, "no-metadata": "Ingen information tilgængelig", title: "Juridiske overvejelser" }, navigation: { index: { compact: "Indholdsfortegnelse", descriptive: "Indholdsfortegnelse med links til referencer" }, "no-metadata": "Ingen information tilgængelig", "page-navigation": { compact: "Gå til side", descriptive: "Sideliste for at gå til sider fra den trykte kildeversion" }, structural: { compact: "Overskrifter", descriptive: "Elementer så som overskrifter og tabeller til struktureret navigation" }, title: "Navigation", toc: { compact: "Indholdsfortegnelse", descriptive: "Indholdsfortegnelse med links til alle kapitler" } }, "rich-content": { "accessible-chemistry-as-latex": { compact: "Kemiske formularer i LaTeX", descriptive: "Kemiske formularer i tilgængeligt format (LaTeX)" }, "accessible-chemistry-as-mathml": { compact: "Kemiske formularer i MathML notation", descriptive: "Kemiske formularer i tilgængeligt format (MathML)" }, "accessible-math-as-latex": { compact: "Matematik som LaTeX", descriptive: "Matematikformler i tilgængeligt format (LaTeX)" }, "accessible-math-described": "Tekstbeskrivelser til matematiske formler", "closed-captions": { compact: "Videoer har undertekster", descriptive: "Videoer der optræder i bogen har undertekster" }, "extended-descriptions": "Informationsrige billeder beskrives med udvidede beskrivelser", "math-as-mathml": { compact: "Matematik som MathML", descriptive: "Matematiske formler i tilgængeligt format (MathML)" }, "open-captions": { compact: "Videoer har indlejrede undertekster", descriptive: "Videoer der optræder i bogen har indlejrede undertekster" }, title: "Komplekst indhold", transcript: "Indeholder transskription(er)", unknown: "Ingen information tilgængelig" }, "ways-of-reading": { "nonvisual-reading": { "alt-text": { compact: "Har alternativ tekst", descriptive: "Har billedbeskrivelser" }, "no-metadata": "Ingen information omkring ikke-visuel læsning", none: { compact: "Ikke læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Dette indhold er ikke læsbart med oplæsning eller dynamisk punktskrift" }, "not-fully": { compact: "Ikke fuldt læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Alt indholdet er ikke fuldt læsbart med oplæsning eller dynamisk punktskrift" }, readable: { compact: "Læsbar med oplæsning eller dynamisk punktskrift", descriptive: "Alt indholdet er læsbart med oplæsning eller dynamisk punktskrift" } }, "prerecorded-audio": { complementary: { compact: "Indlæste lydklip", descriptive: "Indlæste lydklip er indlejret i indholdet" }, "no-metadata": "Ingen information om indlæst lyd", only: { compact: "Kun indlæst lyd", descriptive: "Lydbog uden tekst alternativer" }, synchronized: { compact: "Indlæst lyd med synkroniseret tekst", descriptive: "Alt indholdet er tilgængeligt med indlæst lyd og synkroniseret tekst" } }, title: "Læseformer", "visual-adjustments": { modifiable: { compact: "Udseende kan ændres", descriptive: "Udseende af tekst og sidelayout kan ændres, så vidt muligt i læsesystemet (skrifttype, skriftstørrelse, afstand mellem afsnit, sætninger, ord og bogstaver, samt farven på tekst og baggrund)" }, unknown: "Ingen information om mulighed for ændring af udseende", unmodifiable: { compact: "Udseende kan ikke ændres", descriptive: "Tekst og sidelayout kan ikke ændres, da læseoplevelsen afspejler den trykte version af materialet. Læsesystemet kan dog stadig give mulighed for zoom" } } } } }, altIdentifier_one: "alternativt ID", altIdentifier_other: "alternative ID\'er", artist_one: "kunstner", artist_other: "kunstnere", author_one: "forfatter", author_other: "forfattere", collection_one: "redaktionel samling", collection_other: "redaktionelle samlinger", colorist_one: "farvelægger", colorist_other: "farvelæggere", contributor_one: "bidragsyder", contributor_other: "bidragsydere", description: "beskrivelse", duration: "varighed", editor_one: "redaktør", editor_other: "redaktører", identifier_one: "ID", identifier_other: "ID\'er", illustrator_one: "illustrator", illustrator_other: "illustratorer", imprint_one: "trykkeri", imprint_other: "trykkerier", inker_one: "tegner", inker_other: "tegnere", language_one: "sprog", language_other: "sprog", letterer_one: "taleboble-forfatter", letterer_other: "taleboble-forfattere", modified: "rettet dato", narrator_one: "indlæser", narrator_other: "indlæsere", numberOfPages: "printbare sider", penciler_one: "tegneseriekunstner", penciler_other: "tegneseriekunstnere", published: "udgivelsesdato", publisher_one: "udgiver", publisher_other: "udgivere", series_one: "serie", series_other: "serier", subject_one: "emne", subject_other: "emner", subtitle: "undertitel", title: "titel", translator_one: "oversætter", translator_other: "oversættere" } }, i = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/da-Dct0PS3E.js?\n}')},"./node_modules/@readium/navigator/dist/fr-C5HEel98.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ i),\n/* harmony export */ publication: () => (/* binding */ e)\n/* harmony export */ });\nconst e = /* @__PURE__ */ JSON.parse(`{"format":{"audiobook":"Livre audio","audiobookJSON":"Manifeste de livre audio","cbz":"Bande dessinée","divina":"Bande dessinée Divina","divinaJSON":"Manifeste de bande dessinée Divina","epub":"EPUB","lcpa":"Livre audio protégé par LCP","lcpdf":"PDF protégé par LCP","lcpl":"Licence LCP","pdf":"PDF","rwp":"Publication web Readium","rwpm":"Manifeste de publication web Readium","zab":"Livre audio","zip":"Archive ZIP"},"kind":{"audiobook_many":"livres audio","audiobook_one":"livre audio","audiobook_other":"livres audio","book_many":"livres","book_one":"livre","book_other":"livres","comic_many":"bandes dessinées","comic_one":"bande dessinée","comic_other":"bandes dessinées","document_many":"documents","document_one":"document","document_other":"documents"},"metadata":{"accessibility":{"display-guide":{"accessibility-summary":{"no-metadata":"Aucune information disponible","publisher-contact":"Pour plus d\'information à propos de l\'accessibilité de cette publication, veuillez contacter l\'éditeur : ","title":"Informations d\'accessibilité supplémentaires fournies par l\'éditeur"},"additional-accessibility-information":{"aria":{"compact":"Information enrichie pour les technologies d\'assistances","descriptive":"La structure est enrichi de rôles ARIA afin d\'optimiser l\'organisation et de faciliter la navigation via les technologies d\'assistances"},"audio-descriptions":"Description audio","braille":"Braille","color-not-sole-means-of-conveying-information":"La couleur n\'est pas la seule manière de communiquer de l\'information","dyslexia-readability":"Lisibilité adapté aux publics dys","full-ruby-annotations":"Annotations complètes au format ruby (langues asiatiques)","high-contrast-between-foreground-and-background-audio":"Contraste sonore amélioré entre les différents plans","high-contrast-between-text-and-background":"Contraste élevé entre le texte et l\'arrière-plan","large-print":"Grands caractères","page-breaks":{"compact":"Pagination identique à l\'imprimé","descriptive":"Contient une pagination identique à la version imprimée"},"ruby-annotations":"Annotations partielles au format ruby (langues asiatiques)","sign-language":"Langue des signes","tactile-graphics":{"compact":"Graphiques tactiles","descriptive":"Des graphiques tactiles ont été intégrés pour faciliter l\'accès des personnes aveugles aux éléments visuels"},"tactile-objects":"Objets 3D ou tactiles","text-to-speech-hinting":"Prononciation améliorée pour la synthèse vocale","title":"Informations complémentaires sur l\'accessibilité","ultra-high-contrast-between-text-and-background":"Contraste très élevé entre le texte et l\'arrière-plan","visible-page-numbering":"Numérotation de page visible","without-background-sounds":"Aucun bruit de fond"},"conformance":{"a":{"compact":"Cette publication répond aux règles minimales d\'accessibilité","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau A"},"aa":{"compact":"Cette publication répond aux règles d\'accessibilité reconnues","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau AA"},"aaa":{"compact":"Cette publication dépasse les règles d\'accessibilité reconnues","descriptive":"La publication indique qu\'elle respecte les règles d\'accessibilité EPUB et WCAG 2 niveau AAA"},"certifier":"Accessibilité évaluée par ","certifier-credentials":"L\'évaluateur est accrédité par ","details":{"certification-info":"Cette publication a été certifié le","certifier-report":"Pour plus d\'information, veuillez consulter le rapport de certification","claim":"Cette publication indique respecter","epub-accessibility-1-0":"EPUB Accessibilité 1.0","epub-accessibility-1-1":"EPUB Accessibilité 1.1","level-a":"Niveau A","level-aa":"Niveau AA","level-aaa":"Niveau AAA","wcag-2-0":{"compact":"WCAG 2.0","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.0"},"wcag-2-1":{"compact":"WCAG 2.1","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.1"},"wcag-2-2":{"compact":"WCAG 2.2","descriptive":"Règles pour l’accessibilité des contenus Web (WCAG) 2.2"}},"details-title":"Information détaillée","no":"Aucune information disponible","title":"Règles d\'accessibilité","unknown-standard":"Aucune indication concernant les normes d\'accessibilité"},"hazards":{"flashing":{"compact":"Flashs lumineux","descriptive":"La publication contient des flashs lumineux qui peuvent provoquer des crises d’épilepsie"},"flashing-none":{"compact":"Pas de flashs lumineux","descriptive":"La publication ne contient pas de flashs lumineux susceptibles de provoquer des crises d’épilepsie"},"flashing-unknown":{"compact":"Pas d\'information concernant la présence de flashs lumineux","descriptive":"La présence de flashs lumineux susceptibles de provoquer des crises d’épilepsie n\'a pas pu être déterminée"},"motion":{"compact":"Sensations de mouvement","descriptive":"La publication contient des images en mouvement qui peuvent provoquer des nausées, des vertiges et des maux de tête"},"motion-none":{"compact":"Pas de sensations de mouvement","descriptive":"La publication ne contient pas d\'images en mouvement qui pourraient provoquer des nausées, des vertiges et des maux de tête"},"motion-unknown":{"compact":"Pas d\'information concernant la présence d\'images en mouvement","descriptive":"La présence d\'images en mouvement susceptibles de provoquer des nausées, des vertiges et des maux de tête n\'a pas pu être déterminée"},"no-metadata":"Aucune information disponible","none":{"compact":"Aucun points d\'attention","descriptive":"La publication ne présente aucun risque lié à la présence de flashs lumineux, de sensations de mouvement ou de sons"},"sound":{"compact":"Sons","descriptive":"La publication contient des sons qui peuvent causer des troubles de la sensibilité"},"sound-none":{"compact":"Pas de risques sonores","descriptive":"La publication ne contient pas de sons susceptibles de provoquer des troubles de la sensibilité"},"sound-unknown":{"compact":"Pas d\'information concernant la présence de sons","descriptive":"La présence de sons susceptibles de causer des troubles de sensibilité n\'a pas pu être déterminée"},"title":"Points d\'attention","unknown":"La présence de risques est inconnue"},"legal-considerations":{"exempt":{"compact":"Déclare être sous le coup d\'une exemption dans certaines juridictions","descriptive":"Cette publication dééclare être sous le coup d\'une exemption dans certaines juridictions"},"no-metadata":"Aucune information disponible","title":"Considérations légales"},"navigation":{"index":{"compact":"Index","descriptive":"Index comportant des liens vers les entrées référencées"},"no-metadata":"Aucune information disponible","page-navigation":{"compact":"Aller à la page","descriptive":"Permet d\'accéder aux pages de la version source imprimée"},"structural":{"compact":"Titres","descriptive":"Contient des titres pour une navigation structurée"},"title":"Points de repère","toc":{"compact":"Table des matières","descriptive":"Table des matières"}},"rich-content":{"accessible-chemistry-as-latex":{"compact":"Formules chimiques en LaTeX","descriptive":"Formules chimiques en format accessible (LaTeX)"},"accessible-chemistry-as-mathml":{"compact":"Formules chimiques en MathML","descriptive":"Formules chimiques en format accessible (MathML)"},"accessible-math-as-latex":{"compact":"Mathématiques en LaTeX","descriptive":"Formules mathématiques en format accessible (LaTeX)"},"accessible-math-described":"Des descriptions textuelles des formules mathématiques sont fournies","closed-captions":{"compact":"Sous-titres disponibles pour les vidéos","descriptive":"Des sous titres sont disponibles pour les vidéos"},"extended-descriptions":"Les images porteuses d\'informations complexes sont décrites par des descriptions longues","math-as-mathml":{"compact":"Mathématiques en MathML","descriptive":"Formules mathématiques en format accessible (MathML)"},"open-captions":{"compact":"Sous-titres incrustés","descriptive":"Des sous titres sont incrustés pour les vidéos"},"title":"Contenus spécifiques","transcript":"Transcriptions fournies","unknown":"Aucune information disponible"},"ways-of-reading":{"nonvisual-reading":{"alt-text":{"compact":"Images décrites","descriptive":"Les images sont décrites par un texte"},"no-metadata":"Aucune information pour la lecture en voix de synthèse ou en braille","none":{"compact":"Non lisible en voix de synthèse ou en braille","descriptive":"Le contenu n\'est pas lisible en voix de synthèse ou en braille"},"not-fully":{"compact":"Pas entièrement lisible en voix de synthèse ou en braille","descriptive":"Tous les contenus ne pourront pas être lus à haute voix ou en braille"},"readable":{"compact":"Entièrement lisible en voix de synthèse ou en braille","descriptive":"Tous les contenus peuvent être lus en voix de synthèse ou en braille"}},"prerecorded-audio":{"complementary":{"compact":"Clips audio préenregistrés","descriptive":"Des clips audio préenregistrés sont intégrés au contenu"},"no-metadata":"Aucune information sur les enregistrements audio","only":{"compact":"Audio préenregistré uniquement","descriptive":"Livre audio sans texte alternatif"},"synchronized":{"compact":"Audio préenregistré synchronisé avec du texte","descriptive":"Tous les contenus sont disponibles comme audio préenregistrés synchronisés avec le texte"}},"title":"Lisibilité","visual-adjustments":{"modifiable":{"compact":"L\'affichage peut être adapté","descriptive":"L\'apparence du texte et la mise en page peuvent être modifiées en fonction des capacités du système de lecture (famille et taille des polices, espaces entre les paragraphes, les phrases, les mots et les lettres, ainsi que la couleur de l\'arrière-plan et du texte)"},"unknown":"Aucune information sur les possibilités d\'adaptation de l\'affichage","unmodifiable":{"compact":"L\'affichage ne peut pas être adapté","descriptive":"Le texte et la mise en page ne peuvent pas être adaptés étant donné que l\'expérience de lecture est proche de celle de la version imprimée, mais l\'application de lecture peut tout de même proposer la capacité de zoomer"}}}}},"altIdentifier_many":"","altIdentifier_one":"identifiant alternatif","altIdentifier_other":"identifiants alternatifs","artist_many":"","artist_one":"artiste","artist_other":"artiste","author_many":"","author_one":"auteur","author_other":"auteurs","collection_many":"","collection_one":"collection éditoriale","collection_other":"collections éditoriales","colorist_many":"","colorist_one":"coloriste","colorist_other":"coloristes","contributor_many":"","contributor_one":"contributeur","contributor_other":"contributeurs","description":"description","duration":"durée","editor_many":"","editor_one":"éditeur","editor_other":"éditeurs","identifier_many":"","identifier_one":"identifiant","identifier_other":"identifiants","illustrator_many":"","illustrator_one":"illustrateur","illustrator_other":"illustrateurs","imprint_many":"","imprint_one":"marque éditoriale","imprint_other":"marques éditoriales","inker_many":"","inker_one":"encreur","inker_other":"encreurs","language_many":"","language_one":"langue","language_other":"langues","letterer_many":"","letterer_one":"lettreur","letterer_other":"lettreurs","modified":"date de modification","narrator_many":"","narrator_one":"narrateur","narrator_other":"narrateurs","numberOfPages":"pagination papier","penciler_many":"","penciler_one":"dessinateur","penciler_other":"dessinateurs","published":"date de publication","publisher_many":"","publisher_one":"éditeur","publisher_other":"éditeurs","series_many":"","series_one":"série","series_other":"séries","subject_many":"","subject_one":"catégorie","subject_other":"catégories","subtitle":"sous-titre","title":"titre","translator_many":"","translator_one":"traducteur","translator_other":"traducteurs"}}`), i = {\n publication: e\n};\n\n\n\n//# sourceURL=webpack:///./node_modules/@readium/navigator/dist/fr-C5HEel98.js?\n}')},"./node_modules/@readium/navigator/dist/index.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ AudioDefaults: () => (/* binding */ ao),\n/* harmony export */ AudioNavigator: () => (/* binding */ yo),\n/* harmony export */ AudioPreferences: () => (/* binding */ ce),\n/* harmony export */ AudioPreferencesEditor: () => (/* binding */ $i),\n/* harmony export */ AudioSettings: () => (/* binding */ ji),\n/* harmony export */ BooleanPreference: () => (/* binding */ A),\n/* harmony export */ EnumPreference: () => (/* binding */ yn),\n/* harmony export */ EpubDefaults: () => (/* binding */ Gr),\n/* harmony export */ EpubNavigator: () => (/* binding */ Ln),\n/* harmony export */ EpubPreferences: () => (/* binding */ Ft),\n/* harmony export */ EpubPreferencesEditor: () => (/* binding */ Bi),\n/* harmony export */ EpubSettings: () => (/* binding */ Vi),\n/* harmony export */ ExperimentalWebPubNavigator: () => (/* binding */ go),\n/* harmony export */ FXLCoordinator: () => (/* binding */ Ir),\n/* harmony export */ FXLFrameManager: () => (/* binding */ Nr),\n/* harmony export */ FXLFramePoolManager: () => (/* binding */ $r),\n/* harmony export */ FXLPeripherals: () => (/* binding */ Dr),\n/* harmony export */ FXLSpreader: () => (/* binding */ Wr),\n/* harmony export */ FrameComms: () => (/* binding */ Nt),\n/* harmony export */ FrameManager: () => (/* binding */ Cn),\n/* harmony export */ FramePoolManager: () => (/* binding */ Tr),\n/* harmony export */ HorizontalThird: () => (/* binding */ Mr),\n/* harmony export */ Injector: () => (/* binding */ Sn),\n/* harmony export */ LineLengths: () => (/* binding */ kt),\n/* harmony export */ MediaNavigator: () => (/* binding */ vs),\n/* harmony export */ Navigator: () => (/* binding */ cn),\n/* harmony export */ Orientation: () => (/* binding */ Ne),\n/* harmony export */ Preference: () => (/* binding */ N),\n/* harmony export */ Properties: () => (/* binding */ le),\n/* harmony export */ RSProperties: () => (/* binding */ to),\n/* harmony export */ RangePreference: () => (/* binding */ x),\n/* harmony export */ ReadiumCSS: () => (/* binding */ eo),\n/* harmony export */ Spread: () => (/* binding */ Me),\n/* harmony export */ TextAlignment: () => (/* binding */ tt),\n/* harmony export */ UserProperties: () => (/* binding */ _n),\n/* harmony export */ VerticalThird: () => (/* binding */ Fr),\n/* harmony export */ VisualNavigator: () => (/* binding */ dn),\n/* harmony export */ WebAudioEngine: () => (/* binding */ oo),\n/* harmony export */ WebPubBlobBuilder: () => (/* binding */ Ps),\n/* harmony export */ WebPubCSS: () => (/* binding */ cr),\n/* harmony export */ WebPubDefaults: () => (/* binding */ pr),\n/* harmony export */ WebPubFrameManager: () => (/* binding */ ks),\n/* harmony export */ WebPubFramePoolManager: () => (/* binding */ Os),\n/* harmony export */ WebPubNavigator: () => (/* binding */ Rr),\n/* harmony export */ WebPubPreferences: () => (/* binding */ Mt),\n/* harmony export */ WebPubPreferencesEditor: () => (/* binding */ Ti),\n/* harmony export */ WebPubSettings: () => (/* binding */ Ai),\n/* harmony export */ WebRSProperties: () => (/* binding */ hr),\n/* harmony export */ WebUserProperties: () => (/* binding */ mn),\n/* harmony export */ ensureBoolean: () => (/* binding */ E),\n/* harmony export */ ensureEnumValue: () => (/* binding */ he),\n/* harmony export */ ensureExperiment: () => (/* binding */ gn),\n/* harmony export */ ensureFilter: () => (/* binding */ wt),\n/* harmony export */ ensureLessThanOrEqual: () => (/* binding */ dr),\n/* harmony export */ ensureMoreThanOrEqual: () => (/* binding */ ur),\n/* harmony export */ ensureNonNegative: () => (/* binding */ S),\n/* harmony export */ ensureString: () => (/* binding */ W),\n/* harmony export */ ensureValueInRange: () => (/* binding */ F),\n/* harmony export */ experiments: () => (/* binding */ Ge),\n/* harmony export */ filterRangeConfig: () => (/* binding */ dt),\n/* harmony export */ fontSizeRangeConfig: () => (/* binding */ Yt),\n/* harmony export */ fontWeightRangeConfig: () => (/* binding */ st),\n/* harmony export */ fontWidthRangeConfig: () => (/* binding */ qt),\n/* harmony export */ getScriptMode: () => (/* binding */ bt),\n/* harmony export */ i18n: () => (/* binding */ mo),\n/* harmony export */ letterSpacingRangeConfig: () => (/* binding */ Kt),\n/* harmony export */ lineHeightRangeConfig: () => (/* binding */ Jt),\n/* harmony export */ lineLengthRangeConfig: () => (/* binding */ ut),\n/* harmony export */ paragraphIndentRangeConfig: () => (/* binding */ Zt),\n/* harmony export */ paragraphSpacingRangeConfig: () => (/* binding */ Qt),\n/* harmony export */ playbackRateRangeConfig: () => (/* binding */ ne),\n/* harmony export */ sML: () => (/* binding */ J),\n/* harmony export */ sMLWithRequest: () => (/* binding */ T),\n/* harmony export */ settings: () => (/* binding */ fo),\n/* harmony export */ skipIntervalRangeConfig: () => (/* binding */ it),\n/* harmony export */ volumeRangeConfig: () => (/* binding */ ie),\n/* harmony export */ withFallback: () => (/* binding */ ge),\n/* harmony export */ wordSpacingRangeConfig: () => (/* binding */ te),\n/* harmony export */ zoomRangeConfig: () => (/* binding */ ee)\n/* harmony export */ });\nconst v = class v {\n constructor(t) {\n this.uri = t;\n }\n /**\n * Parses an [AccessibilityProfile] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new v(t);\n }\n /**\n * Serializes an [AccessibilityProfile] to its RWPM JSON representation.\n */\n serialize() {\n return this.uri;\n }\n /**\n * Returns true if the profile is a WCAG Level A profile.\n */\n get isWCAGLevelA() {\n return this === v.EPUB_A11Y_10_WCAG_20_A || this === v.EPUB_A11Y_11_WCAG_20_A || this === v.EPUB_A11Y_11_WCAG_21_A || this === v.EPUB_A11Y_11_WCAG_22_A;\n }\n /**\n * Returns true if the profile is a WCAG Level AA profile.\n */\n get isWCAGLevelAA() {\n return this === v.EPUB_A11Y_10_WCAG_20_AA || this === v.EPUB_A11Y_11_WCAG_20_AA || this === v.EPUB_A11Y_11_WCAG_21_AA || this === v.EPUB_A11Y_11_WCAG_22_AA;\n }\n /**\n * Returns true if the profile is a WCAG Level AAA profile.\n */\n get isWCAGLevelAAA() {\n return this === v.EPUB_A11Y_10_WCAG_20_AAA || this === v.EPUB_A11Y_11_WCAG_20_AAA || this === v.EPUB_A11Y_11_WCAG_21_AAA || this === v.EPUB_A11Y_11_WCAG_22_AAA;\n }\n};\nv.EPUB_A11Y_10_WCAG_20_A = new v("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-a"), v.EPUB_A11Y_10_WCAG_20_AA = new v("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-aa"), v.EPUB_A11Y_10_WCAG_20_AAA = new v("http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-aaa"), v.EPUB_A11Y_11_WCAG_20_A = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-a"), v.EPUB_A11Y_11_WCAG_20_AA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-aa"), v.EPUB_A11Y_11_WCAG_20_AAA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.0-aaa"), v.EPUB_A11Y_11_WCAG_21_A = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-a"), v.EPUB_A11Y_11_WCAG_21_AA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-aa"), v.EPUB_A11Y_11_WCAG_21_AAA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.1-aaa"), v.EPUB_A11Y_11_WCAG_22_A = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-a"), v.EPUB_A11Y_11_WCAG_22_AA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-aa"), v.EPUB_A11Y_11_WCAG_22_AAA = new v("https://www.w3.org/TR/epub-a11y-11#wcag-2.2-aaa");\nlet Qe = v;\nconst _ = class _ {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses an [AccessMode] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new _(t);\n }\n /**\n * Serializes an [AccessMode] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\n_.AUDITORY = new _("auditory"), _.CHART_ON_VISUAL = new _("chartOnVisual"), _.CHEM_ON_VISUAL = new _("chemOnVisual"), _.COLOR_DEPENDENT = new _("colorDependent"), _.DIAGRAM_ON_VISUAL = new _("diagramOnVisual"), _.MATH_ON_VISUAL = new _("mathOnVisual"), _.MUSIC_ON_VISUAL = new _("musicOnVisual"), _.TACTILE = new _("tactile"), _.TEXT_ON_VISUAL = new _("textOnVisual"), _.TEXTUAL = new _("textual"), _.VISUAL = new _("visual");\nlet ti = _;\nconst z = class z {\n constructor(t) {\n if (typeof t == "string") {\n if (!z.VALID_MODES.has(t.toLowerCase()))\n return;\n this.value = t.toLowerCase();\n } else {\n const e = t.filter(\n (i) => z.VALID_MODES.has(i.toLowerCase())\n );\n if (e.length === 0)\n return;\n this.value = Array.from(new Set(e));\n }\n }\n /**\n * Parses a [PrimaryAccessMode] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n if (typeof t == "string")\n return new z(t);\n if (!Array.isArray(t)) return;\n const e = t.filter((i) => i ? z.VALID_MODES.has(i.toLowerCase()) : !1);\n if (e.length !== 0)\n return new z(e);\n }\n /**\n * Serializes a [PrimaryAccessMode] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nz.VALID_MODES = /* @__PURE__ */ new Set(["auditory", "tactile", "textual", "visual"]), z.AUDITORY = new z("auditory"), z.TACTILE = new z("tactile"), z.TEXTUAL = new z("textual"), z.VISUAL = new z("visual");\nlet ei = z;\nconst y = class y {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses a [Feature] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new y(t);\n }\n /**\n * Serializes a [Feature] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\ny.NONE = new y("none"), y.ANNOTATIONS = new y("annotations"), y.ARIA = new y("ARIA"), y.INDEX = new y("index"), y.PAGE_BREAK_MARKERS = new y("pageBreakMarkers"), y.PAGE_NAVIGATION = new y("pageNavigation"), y.PRINT_PAGE_NUMBERS = new y("printPageNumbers"), y.READING_ORDER = new y("readingOrder"), y.STRUCTURAL_NAVIGATION = new y("structuralNavigation"), y.TABLE_OF_CONTENTS = new y("tableOfContents"), y.TAGGED_PDF = new y("taggedPDF"), y.ALTERNATIVE_TEXT = new y("alternativeText"), y.AUDIO_DESCRIPTION = new y("audioDescription"), y.CAPTIONS = new y("captions"), y.CLOSED_CAPTIONS = new y("closedCaptions"), y.DESCRIBED_MATH = new y("describedMath"), y.LONG_DESCRIPTION = new y("longDescription"), y.OPEN_CAPTIONS = new y("openCaptions"), y.SIGN_LANGUAGE = new y("signLanguage"), y.TRANSCRIPT = new y("transcript"), y.DISPLAY_TRANSFORMABILITY = new y("displayTransformability"), y.SYNCHRONIZED_AUDIO_TEXT = new y("synchronizedAudioText"), y.TIMING_CONTROL = new y("timingControl"), y.UNLOCKED = new y("unlocked"), y.CHEM_ML = new y("ChemML"), y.LATEX = new y("latex"), y.LATEX_CHEMISTRY = new y("latex-chemistry"), y.MATH_ML = new y("MathML"), y.MATH_ML_CHEMISTRY = new y("MathML-chemistry"), y.TTS_MARKUP = new y("ttsMarkup"), y.HIGH_CONTRAST_AUDIO = new y("highContrastAudio"), y.HIGH_CONTRAST_DISPLAY = new y("highContrastDisplay"), y.LARGE_PRINT = new y("largePrint"), y.BRAILLE = new y("braille"), y.TACTILE_GRAPHIC = new y("tactileGraphic"), y.TACTILE_OBJECT = new y("tactileObject"), y.FULL_RUBY_ANNOTATIONS = new y("fullRubyAnnotations"), y.HORIZONTAL_WRITING = new y("horizontalWriting"), y.RUBY_ANNOTATIONS = new y("rubyAnnotations"), y.VERTICAL_WRITING = new y("verticalWriting"), y.WITH_ADDITIONAL_WORD_SEGMENTATION = new y("withAdditionalWordSegmentation"), y.WITHOUT_ADDITIONAL_WORD_SEGMENTATION = new y("withoutAdditionalWordSegmentation");\nlet Ht = y;\nconst L = class L {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses a [Hazard] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new L(t);\n }\n /**\n * Serializes a [Hazard] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nL.FLASHING = new L("flashing"), L.NO_FLASHING_HAZARD = new L("noFlashingHazard"), L.UNKNOWN_FLASHING_HAZARD = new L("unknownFlashingHazard"), L.MOTION_SIMULATION = new L("motionSimulation"), L.NO_MOTION_SIMULATION_HAZARD = new L("noMotionSimulationHazard"), L.UNKNOWN_MOTION_SIMULATION_HAZARD = new L("unknownMotionSimulationHazard"), L.SOUND = new L("sound"), L.NO_SOUND_HAZARD = new L("noSoundHazard"), L.UNKNOWN_SOUND_HAZARD = new L("unknownSoundHazard"), L.UNKNOWN = new L("unknown"), L.NONE = new L("none");\nlet ii = L;\nconst k = class k {\n constructor(t) {\n this.value = t;\n }\n /**\n * Parses an [Exemption] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t != "string"))\n return new k(t);\n }\n /**\n * Serializes an [Exemption] to its RWPM JSON representation.\n */\n serialize() {\n return this.value;\n }\n};\nk.NONE = new k("none"), k.DOCUMENTED = new k("documented"), k.LEGAL = new k("legal"), k.TEMPORARY = new k("temporary"), k.TECHNICAL = new k("technical"), k.EAA_DISPROPORTIONATE_BURDEN = new k("eaa-disproportionate-burden"), k.EAA_FUNDAMENTAL_ALTERATION = new k("eaa-fundamental-alteration"), k.EAA_MICROENTERPRISE = new k("eaa-microenterprise"), k.EAA_TECHNICAL_IMPOSSIBILITY = new k("eaa-technical-impossibility"), k.EAA_TEMPORARY = new k("eaa-temporary");\nlet ni = k;\nconst si = ["en", "ar", "da", "fr", "it", "pt_PT", "sv"], kn = /* @__PURE__ */ JSON.parse(`{"format":{"audiobook":"Audiobook","audiobookJSON":"Audiobook Manifest","cbz":"Comic Book Archive","divina":"Divina Publication","divinaJSON":"Divina Publication Manifest","epub":"EPUB","lcpa":"LCP Protected Audiobook","lcpdf":"LCP Protected PDF","lcpl":"LCP License Document","pdf":"PDF","rwp":"Readium Web Publication","rwpm":"Readium Web Publication Manifest","zab":"Audiobook Archive","zip":"ZIP Archive"},"kind":{"audiobook_one":"audiobook","audiobook_other":"audiobooks","book_one":"book","book_other":"books","comic_one":"comic","comic_other":"comics","document_one":"document","document_other":"documents"},"metadata":{"accessibility":{"display-guide":{"accessibility-summary":{"no-metadata":"No information is available","publisher-contact":"For more information about the accessibility of this product, please contact the publisher: ","title":"Accessibility summary"},"additional-accessibility-information":{"aria":{"compact":"ARIA roles included","descriptive":"Content is enhanced with ARIA roles to optimize organization and facilitate navigation"},"audio-descriptions":"Audio descriptions","braille":"Braille","color-not-sole-means-of-conveying-information":"Color is not the sole means of conveying information","dyslexia-readability":"Dyslexia readability","full-ruby-annotations":"Full ruby annotations","high-contrast-between-foreground-and-background-audio":"High contrast between foreground and background audio","high-contrast-between-text-and-background":"High contrast between foreground text and background","large-print":"Large print","page-breaks":{"compact":"Page breaks included","descriptive":"Page breaks included from the original print source"},"ruby-annotations":"Some Ruby annotations","sign-language":"Sign language","tactile-graphics":{"compact":"Tactile graphics included","descriptive":"Tactile graphics have been integrated to facilitate access to visual elements for blind people"},"tactile-objects":"Tactile 3D objects","text-to-speech-hinting":"Text-to-speech hinting provided","title":"Additional accessibility information","ultra-high-contrast-between-text-and-background":"Ultra high contrast between text and background","visible-page-numbering":"Visible page numbering","without-background-sounds":"Without background sounds"},"conformance":{"a":{"compact":"This publication meets minimum accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level A standard"},"aa":{"compact":"This publication meets accepted accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level AA standard"},"aaa":{"compact":"This publication exceeds accepted accessibility standards","descriptive":"The publication contains a conformance statement that it meets the EPUB Accessibility and WCAG 2 Level AAA standard"},"certifier":"The publication was certified by ","certifier-credentials":"The certifier\'s credential is ","details":{"certification-info":"The publication was certified on ","certifier-report":"For more information refer to the certifier\'s report","claim":"This publication claims to meet","epub-accessibility-1-0":"EPUB Accessibility 1.0","epub-accessibility-1-1":"EPUB Accessibility 1.1","level-a":"Level A","level-aa":"Level AA","level-aaa":"Level AAA","wcag-2-0":{"compact":"WCAG 2.0","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.0"},"wcag-2-1":{"compact":"WCAG 2.1","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.1"},"wcag-2-2":{"compact":"WCAG 2.2","descriptive":"Web Content Accessibility Guidelines (WCAG) 2.2"}},"details-title":"Detailed conformance information","no":"No information is available","title":"Conformance","unknown-standard":"Conformance to accepted standards for accessibility of this publication cannot be determined"},"hazards":{"flashing":{"compact":"Flashing content","descriptive":"The publication contains flashing content that can cause photosensitive seizures"},"flashing-none":{"compact":"No flashing hazards","descriptive":"The publication does not contain flashing content that can cause photosensitive seizures"},"flashing-unknown":{"compact":"Flashing hazards not known","descriptive":"The presence of flashing content that can cause photosensitive seizures could not be determined"},"motion":{"compact":"Motion simulation","descriptive":"The publication contains motion simulations that can cause motion sickness"},"motion-none":{"compact":"No motion simulation hazards","descriptive":"The publication does not contain motion simulations that can cause motion sickness"},"motion-unknown":{"compact":"Motion simulation hazards not known","descriptive":"The presence of motion simulations that can cause motion sickness could not be determined"},"no-metadata":"No information is available","none":{"compact":"No hazards","descriptive":"The publication contains no hazards"},"sound":{"compact":"Sounds","descriptive":"The publication contains sounds that can cause sensitivity issues"},"sound-none":{"compact":"No sound hazards","descriptive":"The publication does not contain sounds that can cause sensitivity issues"},"sound-unknown":{"compact":"Sound hazards not known","descriptive":"The presence of sounds that can cause sensitivity issues could not be determined"},"title":"Hazards","unknown":"The presence of hazards is unknown"},"legal-considerations":{"exempt":{"compact":"Claims an accessibility exemption in some jurisdictions","descriptive":"This publication claims an accessibility exemption in some jurisdictions"},"no-metadata":"No information is available","title":"Legal considerations"},"navigation":{"index":{"compact":"Index","descriptive":"Index with links to referenced entries"},"no-metadata":"No information is available","page-navigation":{"compact":"Go to page","descriptive":"Page list to go to pages from the print source version"},"structural":{"compact":"Headings","descriptive":"Elements such as headings, tables, etc for structured navigation"},"title":"Navigation","toc":{"compact":"Table of contents","descriptive":"Table of contents to all chapters of the text via links"}},"rich-content":{"accessible-chemistry-as-latex":{"compact":"Chemical formulas in LaTeX","descriptive":"Chemical formulas in accessible format (LaTeX)"},"accessible-chemistry-as-mathml":{"compact":"Chemical formulas in MathML","descriptive":"Chemical formulas in accessible format (MathML)"},"accessible-math-as-latex":{"compact":"Math as LaTeX","descriptive":"Math formulas in accessible format (LaTeX)"},"accessible-math-described":"Text descriptions of math are provided","closed-captions":{"compact":"Videos have closed captions","descriptive":"Videos included in publications have closed captions"},"extended-descriptions":"Information-rich images are described by extended descriptions","math-as-mathml":{"compact":"Math as MathML","descriptive":"Math formulas in accessible format (MathML)"},"open-captions":{"compact":"Videos have open captions","descriptive":"Videos included in publications have open captions"},"title":"Rich content","transcript":"Transcript(s) provided","unknown":"No information is available"},"ways-of-reading":{"nonvisual-reading":{"alt-text":{"compact":"Has alternative text","descriptive":"Has alternative text descriptions for images"},"no-metadata":"No information about nonvisual reading is available","none":{"compact":"Not readable in read aloud or dynamic braille","descriptive":"The content is not readable as read aloud speech or dynamic braille"},"not-fully":{"compact":"Not fully readable in read aloud or dynamic braille","descriptive":"Not all of the content will be readable as read aloud speech or dynamic braille"},"readable":{"compact":"Readable in read aloud or dynamic braille","descriptive":"All content can be read as read aloud speech or dynamic braille"}},"prerecorded-audio":{"complementary":{"compact":"Prerecorded audio clips","descriptive":"Prerecorded audio clips are embedded in the content"},"no-metadata":"No information about prerecorded audio is available","only":{"compact":"Prerecorded audio only","descriptive":"Audiobook with no text alternative"},"synchronized":{"compact":"Prerecorded audio synchronized with text","descriptive":"All the content is available as prerecorded audio synchronized with text"}},"title":"Ways of reading","visual-adjustments":{"modifiable":{"compact":"Appearance can be modified","descriptive":"Appearance of the text and page layout can be modified according to the capabilities of the reading system (font family and font size, spaces between paragraphs, sentences, words, and letters, as well as color of background and text)"},"unknown":"No information about appearance modifiability is available","unmodifiable":{"compact":"Appearance cannot be modified","descriptive":"Text and page layout cannot be modified as the reading experience is close to a print version, but reading systems can still provide zooming options"}}}}},"altIdentifier_one":"alternate identifier","altIdentifier_other":"alternate identifiers","artist_one":"artist","artist_other":"artists","author_one":"author","author_other":"authors","collection_one":"editorial collection","collection_other":"editorial collections","colorist_one":"colorist","colorist_other":"colorists","contributor_one":"contributor","contributor_other":"contributors","description":"description","duration":"duration","editor_one":"editor","editor_other":"editors","identifier_one":"identifier","identifier_other":"identifiers","illustrator_one":"illustrator","illustrator_other":"illustrators","imprint_one":"imprint","imprint_other":"imprints","inker_one":"inker","inker_other":"inkers","language_one":"language","language_other":"languages","letterer_one":"letterer","letterer_other":"letterers","modified":"modification date","narrator_one":"narrator","narrator_other":"narrators","numberOfPages":"print length","penciler_one":"penciler","penciler_other":"pencilers","published":"publication date","publisher_one":"publisher","publisher_other":"publishers","series_one":"series","series_other":"series","subject_one":"subject","subject_other":"subjects","subtitle":"subtitle","title":"title","translator_one":"translator","translator_other":"translators"}}`), On = {\n publication: kn\n}, ri = {\n fr: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./fr-C5HEel98.js */ "./node_modules/@readium/navigator/dist/fr-C5HEel98.js")),\n ar: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./ar-DyHX_uy2.js */ "./node_modules/@readium/navigator/dist/ar-DyHX_uy2.js")),\n da: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./da-Dct0PS3E.js */ "./node_modules/@readium/navigator/dist/da-Dct0PS3E.js")),\n // \'el\': () => import(\'@edrlab/thorium-locales/publication-metadata/el.json\'),\n // \'et\': () => import(\'@edrlab/thorium-locales/publication-metadata/et.json\'),\n it: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./it-DFOBoXGy.js */ "./node_modules/@readium/navigator/dist/it-DFOBoXGy.js")),\n pt_PT: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./pt_PT-Di3sVjze.js */ "./node_modules/@readium/navigator/dist/pt_PT-Di3sVjze.js")),\n sv: () => Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./sv-BfzAFsVN.js */ "./node_modules/@readium/navigator/dist/sv-BfzAFsVN.js"))\n // \'tr\': () => import(\'@edrlab/thorium-locales/publication-metadata/tr.json\'),\n // \'uk\': () => import(\'@edrlab/thorium-locales/publication-metadata/uk.json\')\n}, oi = On?.publication?.metadata?.accessibility?.["display-guide"] || {};\nclass gt {\n constructor() {\n this.currentLocaleCode = "en", this.locale = oi, this.loadedLocales = {}, this.loadedLocales.en = oi;\n }\n static getInstance() {\n return gt.instance || (gt.instance = new gt()), gt.instance;\n }\n /**\n * Loads a locale dynamically\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr\')\n * @returns Promise indicating if the locale was loaded successfully\n */\n async loadLocale(t) {\n if (!si.includes(t))\n return console.warn(`Locale \'${t}\' is not enabled`), !1;\n if (t in this.loadedLocales)\n return !0;\n try {\n if (!(t in ri))\n return console.warn(`Locale file not found for: ${t}`), !1;\n const n = (await ri[t]()).default?.publication?.metadata?.accessibility?.["display-guide"];\n return n ? (this.loadedLocales[t] = n, !0) : (console.warn(`No accessibility strings found in locale ${t}`), !1);\n } catch (e) {\n return console.warn(`Failed to load locale ${t}:`, e), !1;\n }\n }\n /**\n * Registers a new locale or updates an existing one\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr-FR\')\n * @param localeData The locale data to register\n */\n registerLocale(t, e) {\n if (!t || typeof t != "string")\n throw new Error("Locale code must be a non-empty string");\n this.loadedLocales[t] = e;\n }\n /**\n * Sets the current locale by language code, loading it dynamically if needed\n * @param localeCode BCP 47 language code (e.g., \'en\', \'fr\')\n * @returns Promise indicating if the locale was set successfully\n */\n async setLocale(t) {\n return t in this.loadedLocales || await this.loadLocale(t), t in this.loadedLocales ? (this.locale = this.loadedLocales[t], this.currentLocaleCode = t, !0) : (console.warn(`Locale \'${t}\' is not available`), !1);\n }\n /**\n * Gets the current locale code (BCP 47)\n */\n getCurrentLocale() {\n return this.currentLocaleCode;\n }\n /**\n * Gets a list of available locale codes\n */\n getAvailableLocales() {\n return si;\n }\n getNestedValue(t, e) {\n const i = e.split(".");\n let n = t;\n for (const s of i) {\n if (n == null)\n return;\n n = n[s];\n }\n return n;\n }\n /**\n * Gets a localized string by key\n * @param key The key for the string to retrieve\n * @returns The localized string as a [L10nString], or an empty string if not found\n */\n getString(t) {\n let e = this.getNestedValue(this.locale, t);\n return e === void 0 && this.currentLocaleCode !== "en" && (e = this.getNestedValue(this.loadedLocales.en, t)), e !== void 0 ? typeof e == "string" ? { compact: e, descriptive: e } : e : (console.warn(`Missing localization for key: ${t}`), { compact: "", descriptive: "" });\n }\n}\ngt.getInstance();\nvar b = /* @__PURE__ */ ((r) => (r.reflowable = "reflowable", r.fixed = "fixed", r.scrolled = "scrolled", r))(b || {});\nclass Fe {\n /**\n * Creates a [Encryption].\n */\n constructor(t) {\n this.algorithm = t.algorithm, this.compression = t.compression, this.originalLength = t.originalLength, this.profile = t.profile, this.scheme = t.scheme;\n }\n /**\n * Parses a [Encryption] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.algorithm)\n return new Fe({\n algorithm: t.algorithm,\n compression: t.compression,\n originalLength: t.originalLength,\n profile: t.profile,\n scheme: t.scheme\n });\n }\n /**\n * Serializes a [Encryption] to its RWPM JSON representation.\n */\n serialize() {\n const t = { algorithm: this.algorithm };\n return this.compression !== void 0 && (t.compression = this.compression), this.originalLength !== void 0 && (t.originalLength = this.originalLength), this.profile !== void 0 && (t.profile = this.profile), this.scheme !== void 0 && (t.scheme = this.scheme), t;\n }\n}\nvar G = /* @__PURE__ */ ((r) => (r.left = "left", r.right = "right", r.center = "center", r))(G || {});\nlet X = class be {\n constructor(t) {\n this.otherProperties = t;\n }\n get page() {\n return this.otherProperties.page;\n }\n /**\n * Creates a [Properties] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new be(t);\n }\n /**\n * Serializes a [Properties] to its RWPM JSON representation.\n */\n serialize() {\n return this.otherProperties;\n }\n /**\n * Makes a copy of this [Properties] after merging in the given additional other [properties].\n */\n add(t) {\n const e = Object.assign({}, this.otherProperties);\n for (const i in t)\n e[i] = t[i];\n return new be(e);\n }\n};\nObject.defineProperty(X.prototype, "encryption", {\n get: function() {\n return Fe.deserialize(this.otherProperties.encrypted);\n }\n});\nfunction Rn(r) {\n return r && Array.isArray(r) ? r : void 0;\n}\nfunction Yi(r) {\n return r && typeof r == "string" ? [r] : Rn(r);\n}\nfunction ai(r) {\n return typeof r == "string" ? new Date(r) : void 0;\n}\nfunction Ut(r) {\n return isNaN(r) ? void 0 : r;\n}\nfunction V(r) {\n return Ut(r) !== void 0 && Math.sign(r) >= 0 ? r : void 0;\n}\nfunction An(r) {\n const t = new Array();\n return r.forEach((e) => t.push(e)), t;\n}\nclass m {\n /** Creates a MediaType object. */\n constructor(t) {\n let e, i, n = t.mediaType.replace(/\\s/g, "").split(";");\n const s = n[0].split("/");\n if (s.length === 2) {\n if (e = s[0].toLowerCase().trim(), i = s[1].toLowerCase().trim(), e.length === 0 || i.length === 0)\n throw new Error("Invalid media type");\n } else\n throw new Error("Invalid media type");\n const o = {};\n for (let p = 1; p < n.length; p++) {\n const g = n[p].split("=");\n if (g.length === 2) {\n const d = g[0].toLocaleLowerCase(), f = d === "charset" ? g[1].toUpperCase() : g[1];\n o[d] = f;\n }\n }\n const a = {}, l = Object.keys(o);\n l.sort((p, g) => p.localeCompare(g)), l.forEach((p) => a[p] = o[p]);\n let h = "";\n for (const p in a) {\n const g = a[p];\n h += `;${p}=${g}`;\n }\n const c = `${e}/${i}${h}`, u = a.encoding;\n this.string = c, this.type = e, this.subtype = i, this.parameters = a, this.encoding = u, this.name = t.name, this.fileExtension = t.fileExtension;\n }\n static parse(t) {\n return new m(t);\n }\n /** Structured syntax suffix, e.g. `+zip` in `application/epub+zip`.\n * Gives a hint on the underlying structure of this media type.\n * See. https://tools.ietf.org/html/rfc6838#section-4.2.8\n */\n get structuredSyntaxSuffix() {\n const t = this.subtype.split("+");\n return t.length > 1 ? `+${t[t.length - 1]}` : void 0;\n }\n /** Parameter values might or might not be case-sensitive, depending on the semantics of\n * the parameter name.\n * https://tools.ietf.org/html/rfc2616#section-3.7\n *\n * The character set names may be up to 40 characters taken from the printable characters\n * of US-ASCII. However, no distinction is made between use of upper and lower case\n * letters.\n * https://www.iana.org/assignments/character-sets/character-sets.xhtml\n */\n get charset() {\n return this.parameters.charset;\n }\n /** Returns whether the given `other` media type is included in this media type.\n * For example, `text/html` contains `text/html;charset=utf-8`.\n * - `other` must match the parameters in the `parameters` property, but extra parameters\n * are ignored.\n * - Order of parameters is ignored.\n * - Wildcards are supported, meaning that `image/*` contains `image/png`\n */\n contains(t) {\n const e = typeof t == "string" ? m.parse({ mediaType: t }) : t;\n if (!((this.type === "*" || this.type === e.type) && (this.subtype === "*" || this.subtype === e.subtype)))\n return !1;\n const i = new Set(\n Object.entries(this.parameters).map(([s, o]) => `${s}=${o}`)\n ), n = new Set(\n Object.entries(e.parameters).map(([s, o]) => `${s}=${o}`)\n );\n for (const s of Array.from(i.values()))\n if (!n.has(s))\n return !1;\n return !0;\n }\n /** Returns whether this media type and `other` are the same, ignoring parameters that\n * are not in both media types.\n * For example, `text/html` matches `text/html;charset=utf-8`, but `text/html;charset=ascii`\n * doesn\'t. This is basically like `contains`, but working in both direction.\n */\n matches(t) {\n const e = typeof t == "string" ? m.parse({ mediaType: t }) : t;\n return this.contains(e) || e.contains(this);\n }\n /**\n * Returns whether this media type matches any of the [others] media types.\n */\n matchesAny(...t) {\n for (const e of t)\n if (this.matches(e))\n return !0;\n return !1;\n }\n /** Checks the MediaType equals another one (comparing their string) */\n equals(t) {\n return this.string === t.string;\n }\n /** Returns whether this media type is structured as a ZIP archive. */\n get isZIP() {\n return this.matchesAny(\n m.ZIP,\n m.LCP_PROTECTED_AUDIOBOOK,\n m.LCP_PROTECTED_PDF\n ) || this.structuredSyntaxSuffix === "+zip";\n }\n /** Returns whether this media type is structured as a JSON file. */\n get isJSON() {\n return this.matchesAny(m.JSON) || this.structuredSyntaxSuffix === "+json";\n }\n /** Returns whether this media type is of an OPDS feed. */\n get isOPDS() {\n return this.matchesAny(\n m.OPDS1,\n m.OPDS1_ENTRY,\n m.OPDS2,\n m.OPDS2_PUBLICATION,\n m.OPDS_AUTHENTICATION\n ) || this.structuredSyntaxSuffix === "+json";\n }\n /** Returns whether this media type is of an HTML document. */\n get isHTML() {\n return this.matchesAny(m.HTML, m.XHTML);\n }\n /** Returns whether this media type is of a bitmap image, so excluding vectorial formats. */\n get isBitmap() {\n return this.matchesAny(\n m.AVIF,\n m.BMP,\n m.GIF,\n m.JPEG,\n m.PNG,\n m.TIFF,\n m.WEBP\n );\n }\n /** Returns whether this media type is of an audio clip. */\n get isAudio() {\n return this.type === "audio";\n }\n /** Returns whether this media type is of a video clip. */\n get isVideo() {\n return this.type === "video";\n }\n /** Returns whether this media type is of a Readium Web Publication Manifest. */\n get isRWPM() {\n return this.matchesAny(\n m.READIUM_AUDIOBOOK_MANIFEST,\n m.DIVINA_MANIFEST,\n m.READIUM_WEBPUB_MANIFEST\n );\n }\n /** Returns whether this media type is of a publication file. */\n get isPublication() {\n return this.matchesAny(\n m.READIUM_AUDIOBOOK,\n m.READIUM_AUDIOBOOK_MANIFEST,\n m.CBZ,\n m.DIVINA,\n m.DIVINA_MANIFEST,\n m.EPUB,\n m.LCP_PROTECTED_AUDIOBOOK,\n m.LCP_PROTECTED_PDF,\n m.LPF,\n m.PDF,\n m.W3C_WPUB_MANIFEST,\n m.READIUM_WEBPUB,\n m.READIUM_WEBPUB_MANIFEST,\n m.ZAB\n );\n }\n // Known Media Types\n static get AAC() {\n return m.parse({ mediaType: "audio/aac", fileExtension: "aac" });\n }\n static get ACSM() {\n return m.parse({\n mediaType: "application/vnd.adobe.adept+xml",\n name: "Adobe Content Server Message",\n fileExtension: "acsm"\n });\n }\n static get AIFF() {\n return m.parse({ mediaType: "audio/aiff", fileExtension: "aiff" });\n }\n static get AVI() {\n return m.parse({\n mediaType: "video/x-msvideo",\n fileExtension: "avi"\n });\n }\n static get AVIF() {\n return m.parse({ mediaType: "image/avif", fileExtension: "avif" });\n }\n static get BINARY() {\n return m.parse({ mediaType: "application/octet-stream" });\n }\n static get BMP() {\n return m.parse({ mediaType: "image/bmp", fileExtension: "bmp" });\n }\n static get CBZ() {\n return m.parse({\n mediaType: "application/vnd.comicbook+zip",\n name: "Comic Book Archive",\n fileExtension: "cbz"\n });\n }\n static get CSS() {\n return m.parse({ mediaType: "text/css", fileExtension: "css" });\n }\n static get DIVINA() {\n return m.parse({\n mediaType: "application/divina+zip",\n name: "Digital Visual Narratives",\n fileExtension: "divina"\n });\n }\n static get DIVINA_MANIFEST() {\n return m.parse({\n mediaType: "application/divina+json",\n name: "Digital Visual Narratives",\n fileExtension: "json"\n });\n }\n static get EPUB() {\n return m.parse({\n mediaType: "application/epub+zip",\n name: "EPUB",\n fileExtension: "epub"\n });\n }\n static get GIF() {\n return m.parse({ mediaType: "image/gif", fileExtension: "gif" });\n }\n static get GZ() {\n return m.parse({\n mediaType: "application/gzip",\n fileExtension: "gz"\n });\n }\n static get HTML() {\n return m.parse({ mediaType: "text/html", fileExtension: "html" });\n }\n static get JAVASCRIPT() {\n return m.parse({\n mediaType: "text/javascript",\n fileExtension: "js"\n });\n }\n static get JPEG() {\n return m.parse({ mediaType: "image/jpeg", fileExtension: "jpeg" });\n }\n static get JSON() {\n return m.parse({ mediaType: "application/json" });\n }\n static get LCP_LICENSE_DOCUMENT() {\n return m.parse({\n mediaType: "application/vnd.readium.lcp.license.v1.0+json",\n name: "LCP License",\n fileExtension: "lcpl"\n });\n }\n static get LCP_PROTECTED_AUDIOBOOK() {\n return m.parse({\n mediaType: "application/audiobook+lcp",\n name: "LCP Protected Audiobook",\n fileExtension: "lcpa"\n });\n }\n static get LCP_PROTECTED_PDF() {\n return m.parse({\n mediaType: "application/pdf+lcp",\n name: "LCP Protected PDF",\n fileExtension: "lcpdf"\n });\n }\n static get LCP_STATUS_DOCUMENT() {\n return m.parse({\n mediaType: "application/vnd.readium.license.status.v1.0+json"\n });\n }\n static get LPF() {\n return m.parse({\n mediaType: "application/lpf+zip",\n fileExtension: "lpf"\n });\n }\n static get MP3() {\n return m.parse({ mediaType: "audio/mpeg", fileExtension: "mp3" });\n }\n static get MPEG() {\n return m.parse({ mediaType: "video/mpeg", fileExtension: "mpeg" });\n }\n static get NCX() {\n return m.parse({\n mediaType: "application/x-dtbncx+xml",\n fileExtension: "ncx"\n });\n }\n static get OGG() {\n return m.parse({ mediaType: "audio/ogg", fileExtension: "oga" });\n }\n static get OGV() {\n return m.parse({ mediaType: "video/ogg", fileExtension: "ogv" });\n }\n static get OPDS1() {\n return m.parse({\n mediaType: "application/atom+xml;profile=opds-catalog"\n });\n }\n static get OPDS1_ENTRY() {\n return m.parse({\n mediaType: "application/atom+xml;type=entry;profile=opds-catalog"\n });\n }\n static get OPDS2() {\n return m.parse({ mediaType: "application/opds+json" });\n }\n static get OPDS2_PUBLICATION() {\n return m.parse({ mediaType: "application/opds-publication+json" });\n }\n static get OPDS_AUTHENTICATION() {\n return m.parse({\n mediaType: "application/opds-authentication+json"\n });\n }\n static get OPUS() {\n return m.parse({ mediaType: "audio/opus", fileExtension: "opus" });\n }\n static get OTF() {\n return m.parse({ mediaType: "font/otf", fileExtension: "otf" });\n }\n static get PDF() {\n return m.parse({\n mediaType: "application/pdf",\n name: "PDF",\n fileExtension: "pdf"\n });\n }\n static get PNG() {\n return m.parse({ mediaType: "image/png", fileExtension: "png" });\n }\n static get READIUM_AUDIOBOOK() {\n return m.parse({\n mediaType: "application/audiobook+zip",\n name: "Readium Audiobook",\n fileExtension: "audiobook"\n });\n }\n static get READIUM_AUDIOBOOK_MANIFEST() {\n return m.parse({\n mediaType: "application/audiobook+json",\n name: "Readium Audiobook",\n fileExtension: "json"\n });\n }\n static get READIUM_CONTENT_DOCUMENT() {\n return m.parse({\n mediaType: "application/vnd.readium.content+json",\n name: "Readium Content Document",\n fileExtension: "json"\n });\n }\n static get READIUM_GUIDED_NAVIGATION_DOCUMENT() {\n return m.parse({\n mediaType: "application/guided-navigation+json",\n name: "Readium Guided Navigation Document",\n fileExtension: "json"\n });\n }\n static get READIUM_POSITION_LIST() {\n return m.parse({\n mediaType: "application/vnd.readium.position-list+json",\n name: "Readium Position List",\n fileExtension: "json"\n });\n }\n static get READIUM_WEBPUB() {\n return m.parse({\n mediaType: "application/webpub+zip",\n name: "Readium Web Publication",\n fileExtension: "webpub"\n });\n }\n static get READIUM_WEBPUB_MANIFEST() {\n return m.parse({\n mediaType: "application/webpub+json",\n name: "Readium Web Publication",\n fileExtension: "json"\n });\n }\n static get SMIL() {\n return m.parse({\n mediaType: "application/smil+xml",\n fileExtension: "smil"\n });\n }\n static get SVG() {\n return m.parse({\n mediaType: "image/svg+xml",\n fileExtension: "svg"\n });\n }\n static get TEXT() {\n return m.parse({ mediaType: "text/plain", fileExtension: "txt" });\n }\n static get TIFF() {\n return m.parse({ mediaType: "image/tiff", fileExtension: "tiff" });\n }\n static get TTF() {\n return m.parse({ mediaType: "font/ttf", fileExtension: "ttf" });\n }\n static get W3C_WPUB_MANIFEST() {\n return m.parse({\n mediaType: "application/x.readium.w3c.wpub+json",\n name: "Web Publication",\n fileExtension: "json"\n });\n }\n static get WAV() {\n return m.parse({ mediaType: "audio/wav", fileExtension: "wav" });\n }\n static get WEBM_AUDIO() {\n return m.parse({ mediaType: "audio/webm", fileExtension: "webm" });\n }\n static get WEBM_VIDEO() {\n return m.parse({ mediaType: "video/webm", fileExtension: "webm" });\n }\n static get WEBP() {\n return m.parse({ mediaType: "image/webp", fileExtension: "webp" });\n }\n static get WOFF() {\n return m.parse({ mediaType: "font/woff", fileExtension: "woff" });\n }\n static get WOFF2() {\n return m.parse({ mediaType: "font/woff2", fileExtension: "woff2" });\n }\n static get XHTML() {\n return m.parse({\n mediaType: "application/xhtml+xml",\n fileExtension: "xhtml"\n });\n }\n static get XML() {\n return m.parse({\n mediaType: "application/xml",\n fileExtension: "xml"\n });\n }\n static get ZAB() {\n return m.parse({\n mediaType: "application/x.readium.zab+zip",\n name: "Zipped Audio Book",\n fileExtension: "zab"\n });\n }\n static get ZIP() {\n return m.parse({\n mediaType: "application/zip",\n fileExtension: "zip"\n });\n }\n}\nclass li {\n constructor(t) {\n this.uri = t, this.parameters = this.getParameters(t);\n }\n /**\n * List of URI template parameter keys, if the [Link] is templated.\n */\n getParameters(t) {\n const e = /\\{\\??([^}]+)\\}/g, i = t.match(e);\n return i ? new Set(\n i.join(",").replace(e, "$1").split(",").map((n) => n.trim())\n ) : /* @__PURE__ */ new Set();\n }\n /** Expands the URI by replacing the template variables by the given parameters.\n * Any extra parameter is appended as query parameters.\n * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570\n */\n expand(t) {\n const e = (n) => n.split(",").map((s) => {\n const o = t[s];\n return o ? encodeURIComponent(o) : "";\n }).join(","), i = (n) => "?" + n.split(",").map((s) => {\n const o = s.split("=")[0], a = t[o];\n return a ? `${o}=${encodeURIComponent(a)}` : "";\n }).join("&");\n return this.uri.replace(/\\{(\\??)([^}]+)\\}/g, (...n) => n[1] ? i(n[2]) : e(n[2]));\n }\n}\nclass C {\n /**\n * Creates a [Locations].\n */\n constructor(t) {\n this.fragments = t.fragments ? t.fragments : new Array(), this.progression = t.progression, this.totalProgression = t.totalProgression, this.position = t.position, this.otherLocations = t.otherLocations;\n }\n /**\n * Parses a [Locations] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n const e = Ut(t.progression), i = Ut(t.totalProgression), n = Ut(t.position), s = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set([\n "fragment",\n "fragments",\n "progression",\n "totalProgression",\n "position"\n ]);\n return Object.entries(t).forEach(([a, l]) => {\n o.has(a) || s.set(a, l);\n }), new C({\n fragments: Yi(t.fragments || t.fragment),\n progression: e !== void 0 && e >= 0 && e <= 1 ? e : void 0,\n totalProgression: i !== void 0 && i >= 0 && i <= 1 ? i : void 0,\n position: n !== void 0 && n > 0 ? n : void 0,\n otherLocations: s.size === 0 ? void 0 : s\n });\n }\n /**\n * Serializes a [Locations] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.fragments && (t.fragments = this.fragments), this.progression !== void 0 && (t.progression = this.progression), this.totalProgression !== void 0 && (t.totalProgression = this.totalProgression), this.position !== void 0 && (t.position = this.position), this.otherLocations && this.otherLocations.forEach((e, i) => t[i] = e), t;\n }\n}\nclass rt {\n /**\n * Creates a [Text].\n */\n constructor(t) {\n this.after = t.after, this.before = t.before, this.highlight = t.highlight;\n }\n /**\n * Parses a [Locations] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new rt({\n after: t.after,\n before: t.before,\n highlight: t.highlight\n });\n }\n /**\n * Serializes a [Locations] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.after !== void 0 && (t.after = this.after), this.before !== void 0 && (t.before = this.before), this.highlight !== void 0 && (t.highlight = this.highlight), t;\n }\n}\nclass I {\n /**\n * Creates a [Locator].\n */\n constructor(t) {\n this.href = t.href, this.type = t.type, this.title = t.title, this.locations = t.locations ? t.locations : new C({}), this.text = t.text;\n }\n /**\n * Parses a [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.href && t.type)\n return new I({\n href: t.href,\n type: t.type,\n title: t.title,\n locations: C.deserialize(t.locations),\n text: rt.deserialize(t.text)\n });\n }\n /**\n * Serializes a [Link] to its RWPM JSON representation.\n */\n serialize() {\n const t = { href: this.href, type: this.type };\n return this.title !== void 0 && (t.title = this.title), this.locations && (t.locations = this.locations.serialize()), this.text && (t.text = this.text.serialize()), t;\n }\n /**\n * Shortcut to get a copy of the [Locator] with different [Locations] sub-properties.\n */\n copyWithLocations(t) {\n return new I({\n href: this.href,\n type: this.type,\n title: this.title,\n text: this.text,\n locations: new C({ ...this.locations, ...t })\n });\n }\n}\nclass $ {\n /**\n * Creates a [Link].\n */\n constructor(t) {\n this.href = t.href, this.templated = t.templated, this.type = t.type, this.title = t.title, this.rels = t.rels, this.properties = t.properties, this.height = t.height, this.width = t.width, this.size = t.size, this.duration = t.duration, this.bitrate = t.bitrate, this.languages = t.languages, this.alternates = t.alternates, this.children = t.children;\n }\n /**\n * Parses a [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(!t || typeof t.href != "string"))\n return new $({\n href: t.href,\n templated: t.templated,\n type: t.type,\n title: t.title,\n rels: t.rel ? Array.isArray(t.rel) ? new Set(t.rel) : /* @__PURE__ */ new Set([t.rel]) : void 0,\n properties: X.deserialize(t.properties),\n height: V(t.height),\n width: V(t.width),\n size: V(t.size),\n duration: V(t.duration),\n bitrate: V(t.bitrate),\n languages: Yi(t.language),\n alternates: Bt.deserialize(t.alternate),\n children: Bt.deserialize(t.children)\n });\n }\n /**\n * Serializes a [Link] to its RWPM JSON representation.\n */\n serialize() {\n const t = { href: this.href };\n return this.templated !== void 0 && (t.templated = this.templated), this.type !== void 0 && (t.type = this.type), this.title !== void 0 && (t.title = this.title), this.rels && (t.rel = An(this.rels)), this.properties && (t.properties = this.properties.serialize()), this.height !== void 0 && (t.height = this.height), this.width !== void 0 && (t.width = this.width), this.size !== void 0 && (t.size = this.size), this.duration !== void 0 && (t.duration = this.duration), this.bitrate !== void 0 && (t.bitrate = this.bitrate), this.languages && (t.language = this.languages), this.alternates && (t.alternate = this.alternates.serialize()), this.children && (t.children = this.children.serialize()), t;\n }\n /** MediaType of the linked resource. */\n get mediaType() {\n return this.type !== void 0 ? m.parse({ mediaType: this.type }) : m.BINARY;\n }\n /** Computes an absolute URL to the link, relative to the given `baseURL`.\n * If the link\'s `href` is already absolute, the `baseURL` is ignored.\n */\n toURL(t) {\n const e = this.href.replace(/^(\\/)/, "");\n if (e.length === 0) return;\n let i = t || "/";\n return i.startsWith("/") && (i = "file://" + i), new URL(e, i).href.replace(/^(file:\\/\\/)/, "");\n }\n /** List of URI template parameter keys, if the `Link` is templated. */\n get templateParameters() {\n return this.templated ? new li(this.href).parameters : /* @__PURE__ */ new Set();\n }\n /** Expands the `Link`\'s HREF by replacing URI template variables by the given parameters.\n * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570\n */\n expandTemplate(t) {\n return new $({\n href: new li(this.href).expand(t),\n templated: !1\n });\n }\n /**\n * Makes a copy of this [Link] after merging in the given additional other [properties].\n */\n addProperties(t) {\n const e = $.deserialize(this.serialize());\n return e.properties = e.properties ? e.properties?.add(t) : new X(t), e;\n }\n /**\n * Creates a [Locator] from a reading order [Link].\n */\n get locator() {\n let t = this.href.split("#");\n return new I({\n href: t.length > 0 && t[0] !== void 0 ? t[0] : this.href,\n type: this.type ?? "",\n title: this.title,\n locations: new C({\n fragments: t.length > 1 && t[1] !== void 0 ? [t[1]] : []\n })\n });\n }\n}\nclass Bt {\n /**\n * Creates a [Links].\n */\n constructor(t) {\n this.items = t;\n }\n /**\n * Creates a list of [Link] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && Array.isArray(t))\n return new Bt(\n t.map((e) => $.deserialize(e)).filter((e) => e !== void 0)\n );\n }\n /**\n * Serializes an array of [Link] to its RWPM JSON representation.\n */\n serialize() {\n return this.items.map((t) => t.serialize());\n }\n /** Finds the first link with the given relation. */\n findWithRel(t) {\n const e = (i) => i.rels && i.rels.has(t);\n return this.items.find(e);\n }\n /** Finds all the links with the given relation. */\n filterByRel(t) {\n const e = (i) => i.rels && i.rels.has(t);\n return this.items.filter(e);\n }\n /** Finds the first link matching the given HREF. */\n findWithHref(t) {\n const e = (i) => i.href === t;\n return this.items.find(e);\n }\n /** Finds the index of the first link matching the given HREF. */\n findIndexWithHref(t) {\n const e = (i) => i.href === t;\n return this.items.findIndex(e);\n }\n /** Finds the first link matching the given media type. */\n findWithMediaType(t) {\n const e = (i) => i.mediaType.matches(t);\n return this.items.find(e);\n }\n /** Finds all the links matching the given media type. */\n filterByMediaType(t) {\n const e = (i) => i.mediaType.matches(t);\n return this.items.filter(e);\n }\n /** Finds all the links matching any of the given media types. */\n filterByMediaTypes(t) {\n const e = (i) => {\n for (const n of t)\n if (i.mediaType.matches(n))\n return !0;\n return !1;\n };\n return this.items.filter(e);\n }\n /** Returns whether all the resources in the collection are audio clips. */\n everyIsAudio() {\n const t = (e) => e.mediaType.isAudio;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are bitmaps. */\n everyIsBitmap() {\n const t = (e) => e.mediaType.isBitmap;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are HTML documents. */\n everyIsHTML() {\n const t = (e) => e.mediaType.isHTML;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are video clips. */\n everyIsVideo() {\n const t = (e) => e.mediaType.isVideo;\n return this.items.length > 0 && this.items.every(t);\n }\n /** Returns whether all the resources in the collection are matching any of the given media types. */\n everyMatchesMediaType(t) {\n return Array.isArray(t) ? this.items.length > 0 && this.items.every((e) => {\n for (const i of t)\n return e.mediaType.matches(i);\n return !1;\n }) : this.items.length > 0 && this.items.every((e) => e.mediaType.matches(t));\n }\n filterLinksHasType() {\n return this.items.filter((t) => t.type);\n }\n}\nvar qi = /* @__PURE__ */ ((r) => (r.EPUB = "https://readium.org/webpub-manifest/profiles/epub", r.AUDIOBOOK = "https://readium.org/webpub-manifest/profiles/audiobook", r.DIVINA = "https://readium.org/webpub-manifest/profiles/divina", r.PDF = "https://readium.org/webpub-manifest/profiles/pdf", r))(qi || {}), M = /* @__PURE__ */ ((r) => (r.ltr = "ltr", r.rtl = "rtl", r))(M || {});\nX.prototype.getContains = function() {\n return new Set(this.otherProperties.contains || []);\n};\nclass Vt {\n /**\n * Creates a [DomRange].\n */\n constructor(t) {\n this.cssSelector = t.cssSelector, this.textNodeIndex = t.textNodeIndex, this.charOffset = t.charOffset;\n }\n /**\n * Parses a [DomRangePoint] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!(t && t.cssSelector)) return;\n let e = V(t.textNodeIndex);\n if (e === void 0) return;\n let i = V(t.charOffset);\n return i === void 0 && (i = V(t.offset)), new Vt({\n cssSelector: t.cssSelector,\n textNodeIndex: e,\n charOffset: i\n });\n }\n /**\n * Serializes a [DomRangePoint] to its RWPM JSON representation.\n */\n serialize() {\n const t = {\n cssSelector: this.cssSelector,\n textNodeIndex: this.textNodeIndex\n };\n return this.charOffset !== void 0 && (t.charOffset = this.charOffset), t;\n }\n}\nclass Ie {\n /**\n * Creates a [DomRange].\n */\n constructor(t) {\n this.start = t.start, this.end = t.end;\n }\n /**\n * Parses a [DomRange] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n let e = Vt.deserialize(t.start);\n if (e)\n return new Ie({\n start: e,\n end: Vt.deserialize(t.end)\n });\n }\n /**\n * Serializes a [DomRange] to its RWPM JSON representation.\n */\n serialize() {\n const t = { start: this.start.serialize() };\n return this.end && (t.end = this.end.serialize()), t;\n }\n}\nC.prototype.getCssSelector = function() {\n return this.otherLocations?.get("cssSelector");\n};\nC.prototype.getPartialCfi = function() {\n return this.otherLocations?.get("partialCfi");\n};\nC.prototype.getDomRange = function() {\n return Ie.deserialize(this.otherLocations?.get("domRange"));\n};\nC.prototype.fragmentParameters = function() {\n return new Map(\n this.fragments.map((r) => r.startsWith("#") ? r.slice(1) : r).join("&").split("&").filter((r) => !r.startsWith("#")).map((r) => r.split("=")).filter((r) => r.length === 2).map((r) => [\n r[0].trim().toLowerCase(),\n r[1].trim()\n ])\n );\n};\nC.prototype.htmlId = function() {\n if (!this.fragments.length) return;\n let r = this.fragments.find((t) => t.length && !t.includes("="));\n if (!r) {\n const t = this.fragmentParameters();\n t.has("id") ? r = t.get("id") : t.has("name") && (r = t.get("name"));\n }\n return r?.startsWith("#") ? r.slice(1) : r;\n};\nC.prototype.page = function() {\n const r = parseInt(this.fragmentParameters().get("page"));\n if (!isNaN(r) && r >= 0) return r;\n};\nC.prototype.time = function() {\n const r = parseInt(this.fragmentParameters().get("t"));\n if (!isNaN(r)) return r;\n};\nC.prototype.space = function() {\n const r = this.fragmentParameters();\n if (!r.has("xywh")) return;\n const t = r.get("xywh").split(",").map((e) => parseInt(e));\n if (t.length === 4 && !t.some(isNaN))\n return t;\n};\nclass ze {\n /** Creates a [Price]. */\n constructor(t) {\n this.currency = t.currency, this.value = t.value;\n }\n /**\n * Parses a [Price] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (!t) return;\n let e = t.currency;\n if (!(e && typeof e == "string" && e.length > 0))\n return;\n let i = V(t.value);\n if (i !== void 0)\n return new ze({ currency: e, value: i });\n }\n /**\n * Serializes a [Price] to its RWPM JSON representation.\n */\n serialize() {\n return { currency: this.currency, value: this.value };\n }\n}\nclass xt {\n /** Creates a [Acquisition]. */\n constructor(t) {\n this.type = t.type, this.children = t.children;\n }\n /**\n * Parses a [Acquisition] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.type)\n return new xt({\n type: t.type,\n children: xt.deserializeArray(t.children)\n });\n }\n static deserializeArray(t) {\n if (Array.isArray(t))\n return t.map((e) => xt.deserialize(e)).filter((e) => e !== void 0);\n }\n /**\n * Serializes a [Acquisition] to its RWPM JSON representation.\n */\n serialize() {\n const t = { type: this.type };\n return this.children && (t.children = this.children.map((e) => e.serialize())), t;\n }\n}\nclass De {\n /** Creates a [Price]. */\n constructor(t) {\n this.total = t.total, this.position = t.position;\n }\n /**\n * Parses a [Holds] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new De({\n total: V(t.total),\n position: V(t.position)\n });\n }\n /**\n * Serializes a [Holds] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.total !== void 0 && (t.total = this.total), this.position !== void 0 && (t.position = this.position), t;\n }\n}\nclass We {\n /** Creates a [Copies]. */\n constructor(t) {\n this.total = t.total, this.available = t.available;\n }\n /**\n * Parses a [Copies] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t)\n return new We({\n total: V(t.total),\n available: V(t.available)\n });\n }\n /**\n * Serializes a [Copies] to its RWPM JSON representation.\n */\n serialize() {\n const t = {};\n return this.total !== void 0 && (t.total = this.total), this.available !== void 0 && (t.available = this.available), t;\n }\n}\nclass Ue {\n /** Creates a [Availability]. */\n constructor(t) {\n this.state = t.state, this.since = t.since, this.until = t.until;\n }\n /**\n * Parses a [Availability] from its RWPM JSON representation.\n */\n static deserialize(t) {\n if (t && t.state)\n return new Ue({\n state: t.state,\n since: ai(t.since),\n until: ai(t.until)\n });\n }\n /**\n * Serializes a [Availability] to its RWPM JSON representation.\n */\n serialize() {\n const t = { state: this.state };\n return this.since !== void 0 && (t.since = this.since.toISOString()), this.until !== void 0 && (t.until = this.until.toISOString()), t;\n }\n}\nX.prototype.getNumberOfItems = function() {\n return V(this.otherProperties.numberOfItems);\n};\nX.prototype.getPrice = function() {\n return ze.deserialize(this.otherProperties.price);\n};\nX.prototype.getIndirectAcquisitions = function() {\n const r = this.otherProperties.indirectAcquisition;\n if (r && Array.isArray(r))\n return r.map((t) => xt.deserialize(t)).filter((t) => t !== void 0);\n};\nX.prototype.getHolds = function() {\n return De.deserialize(this.otherProperties.holds);\n};\nX.prototype.getCopies = function() {\n return We.deserialize(this.otherProperties.copies);\n};\nX.prototype.getAvailability = function() {\n return Ue.deserialize(this.otherProperties.availability);\n};\nX.prototype.getAuthenticate = function() {\n return $.deserialize(this.otherProperties.authenticate);\n};\nconst Tn = "CssSelectorGenerator";\nfunction hi(r = "unknown problem", ...t) {\n console.warn(`${Tn}: ${r}`, ...t);\n}\nfunction Nn(r) {\n return r instanceof RegExp;\n}\nfunction Mn(r) {\n return r.replace(/[|\\\\{}()[\\]^$+?.]/g, "\\\\$&").replace(/\\*/g, ".+");\n}\nfunction Fn(r) {\n const t = r.map((e) => {\n if (Nn(e))\n return (i) => e.test(i);\n if (typeof e == "function")\n return (i) => {\n const n = e(i);\n return typeof n != "boolean" ? (hi("pattern matcher function invalid", "Provided pattern matching function does not return boolean. It\'s result will be ignored.", e), !1) : n;\n };\n if (typeof e == "string") {\n const i = new RegExp("^" + Mn(e) + "$");\n return (n) => i.test(n);\n }\n return hi("pattern matcher invalid", "Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.", e), () => !1;\n });\n return (e) => t.some((i) => i(e));\n}\nFn([\n "class",\n "id",\n // Angular attributes\n "ng-*"\n]);\nconst In = Math.pow(2, 32), ci = () => Math.round(Math.random() * In).toString(36), we = () => `${Math.round(performance.now())}-${ci()}-${ci()}`, ft = 1;\nclass zn {\n constructor(t) {\n this.destination = null, this.registrar = /* @__PURE__ */ new Map(), this.origin = "", this.channelId = "", this.receiver = this.receive.bind(this), this.preLog = [], this.wnd = t, t.addEventListener("message", this.receiver);\n }\n receive(t) {\n if (t.source === null) throw Error("Event source is null");\n if (typeof t.data != "object") return;\n const e = t.data;\n if (!(!("_readium" in e) || !e._readium || e._readium <= 0)) {\n if (e.key === "_ping") {\n if (!this.destination) {\n if (this.destination = t.source, this.origin = t.origin, this.channelId = e._channel, e._readium !== ft) {\n e._readium > ft ? this.send("error", `received comms version ${e._readium} higher than ${ft}`) : this.send("error", `received comms version ${e._readium} lower than ${ft}`), this.destination = null, this.origin = "", this.channelId = "";\n return;\n }\n this.send("_pong", void 0), this.preLog.forEach((i) => this.send("log", i)), this.preLog = [];\n }\n return;\n } else if (this.channelId) {\n if (e._channel !== this.channelId || t.origin !== this.origin) return;\n } else\n return;\n this.handle(e);\n }\n }\n handle(t) {\n const e = this.registrar.get(t.key);\n if (!e || e.length === 0) {\n t.strict && this.send("_unhandled", t);\n return;\n }\n e.forEach((i) => i.cb(t.data, (n) => {\n this.send("_ack", n, t.id);\n }));\n }\n register(t, e, i) {\n Array.isArray(t) || (t = [t]), t.forEach((n) => {\n const s = this.registrar.get(n);\n if (s && s.length >= 0) {\n if (s.find((a) => a.module === e)) throw new Error(`Trying to register another callback for combination of event ${n} and module ${e}`);\n s.push({\n cb: i,\n module: e\n }), this.registrar.set(n, s);\n } else\n this.registrar.set(n, [{\n cb: i,\n module: e\n }]);\n });\n }\n unregister(t, e) {\n Array.isArray(t) || (t = [t]), t.forEach((i) => {\n const n = this.registrar.get(i);\n !n || n.length === 0 || n.splice(n.findIndex((s) => s.module === e), 1);\n });\n }\n unregisterAll(t) {\n this.registrar.forEach((e, i) => this.registrar.set(i, e.filter((n) => n.module !== t)));\n }\n log(...t) {\n this.destination ? this.send("log", t) : this.preLog.push(t);\n }\n get ready() {\n return !!this.destination;\n }\n destroy() {\n this.destination = null, this.channelId = "", this.preLog = [], this.registrar.clear(), this.wnd.removeEventListener("message", this.receiver);\n }\n send(t, e, i = void 0, n = []) {\n if (!this.destination) throw Error("Attempted to send comms message before destination has been initialized");\n const s = {\n _readium: ft,\n _channel: this.channelId,\n id: i ?? we(),\n // scrict,\n key: t,\n data: e\n };\n try {\n this.destination.postMessage(s, {\n targetOrigin: this.origin,\n transfer: n\n });\n } catch (o) {\n if (n.length > 0) throw o;\n this.destination.postMessage(s, this.origin, n);\n }\n }\n}\nclass Et {\n}\nfunction di(r) {\n return r.split("").reverse().join("");\n}\nfunction Dn(r, t, e) {\n const i = di(t);\n return e.map((n) => {\n const s = Math.max(0, n.end - t.length - n.errors), o = di(r.slice(s, n.end));\n return {\n start: Ki(o, i, n.errors).reduce((l, h) => n.end - h.end < l ? n.end - h.end : l, n.end),\n end: n.end,\n errors: n.errors\n };\n });\n}\nfunction de(r) {\n return (r | -r) >> 31 & 1;\n}\nfunction ui(r, t, e, i) {\n let n = r.P[e], s = r.M[e];\n const o = i >>> 31, a = t[e] | o, l = a | s, h = (a & n) + n ^ n | a;\n let c = s | ~(h | n), u = n & h;\n const p = de(c & r.lastRowMask[e]) - de(u & r.lastRowMask[e]);\n return c <<= 1, u <<= 1, u |= o, c |= de(i) - o, n = u | ~(l | c), s = c & l, r.P[e] = n, r.M[e] = s, p;\n}\nfunction Ki(r, t, e) {\n if (t.length === 0)\n return [];\n e = Math.min(e, t.length);\n const i = [], n = 32, s = Math.ceil(t.length / n) - 1, o = {\n P: new Uint32Array(s + 1),\n M: new Uint32Array(s + 1),\n lastRowMask: new Uint32Array(s + 1)\n };\n o.lastRowMask.fill(1 << 31), o.lastRowMask[s] = 1 << (t.length - 1) % n;\n const a = new Uint32Array(s + 1), l = /* @__PURE__ */ new Map(), h = [];\n for (let p = 0; p < 256; p++)\n h.push(a);\n for (let p = 0; p < t.length; p += 1) {\n const g = t.charCodeAt(p);\n if (l.has(g))\n continue;\n const d = new Uint32Array(s + 1);\n l.set(g, d), g < h.length && (h[g] = d);\n for (let f = 0; f <= s; f += 1) {\n d[f] = 0;\n for (let w = 0; w < n; w += 1) {\n const P = f * n + w;\n if (P >= t.length)\n continue;\n t.charCodeAt(P) === g && (d[f] |= 1 << w);\n }\n }\n }\n let c = Math.max(0, Math.ceil(e / n) - 1);\n const u = new Uint32Array(s + 1);\n for (let p = 0; p <= c; p += 1)\n u[p] = (p + 1) * n;\n u[s] = t.length;\n for (let p = 0; p <= c; p += 1)\n o.P[p] = -1, o.M[p] = 0;\n for (let p = 0; p < r.length; p += 1) {\n const g = r.charCodeAt(p);\n let d;\n g < h.length ? d = h[g] : (d = l.get(g), typeof d > "u" && (d = a));\n let f = 0;\n for (let w = 0; w <= c; w += 1)\n f = ui(o, d, w, f), u[w] += f;\n if (u[c] - f <= e && c < s && (d[c + 1] & 1 || f < 0)) {\n c += 1, o.P[c] = -1, o.M[c] = 0;\n let w;\n if (c === s) {\n const P = t.length % n;\n w = P === 0 ? n : P;\n } else\n w = n;\n u[c] = u[c - 1] + w - f + ui(o, d, c, f);\n } else\n for (; c > 0 && u[c] >= e + n; )\n c -= 1;\n c === s && u[c] <= e && (u[c] < e && i.splice(0, i.length), i.push({\n start: -1,\n end: p + 1,\n errors: u[c]\n }), e = u[c]);\n }\n return i;\n}\nfunction Wn(r, t, e) {\n const i = Ki(r, t, e);\n return Dn(r, t, i);\n}\nfunction Ji(r, t, e) {\n let i = 0;\n const n = [];\n for (; i !== -1; )\n i = r.indexOf(t, i), i !== -1 && (n.push({\n start: i,\n end: i + t.length,\n errors: 0\n }), i += 1);\n return n.length > 0 ? n : Wn(r, t, e);\n}\nfunction pi(r, t) {\n return t.length === 0 || r.length === 0 ? 0 : 1 - Ji(r, t, t.length)[0].errors / t.length;\n}\nfunction Un(r, t, e = {}) {\n if (t.length === 0)\n return null;\n const i = Math.min(256, t.length / 2), n = Ji(r, t, i);\n if (n.length === 0)\n return null;\n const s = (a) => {\n const p = 1 - a.errors / t.length, g = e.prefix ? pi(\n r.slice(\n Math.max(0, a.start - e.prefix.length),\n a.start\n ),\n e.prefix\n ) : 1, d = e.suffix ? pi(\n r.slice(a.end, a.end + e.suffix.length),\n e.suffix\n ) : 1;\n let f = 1;\n return typeof e.hint == "number" && (f = 1 - Math.abs(a.start - e.hint) / r.length), (50 * p + 20 * g + 20 * d + 2 * f) / 92;\n }, o = n.map((a) => ({\n start: a.start,\n end: a.end,\n score: s(a)\n }));\n return o.sort((a, l) => l.score - a.score), o[0];\n}\nfunction Se(r, t, e) {\n const i = e === 1 ? t : t - 1;\n if (r.charAt(i).trim() !== "")\n return t;\n let n, s;\n if (e === 2 ? (n = r.substring(0, t), s = n.trimEnd()) : (n = r.substring(t), s = n.trimStart()), !s.length)\n return -1;\n const o = n.length - s.length;\n return e === 2 ? t - o : t + o;\n}\nfunction fi(r, t) {\n const e = r.commonAncestorContainer.ownerDocument.createNodeIterator(\n r.commonAncestorContainer,\n NodeFilter.SHOW_TEXT\n ), i = t === 1 ? r.startContainer : r.endContainer, n = t === 1 ? r.endContainer : r.startContainer;\n let s = e.nextNode();\n for (; s && s !== i; )\n s = e.nextNode();\n t === 2 && (s = e.previousNode());\n let o = -1;\n const a = () => {\n if (s = t === 1 ? e.nextNode() : e.previousNode(), s) {\n const l = s.textContent, h = t === 1 ? 0 : l.length;\n o = Se(l, h, t);\n }\n };\n for (; s && o === -1 && s !== n; )\n a();\n if (s && o >= 0)\n return { node: s, offset: o };\n throw new RangeError("No text nodes with non-whitespace text found in range");\n}\nfunction Hn(r) {\n if (!r.toString().trim().length)\n throw new RangeError("Range contains no non-whitespace text");\n if (r.startContainer.nodeType !== Node.TEXT_NODE)\n throw new RangeError("Range startContainer is not a text node");\n if (r.endContainer.nodeType !== Node.TEXT_NODE)\n throw new RangeError("Range endContainer is not a text node");\n const t = r.cloneRange();\n let e = !1, i = !1;\n const n = {\n start: Se(\n r.startContainer.textContent,\n r.startOffset,\n 1\n /* Forwards */\n ),\n end: Se(\n r.endContainer.textContent,\n r.endOffset,\n 2\n /* Backwards */\n )\n };\n if (n.start >= 0 && (t.setStart(r.startContainer, n.start), e = !0), n.end > 0 && (t.setEnd(r.endContainer, n.end), i = !0), e && i)\n return t;\n if (!e) {\n const { node: s, offset: o } = fi(\n t,\n 1\n /* Forwards */\n );\n s && o >= 0 && t.setStart(s, o);\n }\n if (!i) {\n const { node: s, offset: o } = fi(\n t,\n 2\n /* Backwards */\n );\n s && o > 0 && t.setEnd(s, o);\n }\n return t;\n}\nfunction Zi(r) {\n switch (r.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.TEXT_NODE:\n return r.textContent?.length ?? 0;\n default:\n return 0;\n }\n}\nfunction mi(r) {\n let t = r.previousSibling, e = 0;\n for (; t; )\n e += Zi(t), t = t.previousSibling;\n return e;\n}\nfunction Qi(r, ...t) {\n let e = t.shift();\n const i = r.ownerDocument.createNodeIterator(\n r,\n NodeFilter.SHOW_TEXT\n ), n = [];\n let s = i.nextNode(), o, a = 0;\n for (; e !== void 0 && s; )\n o = s, a + o.data.length > e ? (n.push({ node: o, offset: e - a }), e = t.shift()) : (s = i.nextNode(), a += o.data.length);\n for (; e !== void 0 && o && a === e; )\n n.push({ node: o, offset: o.data.length }), e = t.shift();\n if (e !== void 0)\n throw new RangeError("Offset exceeds text length");\n return n;\n}\nclass K {\n constructor(t, e) {\n if (e < 0)\n throw new Error("Offset is invalid");\n this.element = t, this.offset = e;\n }\n /**\n * Return a copy of this position with offset relative to a given ancestor\n * element.\n *\n * @param parent - Ancestor of `this.element`\n */\n relativeTo(t) {\n if (!t.contains(this.element))\n throw new Error("Parent is not an ancestor of current element");\n let e = this.element, i = this.offset;\n for (; e !== t; )\n i += mi(e), e = e.parentElement;\n return new K(e, i);\n }\n /**\n * Resolve the position to a specific text node and offset within that node.\n *\n * Throws if `this.offset` exceeds the length of the element\'s text. In the\n * case where the element has no text and `this.offset` is 0, the `direction`\n * option determines what happens.\n *\n * Offsets at the boundary between two nodes are resolved to the start of the\n * node that begins at the boundary.\n *\n * @param options.direction - Specifies in which direction to search for the\n * nearest text node if `this.offset` is `0` and\n * `this.element` has no text. If not specified an\n * error is thrown.\n *\n * @throws {RangeError}\n */\n resolve(t = {}) {\n try {\n return Qi(this.element, this.offset)[0];\n } catch (e) {\n if (this.offset === 0 && t.direction !== void 0) {\n const i = document.createTreeWalker(\n this.element.getRootNode(),\n NodeFilter.SHOW_TEXT\n );\n i.currentNode = this.element;\n const n = t.direction === 1, s = n ? i.nextNode() : i.previousNode();\n if (!s)\n throw e;\n return { node: s, offset: n ? 0 : s.data.length };\n } else\n throw e;\n }\n }\n /**\n * Construct a `TextPosition` that refers to the `offset`th character within\n * `node`.\n */\n static fromCharOffset(t, e) {\n switch (t.nodeType) {\n case Node.TEXT_NODE:\n return K.fromPoint(t, e);\n case Node.ELEMENT_NODE:\n return new K(t, e);\n default:\n throw new Error("Node is not an element or text node");\n }\n }\n /**\n * Construct a `TextPosition` representing the range start or end point (node, offset).\n *\n * @param node\n * @param offset - Offset within the node\n */\n static fromPoint(t, e) {\n switch (t.nodeType) {\n case Node.TEXT_NODE: {\n if (e < 0 || e > t.data.length)\n throw new Error("Text node offset is out of range");\n if (!t.parentElement)\n throw new Error("Text node has no parent");\n const i = mi(t) + e;\n return new K(t.parentElement, i);\n }\n case Node.ELEMENT_NODE: {\n if (e < 0 || e > t.childNodes.length)\n throw new Error("Child node offset is out of range");\n let i = 0;\n for (let n = 0; n < e; n++)\n i += Zi(t.childNodes[n]);\n return new K(t, i);\n }\n default:\n throw new Error("Point is not in an element or text node");\n }\n }\n}\nclass et {\n constructor(t, e) {\n this.start = t, this.end = e;\n }\n /**\n * Create a new TextRange whose `start` and `end` are computed relative to\n * `element`. `element` must be an ancestor of both `start.element` and\n * `end.element`.\n */\n relativeTo(t) {\n return new et(\n this.start.relativeTo(t),\n this.end.relativeTo(t)\n );\n }\n /**\n * Resolve this TextRange to a (DOM) Range.\n *\n * The resulting DOM Range will always start and end in a `Text` node.\n * Hence `TextRange.fromRange(range).toRange()` can be used to "shrink" a\n * range to the text it contains.\n *\n * May throw if the `start` or `end` positions cannot be resolved to a range.\n */\n toRange() {\n let t, e;\n this.start.element === this.end.element && this.start.offset <= this.end.offset ? [t, e] = Qi(\n this.start.element,\n this.start.offset,\n this.end.offset\n ) : (t = this.start.resolve({\n direction: 1\n /* FORWARDS */\n }), e = this.end.resolve({\n direction: 2\n /* BACKWARDS */\n }));\n const i = new Range();\n return i.setStart(t.node, t.offset), i.setEnd(e.node, e.offset), i;\n }\n /**\n * Create a TextRange from a (DOM) Range\n */\n static fromRange(t) {\n const e = K.fromPoint(\n t.startContainer,\n t.startOffset\n ), i = K.fromPoint(t.endContainer, t.endOffset);\n return new et(e, i);\n }\n /**\n * Create a TextRange representing the `start`th to `end`th characters in\n * `root`\n */\n static fromOffsets(t, e, i) {\n return new et(\n new K(t, e),\n new K(t, i)\n );\n }\n /**\n * Return a new Range representing `range` trimmed of any leading or trailing\n * whitespace\n */\n static trimmedRange(t) {\n return Hn(et.fromRange(t).toRange());\n }\n}\nclass jt {\n constructor(t, e, i) {\n this.root = t, this.start = e, this.end = i;\n }\n static fromRange(t, e) {\n const i = et.fromRange(e).relativeTo(t);\n return new jt(\n t,\n i.start.offset,\n i.end.offset\n );\n }\n static fromSelector(t, e) {\n return new jt(t, e.start, e.end);\n }\n toSelector() {\n return {\n type: "TextPositionSelector",\n start: this.start,\n end: this.end\n };\n }\n toRange() {\n return et.fromOffsets(this.root, this.start, this.end).toRange();\n }\n}\nclass $t {\n /**\n * @param root - A root element from which to anchor.\n */\n constructor(t, e, i = {}) {\n this.root = t, this.exact = e, this.context = i;\n }\n /**\n * Create a `TextQuoteAnchor` from a range.\n *\n * Will throw if `range` does not contain any text nodes.\n */\n static fromRange(t, e) {\n const i = t.textContent, n = et.fromRange(e).relativeTo(t), s = n.start.offset, o = n.end.offset, a = 32;\n return new $t(t, i.slice(s, o), {\n prefix: i.slice(Math.max(0, s - a), s),\n suffix: i.slice(o, Math.min(i.length, o + a))\n });\n }\n static fromSelector(t, e) {\n const { prefix: i, suffix: n } = e;\n return new $t(t, e.exact, { prefix: i, suffix: n });\n }\n toSelector() {\n return {\n type: "TextQuoteSelector",\n exact: this.exact,\n prefix: this.context.prefix,\n suffix: this.context.suffix\n };\n }\n toRange(t = {}) {\n return this.toPositionAnchor(t).toRange();\n }\n toPositionAnchor(t = {}) {\n const e = this.root.textContent, i = Un(e, this.exact, {\n ...this.context,\n hint: t.hint\n });\n if (!i)\n throw new Error("Quote not found");\n return new jt(this.root, i.start, i.end);\n }\n}\nfunction Bn(r) {\n const t = r.tagName.toUpperCase();\n return t === "IMG" || t === "VIDEO" || t === "AUDIO" || t === "IFRAME" || t === "OBJECT" || t === "EMBED" || t === "CANVAS";\n}\nfunction It(r, t) {\n try {\n const e = t.locations, i = t.text;\n if (i && i.highlight) {\n let n;\n e && e.getCssSelector() && (n = r.querySelector(e.getCssSelector())), n || (n = r.body);\n const s = new $t(n, i.highlight, {\n prefix: i.before,\n suffix: i.after\n });\n try {\n return s.toRange();\n } catch {\n return console.warn("Quote not found:", s), null;\n }\n }\n if (e) {\n let n = null;\n if (!n && e.getCssSelector() && (n = r.querySelector(e.getCssSelector())), !n && e.fragments) {\n for (const s of e.fragments)\n if (n = r.getElementById(s), n)\n break;\n }\n if (n) {\n const s = r.createRange();\n return n.childNodes.length === 0 || Bn(n) ? (s.selectNode(n), s) : (s.setStartBefore(n), s.setEndAfter(n), s);\n }\n }\n } catch (e) {\n console.error(e);\n }\n return null;\n}\nfunction Vn(r, t) {\n let e = r.getClientRects();\n e.length || r.commonAncestorContainer.nodeType === Node.ELEMENT_NODE && (e = r.commonAncestorContainer.getClientRects());\n const i = 1, n = [];\n for (const h of e)\n n.push({\n bottom: h.bottom,\n height: h.height,\n left: h.left,\n right: h.right,\n top: h.top,\n width: h.width\n });\n const s = tn(\n n,\n i\n ), o = $n(s, i), a = en(o), l = 4;\n for (let h = a.length - 1; h >= 0; h--) {\n const c = a[h];\n if (!(c.width * c.height > l))\n if (a.length > 1)\n a.splice(h, 1);\n else\n break;\n }\n return a;\n}\nfunction tn(r, t, e) {\n for (let i = 0; i < r.length; i++)\n for (let n = i + 1; n < r.length; n++) {\n const s = r[i], o = r[n];\n if (s === o)\n continue;\n const a = j(s.top, o.top, t) && j(s.bottom, o.bottom, t), l = j(s.left, o.left, t) && j(s.right, o.right, t);\n if (a && !l && nn(s, o, t)) {\n const u = r.filter((g) => g !== s && g !== o), p = jn(s, o);\n return u.push(p), tn(\n u,\n t\n );\n }\n }\n return r;\n}\nfunction jn(r, t) {\n const e = Math.min(r.left, t.left), i = Math.max(r.right, t.right), n = Math.min(r.top, t.top), s = Math.max(r.bottom, t.bottom);\n return {\n bottom: s,\n height: s - n,\n left: e,\n right: i,\n top: n,\n width: i - e\n };\n}\nfunction $n(r, t) {\n const e = new Set(r);\n for (const i of r) {\n if (!(i.width > 1 && i.height > 1)) {\n e.delete(i);\n continue;\n }\n for (const s of r)\n if (i !== s && e.has(s) && Gn(s, i, t)) {\n e.delete(i);\n break;\n }\n }\n return Array.from(e);\n}\nfunction Gn(r, t, e) {\n return zt(r, t.left, t.top, e) && zt(r, t.right, t.top, e) && zt(r, t.left, t.bottom, e) && zt(r, t.right, t.bottom, e);\n}\nfunction zt(r, t, e, i) {\n return (r.left < t || j(r.left, t, i)) && (r.right > t || j(r.right, t, i)) && (r.top < e || j(r.top, e, i)) && (r.bottom > e || j(r.bottom, e, i));\n}\nfunction en(r) {\n for (let t = 0; t < r.length; t++)\n for (let e = t + 1; e < r.length; e++) {\n const i = r[t], n = r[e];\n if (i !== n && nn(i, n, -1)) {\n let s = [], o;\n const a = gi(i, n);\n if (a.length === 1)\n s = a, o = i;\n else {\n const h = gi(n, i);\n a.length < h.length ? (s = a, o = i) : (s = h, o = n);\n }\n const l = r.filter((h) => h !== o);\n return Array.prototype.push.apply(l, s), en(l);\n }\n }\n return r;\n}\nfunction gi(r, t) {\n const e = Xn(t, r);\n if (e.height === 0 || e.width === 0)\n return [r];\n const i = [];\n {\n const n = {\n bottom: r.bottom,\n height: 0,\n left: r.left,\n right: e.left,\n top: r.top,\n width: 0\n };\n n.width = n.right - n.left, n.height = n.bottom - n.top, n.height !== 0 && n.width !== 0 && i.push(n);\n }\n {\n const n = {\n bottom: e.top,\n height: 0,\n left: e.left,\n right: e.right,\n top: r.top,\n width: 0\n };\n n.width = n.right - n.left, n.height = n.bottom - n.top, n.height !== 0 && n.width !== 0 && i.push(n);\n }\n {\n const n = {\n bottom: r.bottom,\n height: 0,\n left: e.left,\n right: e.right,\n top: e.bottom,\n width: 0\n };\n n.width = n.right - n.left, n.height = n.bottom - n.top, n.height !== 0 && n.width !== 0 && i.push(n);\n }\n {\n const n = {\n bottom: r.bottom,\n height: 0,\n left: e.right,\n right: r.right,\n top: r.top,\n width: 0\n };\n n.width = n.right - n.left, n.height = n.bottom - n.top, n.height !== 0 && n.width !== 0 && i.push(n);\n }\n return i;\n}\nfunction Xn(r, t) {\n const e = Math.max(r.left, t.left), i = Math.min(r.right, t.right), n = Math.max(r.top, t.top), s = Math.min(r.bottom, t.bottom);\n return {\n bottom: s,\n height: Math.max(0, s - n),\n left: e,\n right: i,\n top: n,\n width: Math.max(0, i - e)\n };\n}\nfunction nn(r, t, e) {\n return (r.left < t.right || e >= 0 && j(r.left, t.right, e)) && (t.left < r.right || e >= 0 && j(t.left, r.right, e)) && (r.top < t.bottom || e >= 0 && j(r.top, t.bottom, e)) && (t.top < r.bottom || e >= 0 && j(t.top, r.bottom, e));\n}\nfunction j(r, t, e) {\n return Math.abs(r - t) <= e;\n}\nfunction He(r) {\n const t = {}, e = r.document.documentElement.style;\n for (const i in r.document.documentElement.style)\n Object.hasOwn(e, i) && !Number.isNaN(Number.parseInt(i)) && (t[e[i]] = e.getPropertyValue(e[i]));\n return t;\n}\nfunction sn(r, t) {\n const e = He(r);\n Object.keys(e).forEach((i) => {\n t.hasOwnProperty(i) || re(r, i);\n }), Object.entries(t).forEach(([i, n]) => {\n e[i] !== n && Tt(r, i, n);\n });\n}\nfunction ue(r, t) {\n return r.document.documentElement.style.getPropertyValue(t);\n}\nfunction Tt(r, t, e) {\n r.document.documentElement.style.setProperty(t, e);\n}\nfunction re(r, t) {\n r.document.documentElement.style.removeProperty(t);\n}\nlet Dt = null, pe = null, Ct = 0;\nconst mt = { r: 255, g: 255, b: 255, a: 1 }, ct = /* @__PURE__ */ new Map(), Yn = () => {\n if (!Dt)\n if (typeof OffscreenCanvas < "u")\n Dt = new OffscreenCanvas(5, 5), pe = Dt.getContext("2d", {\n willReadFrequently: !0,\n desynchronized: !0\n });\n else {\n const r = document.createElement("canvas");\n r.width = 5, r.height = 5, Dt = r, pe = r.getContext("2d", {\n willReadFrequently: !0,\n desynchronized: !0\n });\n }\n return pe;\n}, qn = (r) => {\n if (!r) return !0;\n const t = r.trim().toLowerCase();\n return t.startsWith("var(") || [\n "transparent",\n "currentcolor",\n "inherit",\n "initial",\n "revert",\n "unset",\n "revert-layer"\n ].includes(t) ? !0 : [\n "linear-gradient",\n "radial-gradient",\n "conic-gradient",\n "repeating-linear-gradient",\n "repeating-radial-gradient",\n "repeating-conic-gradient"\n ].some((n) => t.includes(n));\n}, Wt = (r, t) => {\n console.warn(\n `[Decorator] Could not parse color: "${r}". ${t} Falling back to ${JSON.stringify(mt)} to compute contrast. Please use a CSS color value that can be computed to RGB(A).`\n );\n}, ve = (r, t = null) => {\n const e = t ? `${r}|${t}` : r, i = ct.get(e);\n if (i !== void 0)\n return i ?? mt;\n if (qn(r))\n return Wt(r, "Unsupported color format or special value."), ct.set(e, null), mt;\n const n = Yn();\n if (!n)\n return Wt(r, "Could not get canvas context."), ct.set(e, null), mt;\n try {\n Ct === 0 && n.clearRect(0, 0, 5, 5);\n const s = Ct % 5, o = Math.floor(Ct / 5);\n n.clearRect(s, o, 1, 1), t && (n.fillStyle = t, n.fillRect(s, o, 1, 1)), n.fillStyle = r, n.fillRect(s, o, 1, 1);\n const a = n.getImageData(s, o, 1, 1);\n Ct = (Ct + 1) % 25;\n const [l, h, c, u] = a.data;\n if (u === 0)\n return Wt(r, "Fully transparent color."), ct.set(e, null), mt;\n const p = { r: l, g: h, b: c, a: u / 255 };\n return ct.set(e, p), p;\n } catch (s) {\n return Wt(r, `Error: ${s instanceof Error ? s.message : String(s)}`), ct.set(e, null), mt;\n }\n}, fe = (r) => {\n const t = r / 255;\n return t <= 0.03928 ? t / 12.92 : Math.pow((t + 0.055) / 1.055, 2.4);\n}, yi = (r) => {\n const t = fe(r.r), e = fe(r.g), i = fe(r.b);\n return 0.2126 * t + 0.7152 * e + 0.0722 * i;\n}, bi = (r, t) => {\n const e = typeof r == "string" ? ve(r) : r, i = typeof t == "string" ? ve(t) : t, n = yi(e), s = yi(i), o = Math.max(n, s), a = Math.min(n, s);\n return (o + 0.05) / (a + 0.05);\n}, Pe = (r, t = null) => {\n const e = ve(r, t), i = bi(e, { r: 255, g: 255, b: 255, a: 1 }), n = bi(e, { r: 0, g: 0, b: 0, a: 1 });\n return i > n;\n}, Kn = (r, t = null) => Pe(r, t) ? "white" : "black", wi = "#FFFF00", Jn = () => "Highlight" in window, Si = ["IMG", "IMAGE", "AUDIO", "VIDEO", "SVG"];\nclass Zn {\n /**\n * Creates a DecorationGroup object\n * @param id Unique HTML ID-adhering name of the group\n * @param name Human-readable name of the group\n */\n constructor(t, e, i, n) {\n this.wnd = t, this.comms = e, this.id = i, this.name = n, this.items = [], this.lastItemId = 0, this.container = void 0, this.activateable = !1, this.experimentalHighlights = !1, this.currentRender = 0, Jn() && (this.experimentalHighlights = !0, this.notTextFlag = /* @__PURE__ */ new Map());\n }\n get activeable() {\n return this.activateable;\n }\n set activeable(t) {\n this.activateable = t;\n }\n /**\n * Adds a new decoration to the group.\n * @param decoration Decoration to add\n */\n add(t) {\n const e = `${this.id}-${this.lastItemId++}`, i = It(this.wnd.document, t.locator);\n if (!i) {\n this.comms.log("Can\'t locate DOM range for decoration", t);\n return;\n }\n const n = i.commonAncestorContainer;\n n.nodeType !== Node.TEXT_NODE && this.experimentalHighlights && (Si.includes(n.nodeName.toUpperCase()) && this.notTextFlag?.set(e, !0), i.cloneContents().querySelector(Si.join(", ").toLowerCase()) && this.notTextFlag?.set(e, !0), (n.textContent?.trim() || "").length === 0 && this.notTextFlag?.set(e, !0));\n const s = {\n decoration: t,\n id: e,\n range: i\n };\n this.items.push(s), this.layout(s), this.renderLayout([s]);\n }\n /**\n * Removes the decoration with given ID from the group.\n * @param identifier ID of item to remove\n */\n remove(t) {\n const e = this.items.findIndex((n) => n.decoration.id === t);\n if (e < 0) return;\n const i = this.items[e];\n this.items.splice(e, 1), i.clickableElements = void 0, i.container && (i.container.remove(), i.container = void 0), this.experimentalHighlights && !this.notTextFlag?.has(i.id) && this.wnd.CSS.highlights.get(this.id)?.delete(i.range), this.notTextFlag?.delete(i.id);\n }\n /**\n * Notifies that the given decoration was modified and needs to be updated.\n * @param decoration Decoration to update\n */\n update(t) {\n this.remove(t.id), this.add(t);\n }\n /**\n * Removes all decorations from this group.\n */\n clear() {\n this.clearContainer(), this.items.length = 0, this.notTextFlag?.clear();\n }\n /**\n * Recreates the decoration elements.\n * To be called after reflowing the resource, for example.\n */\n requestLayout() {\n this.wnd.cancelAnimationFrame(this.currentRender), this.clearContainer(), this.items.forEach((t) => this.layout(t)), this.renderLayout(this.items);\n }\n experimentalLayout(t) {\n const [e, i] = this.requireContainer(!0);\n i.add(t.range);\n const n = ue(this.wnd, "--USER__backgroundColor") || this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color"), s = t.decoration?.style?.tint ?? wi;\n e.innerHTML = `\n ::highlight(${this.id}) {\n color: ${Kn(s, n)};\n background-color: ${s};\n }`;\n }\n /**\n * Layouts a single DecorationItem.\n * @param item\n */\n layout(t) {\n if (this.experimentalHighlights && !this.notTextFlag?.has(t.id))\n return this.experimentalLayout(t);\n const e = this.wnd.document.createElement("div");\n e.setAttribute("id", t.id), e.dataset.highlightId = t.decoration.id, e.style.setProperty("pointer-events", "none");\n const i = this.wnd.innerWidth, n = parseInt(\n getComputedStyle(this.wnd.document.documentElement).getPropertyValue(\n "column-count"\n )\n ), s = i / (n || 1), o = this.wnd.document.scrollingElement, a = o.scrollLeft, l = o.scrollTop, h = (d, f, w) => {\n if (d.style.position = "absolute", t.decoration?.style?.width === "viewport") {\n d.style.width = `${i}px`, d.style.height = `${f.height}px`;\n let P = Math.floor(f.left / i) * i;\n d.style.left = `${P + a}px`, d.style.top = `${f.top + l}px`;\n } else if (t.decoration?.style?.width === "bounds")\n d.style.width = `${w.width}px`, d.style.height = `${f.height}px`, d.style.left = `${w.left + a}px`, d.style.top = `${f.top + l}px`;\n else if (t.decoration?.style?.width === "page") {\n d.style.width = `${s}px`, d.style.height = `${f.height}px`;\n let P = Math.floor(f.left / s) * s;\n d.style.left = `${P + a}px`, d.style.top = `${f.top + l}px`;\n } else\n d.style.width = `${f.width}px`, d.style.height = `${f.height}px`, d.style.left = `${f.left + a}px`, d.style.top = `${f.top + l}px`;\n }, c = t.range.getBoundingClientRect();\n let u = this.wnd.document.createElement("template");\n const p = this.getCurrentDarkMode();\n u.innerHTML = `\n \n \n `.trim();\n const g = u.content.firstElementChild;\n if (t.decoration?.style?.layout === "bounds") {\n const d = g.cloneNode(!0);\n d.style.setProperty("pointer-events", "none"), h(d, c, c), e.append(d);\n } else {\n let d = Vn(\n t.range\n );\n d = d.sort((f, w) => f.top < w.top ? -1 : f.top > w.top ? 1 : 0);\n for (let f of d) {\n const w = g.cloneNode(!0);\n w.style.setProperty("pointer-events", "none"), h(w, f, c), e.append(w);\n }\n }\n t.container = e, t.clickableElements = Array.from(\n e.querySelectorAll("[data-activable=\'1\']")\n ), t.clickableElements.length || (t.clickableElements = Array.from(e.children));\n }\n renderLayout(t) {\n this.wnd.cancelAnimationFrame(this.currentRender), this.currentRender = this.wnd.requestAnimationFrame(() => {\n if (t = t.filter((i) => !this.experimentalHighlights || !!this.notTextFlag?.has(i.id)), !t || t.length === 0) return;\n this.requireContainer().append(...t.map((i) => i.container).filter((i) => !!i));\n });\n }\n /**\n * Returns the group container element, after making sure it exists.\n * @returns Group\'s container\n */\n requireContainer(t = !1) {\n if (t) {\n let e;\n this.wnd.document.getElementById(`${this.id}-style`) ? e = this.wnd.document.getElementById(`${this.id}-style`) : (e = this.wnd.document.createElement("style"), e.dataset.readium = "true", e.id = `${this.id}-style`, this.wnd.document.head.appendChild(e));\n let i;\n return this.wnd.CSS.highlights.has(this.id) ? i = this.wnd.CSS.highlights.get(this.id) : (i = new this.wnd.Highlight(), this.wnd.CSS.highlights.set(this.id, i)), [e, i];\n }\n return this.container || (this.container = this.wnd.document.createElement("div"), this.container.setAttribute("id", this.id), this.container.dataset.group = this.name, this.container.dataset.readium = "true", this.container.style.setProperty("pointer-events", "none"), this.container.style.display = "contents", this.wnd.document.body.append(this.container)), this.container;\n }\n getCurrentDarkMode() {\n return ue(this.wnd, "--USER__appearance") === "readium-night-on" || Pe(ue(this.wnd, "--USER__backgroundColor")) || Pe(this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color"));\n }\n /**\n * Removes the group container.\n */\n clearContainer() {\n this.experimentalHighlights && this.wnd.CSS.highlights.delete(this.id), this.container && (this.container.remove(), this.container = void 0);\n }\n}\nconst Ot = class Ot extends Et {\n constructor() {\n super(...arguments), this.resizeFrame = 0, this.lastGroupId = 0, this.groups = /* @__PURE__ */ new Map(), this.handleResizer = this.handleResize.bind(this);\n }\n cleanup() {\n this.groups.forEach((t) => t.clear()), this.groups.clear();\n }\n updateHighlightStyles() {\n this.groups.forEach((t) => {\n t.requestLayout();\n });\n }\n extractCustomProperty(t, e) {\n if (!t) return null;\n const i = t.match(new RegExp(`${e}:\\\\s*([^;]+)`));\n return i ? i[1].trim() : null;\n }\n handleResize() {\n this.wnd.clearTimeout(this.resizeFrame), this.resizeFrame = this.wnd.setTimeout(() => {\n this.groups.forEach((t) => {\n t.experimentalHighlights || t.requestLayout();\n });\n }, 50);\n }\n mount(t, e) {\n return this.wnd = t, e.register("decorate", Ot.moduleName, (i, n) => {\n const s = i;\n s.decoration && s.decoration.locator && (s.decoration.locator = I.deserialize(s.decoration.locator)), this.groups.has(s.group) || this.groups.set(s.group, new Zn(\n t,\n e,\n `readium-decoration-${this.lastGroupId++}`,\n s.group\n ));\n const o = this.groups.get(s.group);\n switch (s.action) {\n case "add":\n o?.add(s.decoration);\n break;\n case "remove":\n o?.remove(s.decoration.id);\n break;\n case "clear":\n o?.clear();\n break;\n case "update":\n o?.update(s.decoration);\n break;\n }\n n(!0);\n }), this.resizeObserver = new ResizeObserver(() => t.requestAnimationFrame(() => this.handleResize())), this.resizeObserver.observe(t.document.body), t.addEventListener("orientationchange", this.handleResizer), t.addEventListener("resize", this.handleResizer), this.backgroundObserver = new MutationObserver((i) => {\n i.some((s) => {\n if (s.type === "attributes" && s.attributeName === "style") {\n const o = s.target, a = s.oldValue, l = o.getAttribute("style"), h = this.extractCustomProperty(a, "--USER__appearance"), c = this.extractCustomProperty(l, "--USER__appearance"), u = this.extractCustomProperty(a, "--USER__backgroundColor"), p = this.extractCustomProperty(l, "--USER__backgroundColor");\n return h !== c || u !== p;\n }\n return !1;\n }) && this.updateHighlightStyles();\n }), this.backgroundObserver.observe(t.document.documentElement, {\n attributes: !0,\n attributeFilter: ["style"],\n attributeOldValue: !0,\n subtree: !0\n }), e.log("Decorator Mounted"), !0;\n }\n unmount(t, e) {\n return t.removeEventListener("orientationchange", this.handleResizer), t.removeEventListener("resize", this.handleResizer), e.unregisterAll(Ot.moduleName), this.resizeObserver.disconnect(), this.backgroundObserver.disconnect(), this.cleanup(), e.log("Decorator Unmounted"), !0;\n }\n};\nOt.moduleName = "decorator";\nlet Ee = Ot;\nconst vi = "readium-snapper-style", Rt = class Rt extends Et {\n constructor() {\n super(...arguments), this.protected = !1;\n }\n buildStyles() {\n return `\n html, body {\n touch-action: manipulation;\n user-select: ${this.protected ? "none" : "auto"};\n }`;\n }\n mount(t, e) {\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = vi, i.textContent = this.buildStyles(), t.document.head.appendChild(i), e.register("protect", Rt.moduleName, (n, s) => {\n this.protected = !0, i.textContent = this.buildStyles(), s(!0);\n }), e.register("unprotect", Rt.moduleName, (n, s) => {\n this.protected = !1, i.textContent = this.buildStyles(), s(!0);\n }), e.log("Snapper Mounted"), !0;\n }\n unmount(t, e) {\n return t.document.getElementById(vi)?.remove(), e.log("Snapper Unmounted"), !0;\n }\n};\nRt.moduleName = "snapper";\nlet vt = Rt;\nfunction Qn(r) {\n return (r.document.documentElement.dir || r.document.body.dir).toLowerCase() === "rtl";\n}\nfunction ts(r) {\n return (r.getComputedStyle(r.document.documentElement).writingMode || r.getComputedStyle(r.document.body).writingMode) === "vertical-lr";\n}\nfunction rn(r) {\n return parseInt(\n r.getComputedStyle(\n r.document.documentElement\n ).getPropertyValue("column-count")\n );\n}\nfunction Pi(r) {\n const t = getComputedStyle(r), e = parseFloat(t.paddingTop || "0"), i = parseFloat(t.paddingBottom || "0");\n return r.clientHeight - e - i;\n}\nfunction Ei(r) {\n const t = rn(r);\n if (!t)\n return !1;\n const e = r.document.querySelectorAll("div[id^=\'readium-virtual-page\']");\n for (const h of e)\n h.remove();\n const i = e.length, n = r.document.scrollingElement.scrollWidth, s = r.visualViewport.width, a = Math.round(n / s * t) % t, l = t === 1 || a === 0 ? 0 : t - a;\n if (l > 0)\n for (let h = 0; h < l; h++) {\n const c = r.document.createElement("div");\n c.setAttribute("id", `readium-virtual-page-${h}`), c.dataset.readium = "true", CSS.supports("break-before", "column") ? c.style.breakBefore = "column" : (CSS.supports("break-inside", "avoid-column") && (c.style.breakInside = "avoid-column"), c.style.height = Pi(r.document.documentElement) + "px"), c.innerHTML = "​", r.document.body.appendChild(c);\n }\n return i !== l;\n}\nfunction Be(r) {\n const t = r.document.createElement("style");\n t.appendChild(r.document.createTextNode("*{}")), r.document.body.appendChild(t), r.document.body.removeChild(t);\n}\nfunction es(r) {\n return r < 0.5 ? 2 * r * r : -1 + (4 - 2 * r) * r;\n}\nfunction O(r) {\n const t = r.getSelection();\n t && t.removeAllRanges();\n}\nconst is = [\n "a",\n "area",\n "audio",\n "button",\n "canvas",\n "details",\n "input",\n "label",\n "option",\n "select",\n "submit",\n "textarea",\n "video"\n], ns = ["dialog", "radiogroup", "radio", "menu", "menuitem"];\nfunction Ve(r) {\n return ss(r) ? null : on(r) ? r : r.parentElement ? Ve(r.parentElement) : null;\n}\nfunction ss(r) {\n return r ? r.closest("[inert]") !== null || r.hasAttribute("disabled") : !0;\n}\nfunction on(r) {\n return r ? r.role && ns.includes(r.role) || r.tabIndex >= 0 ? !0 : is.includes(r.nodeName.toLowerCase()) || r.hasAttribute("contenteditable") && r.getAttribute("contenteditable")?.toLowerCase() !== "false" : !1;\n}\nfunction oe(r, t) {\n const e = an(r, r.document.body, t), i = r._readium_cssSelectorGenerator.getCssSelector(e, {\n selectors: ["tag", "id", "class", "nthchild", "nthoftype", "attribute"]\n });\n return new I({\n href: "#",\n type: "application/xhtml+xml",\n locations: new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", i]\n ])\n }),\n text: new rt({\n highlight: e.textContent || void 0\n })\n });\n}\nfunction an(r, t, e) {\n for (var i = 0; i < t.children.length; i++) {\n const n = t.children[i];\n if (!as(n) && rs(r, n, e))\n return os(r, n) ? n : an(r, n, e);\n }\n return t;\n}\nfunction rs(r, t, e) {\n if (t === document.body || t === document.documentElement)\n return !0;\n if (!document || !document.documentElement || !document.body)\n return !1;\n const i = t.getBoundingClientRect();\n return e ? i.bottom > 0 && i.top < r.innerHeight : i.right > 0 && i.left < r.innerWidth;\n}\nfunction os(r, t) {\n const e = t.getBoundingClientRect();\n return e.top >= 0 && e.left >= 0 && e.bottom <= r.innerHeight && e.right <= r.innerWidth;\n}\nfunction as(r) {\n const t = getComputedStyle(r);\n if (t) {\n const e = t.getPropertyValue("display");\n if (e != "block" && e != "list-item" || t.getPropertyValue("opacity") === "0")\n return !0;\n }\n return !1;\n}\nconst ls = {\n maxVelocity: 200,\n // Reasonable default for human-like scrolling (pixels/ms)\n minVariance: 0.01,\n // Default variance threshold\n historySize: 20,\n // Balanced history size for performance\n minDirectionChanges: 0.2,\n // Reasonable default for detecting patterns\n maxConsistentScrolls: 15\n // Balanced threshold for flagging\n}, je = {\n maxVelocity: 200,\n // Extremely fast scrolling (pixels/ms)\n minVariance: 1e-5,\n // Near-perfect consistency\n historySize: 100,\n // Large history window\n minDirectionChanges: 0.1,\n // Only trigger on near-perfect patterns\n maxConsistentScrolls: 20\n // Need many consistent scrolls\n}, ln = {\n maxSelectionsPerSecond: 500,\n minVariance: 50,\n historySize: 20\n}, hs = {\n enabled: !0,\n maxSelectionPercent: 0.1,\n minThreshold: 100,\n absoluteMaxChars: 5e3,\n historySize: 20\n};\nclass ae {\n constructor(t = {}) {\n this.history = [], this.consistentScrollCount = 0, this.options = { ...ls, ...t };\n }\n analyze(t, e, i) {\n if (i <= 0) return !1;\n const n = Math.abs(e) / i, s = Date.now();\n if (this.history.push({\n timestamp: s,\n direction: t,\n velocity: n,\n distance: Math.abs(e)\n }), this.history = this.history.filter((f) => s - f.timestamp < 2e3).slice(-(this.options.historySize || 20)), this.history.length < 3) return !1;\n if (n > this.options.maxVelocity)\n return this.resetAfterDetection(), !0;\n const o = this.history.map((f) => f.velocity), a = this.history.map((f) => f.distance), l = o.reduce((f, w) => f + w, 0) / o.length, h = a.reduce((f, w) => f + w, 0) / a.length, c = o.reduce((f, w) => f + Math.pow(w - l, 2), 0) / o.length, u = a.reduce((f, w) => f + Math.pow(w - h, 2), 0) / a.length;\n if (c < this.options.minVariance && u < h * 0.1) {\n if (this.consistentScrollCount++, this.consistentScrollCount >= (this.options.maxConsistentScrolls || 10))\n return this.resetAfterDetection(), !0;\n } else\n this.consistentScrollCount = Math.max(0, this.consistentScrollCount - 1);\n let p = 0, g = this.history[0].direction;\n for (let f = 1; f < this.history.length; f++)\n this.history[f].direction !== g && (p++, g = this.history[f].direction);\n return p / this.history.length > (this.options.minDirectionChanges || 0.3) ? (this.resetAfterDetection(), !0) : !1;\n }\n resetAfterDetection() {\n this.history = this.history.slice(-3), this.consistentScrollCount = 0;\n }\n clear() {\n this.history = [], this.consistentScrollCount = 0;\n }\n}\nconst Ci = "readium-column-snapper-style", cs = 200, D = class D extends vt {\n constructor() {\n super(...arguments), this.isSnapProtectionEnabled = !1, this.patternAnalyzer = null, this.lastTurnTime = 0, this.rtl = !1, this.shakeTimeout = 0, this.snappingCancelled = !1, this.alreadyScrollLeft = 0, this.overscroll = 0, this.cachedScrollWidth = 0, this.touchState = 0, this.startingX = void 0, this.endingX = void 0, this.onTouchStarter = this.onTouchStart.bind(this), this.onTouchEnder = this.onTouchEnd.bind(this), this.onWidthChanger = this.onWidthChange.bind(this), this.onTouchMover = this.onTouchMove.bind(this);\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n scrollOffset() {\n const t = this.doc().scrollLeft;\n return t !== 0 ? t : this.alreadyScrollLeft;\n }\n snapOffset(t) {\n const e = t + (this.rtl ? -1 : 1);\n return e - e % this.wnd.innerWidth;\n }\n /**\n * Snap a non-negative normalized offset (distance from document start) to\n * the nearest page boundary. Works identically regardless of reading direction.\n */\n snapNormOffset(t) {\n const e = t + 1;\n return e - e % this.wnd.innerWidth;\n }\n /**\n * Normalized scroll position: distance from document start, always in\n * [0, scrollWidth - innerWidth] regardless of reading direction.\n * scrollLeft may be negative depending on the browser — Math.abs() normalizes it.\n */\n normScroll() {\n const t = this.doc().scrollLeft || this.alreadyScrollLeft;\n return this.rtl ? Math.abs(t) : Math.max(0, this.wnd.scrollX > 0 ? this.wnd.scrollX : t);\n }\n reportProgress() {\n const t = this.cachedScrollWidth, e = this.wnd.innerWidth, i = this.normScroll(), n = Math.max(1, t - e), s = Math.max(0, Math.min(1, i / n)), o = Math.max(0, Math.min(1, (i + e) / t));\n this.comms.send("progress", {\n start: s,\n end: o\n });\n }\n shake() {\n if (this.overscroll !== 0 || this.shakeTimeout !== 0) return;\n const t = this.doc(), e = this.normScroll() < 5, i = this.rtl ? e ? "readium-bounce-r" : "readium-bounce-l" : "readium-bounce-r";\n t.classList.add(i);\n const n = this.scrollOffset();\n this.shakeTimeout = this.wnd.setTimeout(() => {\n t.classList.remove(i), this.shakeTimeout = 0, this.doc().scrollLeft = n;\n }, 150);\n }\n // We have to cache this because during overscroll (transform, or left) the width is incorrect due to browser\n takeOverSnap() {\n this.snappingCancelled = !0, this.clearTouches();\n const t = this.doc();\n this.overscroll = t.style.transform?.length > 12 ? parseFloat(t.style.transform.slice(12).split("px")[0]) : 0;\n }\n // Snaps the current offset to the page width.\n snapCurrentOffset(t = !1, e = !1) {\n const i = this.doc(), n = rn(this.wnd), s = this.cachedScrollWidth - this.wnd.innerWidth, o = Math.min(Math.max(0, this.normScroll()), s), a = this.dragOffset(), l = this.rtl ? -a : a, h = this.wnd.innerWidth / 3 * (l > 0 ? 2 : 1), c = Math.min(s, Math.max(0, this.snapNormOffset(o + h))), u = this.rtl ? -c : c, p = this.rtl ? -o : o, g = u > p ? "right" : "left";\n if (this.checkSuspiciousSnap(g, Math.abs(u - p)), t && u !== p) {\n this.snappingCancelled = !1;\n const d = (R, Y, lt, ht) => lt > ht ? Y : R + (Y - R) * es(lt / ht), f = cs * n;\n let w;\n const P = (R) => {\n if (this.snappingCancelled) return;\n w || (w = R);\n const Y = R - w, lt = d(this.overscroll, 0, Y, f), ht = d(p, u, Y, f);\n i.scrollLeft = ht, this.overscroll !== 0 && (i.style.transform = `translate3d(${-lt}px, 0px, 0px)`), Y < f ? this.wnd.requestAnimationFrame(P) : (this.clearTouches(), i.style.removeProperty("transform"), i.scrollLeft = u, e || this.reportProgress());\n };\n this.wnd.requestAnimationFrame(P);\n } else\n i.style.removeProperty("transform"), this.wnd.requestAnimationFrame(() => {\n i.scrollLeft = u, this.clearTouches(), e || this.reportProgress();\n });\n }\n dragOffset() {\n return (this.startingX ?? 0) - (this.endingX ?? 0);\n }\n clearTouches() {\n this.startingX = void 0, this.endingX = void 0, this.overscroll = 0;\n }\n onTouchStart(t) {\n switch (t.stopPropagation(), this.takeOverSnap(), t.touches.length) {\n case 1:\n break;\n case 2:\n this.onTouchEnd(t);\n return;\n default: {\n this.onTouchEnd(t), this.comms.send("tap_more", t.touches.length);\n return;\n }\n }\n this.startingX = t.touches[0].clientX, this.alreadyScrollLeft = this.doc().scrollLeft, this.touchState = 1;\n }\n onTouchEnd(t) {\n if (this.touchState === 2) {\n const e = this.dragOffset(), i = this.normScroll(), n = this.cachedScrollWidth - this.wnd.innerWidth, s = this.rtl ? -e : e;\n this.cachedScrollWidth <= this.wnd.innerWidth ? (this.reportProgress(), s > 5 && this.comms.send("no_more", void 0), s < -5 && this.comms.send("no_less", void 0)) : i < 5 && s < 5 ? (this.alreadyScrollLeft = 0, this.comms.send("no_less", void 0)) : n - i < 5 && s > 5 && (this.alreadyScrollLeft = this.rtl ? -n : n, this.comms.send("no_more", void 0)), this.snapCurrentOffset(!0), this.comms.send("swipe", e);\n }\n this.touchState = 0;\n }\n onWidthChange() {\n this.cachedScrollWidth = this.doc().scrollWidth, this.comms.ready && this.snapCurrentOffset();\n }\n onTouchMove(t) {\n if (this.touchState === 0) return;\n this.touchState === 1 && (this.touchState = 2, O(this.wnd)), this.endingX = t.touches[0].clientX;\n const e = this.dragOffset(), i = this.alreadyScrollLeft + e, n = this.rtl ? -(this.cachedScrollWidth - this.wnd.innerWidth) : 0, s = this.rtl ? 0 : this.cachedScrollWidth - this.wnd.innerWidth;\n i < n ? (this.overscroll = i, this.doc().style.transform = `translate3d(${-this.overscroll}px, 0px, 0px)`) : i > s ? (this.overscroll = i, this.doc().style.transform = `translate3d(${-i}px, 0px, 0px)`) : (this.overscroll = 0, this.doc().style.removeProperty("transform"), this.doc().scrollLeft = i);\n }\n enableSnapProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new ae({\n maxVelocity: this.wnd.innerWidth,\n // page width\n minVariance: 0.1,\n // Allow for some variation in swipe speed\n historySize: 5,\n // Fewer samples needed for swipe detection\n maxConsistentScrolls: 3,\n // Lower threshold for consistent scrolling\n minDirectionChanges: 0.3\n // Require more direction changes\n }), this.isSnapProtectionEnabled = !0, this.comms?.log("Snap protection enabled"));\n }\n checkSuspiciousSnap(t, e) {\n if (!this.isSnapProtectionEnabled || !this.patternAnalyzer) return;\n const i = Date.now(), n = i - (this.lastTurnTime || i);\n this.lastTurnTime = i, this.patternAnalyzer.analyze(t, e, n) && this.comms?.send("content_protection", {\n type: "suspicious_snapping",\n timestamp: Date.now(),\n event: null\n });\n }\n mount(t, e) {\n if (this.wnd = t, this.comms = e, this.rtl = Qn(t), !super.mount(t, e)) return !1;\n t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "paginated");\n const i = t.document.createElement("style");\n i.dataset.readium = "true", i.id = Ci, i.textContent = `\n @keyframes readium-bounce-l-animation {\n 0%, 100% {transform: translate3d(0, 0, 0);}\n 50% {transform: translate3d(-50px, 0, 0);}\n }\n\n @keyframes readium-bounce-r-animation {\n 0%, 100% {transform: translate3d(0, 0, 0);}\n 50% {transform: translate3d(50px, 0, 0);}\n }\n\n .readium-bounce-l {\n animation: readium-bounce-l-animation 150ms ease-out 1;\n }\n\n .readium-bounce-r {\n animation: readium-bounce-r-animation 150ms ease-out 1;\n }\n\n html {\n overflow: hidden;\n }\n\n body {\n -ms-overflow-style: none; /* for Internet Explorer, Edge */\n }\n\n * {\n scrollbar-width: none; /* for Firefox */\n }\n\n body::-webkit-scrollbar {\n display: none; /* for Chrome, Safari, and Opera */\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n t.requestAnimationFrame(() => {\n t && Ei(t);\n }), this.onWidthChange();\n }), this.resizeObserver.observe(t.document.body), this.mutationObserver = new MutationObserver((o) => {\n for (const a of o)\n if (a.target === this.wnd.document.documentElement) {\n const l = a.oldValue, h = a.target.getAttribute("style"), c = /transform\\s*:\\s*([^;]+)/, u = l?.match(c), p = h?.match(c);\n (!u && !p || u && !p || u && p && u[1] !== p[1]) && (t.requestAnimationFrame(() => {\n t && Ei(t);\n }), this.onWidthChange());\n } else\n t.requestAnimationFrame(() => this.cachedScrollWidth = this.doc().scrollWidth);\n }), t.frameElement && this.mutationObserver.observe(t.frameElement, { attributes: !0, attributeFilter: ["style"] }), this.mutationObserver.observe(t.document, { attributes: !0, attributeFilter: ["style"] }), this.mutationObserver.observe(t.document.documentElement, { attributes: !0, attributeFilter: ["style"] }), e.register("scroll_protection", D.moduleName, (o, a) => {\n this.enableSnapProtection(), a(!0);\n });\n const n = (o) => {\n const a = this.doc().scrollLeft;\n return this.doc().scrollLeft = this.snapOffset(o), a !== this.doc().scrollLeft;\n }, s = (o) => {\n const a = this.doc().scrollLeft, l = this.snapNormOffset(Math.max(0, Math.min(this.cachedScrollWidth - t.innerWidth, o)));\n return this.doc().scrollLeft = -l, a !== this.doc().scrollLeft;\n };\n return t.addEventListener("orientationchange", this.onWidthChanger), t.addEventListener("resize", this.onWidthChanger), t.requestAnimationFrame(() => this.cachedScrollWidth = this.doc().scrollWidth), e.register("go_progression", D.moduleName, (o, a) => {\n const l = o;\n if (l < 0 || l > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n const c = (this.cachedScrollWidth - t.innerWidth) * l;\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(c) : this.doc().scrollLeft = this.snapOffset(c), this.reportProgress(), O(this.wnd), a(!0);\n });\n }), e.register("go_id", D.moduleName, (o, a) => {\n const l = t.document.getElementById(o);\n if (!l) {\n a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(l.getBoundingClientRect().left + t.scrollX) : this.doc().scrollLeft = this.snapOffset(l.getBoundingClientRect().left + t.scrollX), this.reportProgress(), O(this.wnd), a(!0);\n });\n }), e.register("go_text", D.moduleName, (o, a) => {\n let l;\n Array.isArray(o) && (o.length > 1 && (l = o[1]), o = o[0]);\n const h = rt.deserialize(o), c = It(this.wnd.document, new I({\n href: t.location.href,\n type: "text/html",\n text: h,\n locations: l ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", l]\n ])\n }) : void 0\n }));\n if (!c) {\n a(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.rtl ? this.doc().scrollLeft = -this.snapNormOffset(c.getBoundingClientRect().left + t.scrollX) : this.doc().scrollLeft = this.snapOffset(c.getBoundingClientRect().left + t.scrollX), this.reportProgress(), O(this.wnd), a(!0);\n });\n }), e.register("go_end", D.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let l;\n if (this.rtl ? l = -this.snapNormOffset(this.cachedScrollWidth - t.innerWidth) : l = this.snapOffset(this.cachedScrollWidth), this.doc().scrollLeft === l) return a(!1);\n this.doc().scrollLeft = l, this.reportProgress(), O(this.wnd), a(!0);\n });\n }), e.register("go_start", D.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n if (this.doc().scrollLeft === 0) return a(!1);\n this.doc().scrollLeft = 0, this.reportProgress(), O(this.wnd), a(!0);\n });\n }), e.register("go_prev", D.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let l;\n this.rtl ? l = s(this.normScroll() - t.innerWidth) : l = n(t.scrollX - t.innerWidth), this.reportProgress(), l && (O(this.wnd), this.checkSuspiciousSnap("left", this.wnd.innerWidth)), a(l);\n });\n }), e.register("go_next", D.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth;\n let l;\n this.rtl ? l = s(this.normScroll() + t.innerWidth) : l = n(t.scrollX + t.innerWidth), this.reportProgress(), l && (O(this.wnd), this.checkSuspiciousSnap("right", this.wnd.innerWidth)), a(l);\n });\n }), e.register("unfocus", D.moduleName, (o, a) => {\n this.snappingCancelled = !0, O(this.wnd), a(!0);\n }), e.register("shake", D.moduleName, (o, a) => {\n this.shake(), a(!0);\n }), e.register("focus", D.moduleName, (o, a) => {\n this.wnd.requestAnimationFrame(() => {\n this.cachedScrollWidth = this.doc().scrollWidth, this.snapCurrentOffset(!1, !0), this.reportProgress(), a(!0);\n });\n }), e.register("first_visible_locator", D.moduleName, (o, a) => {\n const l = oe(t, !1);\n this.comms.send("first_visible_locator", l.serialize()), a(!0);\n }), t.addEventListener("touchstart", this.onTouchStarter, { passive: !0 }), t.addEventListener("touchend", this.onTouchEnder, { passive: !0 }), t.addEventListener("touchmove", this.onTouchMover, { passive: !0 }), t.document.addEventListener("touchstart", () => {\n }), e.log("ColumnSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return this.snappingCancelled = !0, e.unregisterAll(D.moduleName), this.resizeObserver.disconnect(), this.mutationObserver.disconnect(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isSnapProtectionEnabled = !1), t.removeEventListener("touchstart", this.onTouchStarter), t.removeEventListener("touchend", this.onTouchEnder), t.removeEventListener("touchmove", this.onTouchMover), t.removeEventListener("orientationchange", this.onWidthChanger), t.removeEventListener("resize", this.onWidthChanger), t.document.getElementById(Ci)?.remove(), e.log("ColumnSnapper Unmounted"), super.unmount(t, e);\n }\n};\nD.moduleName = "column_snapper";\nlet Ce = D;\nconst _i = "readium-scroll-snapper-style", U = class U extends vt {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce = null, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollTop = this.doc().scrollTop, this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = this.doc().scrollTop, i = e - this.lastScrollTop;\n if (this.lastScrollTop = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const n = Date.now(), s = n - (this.lastScrollTime || n);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n i > 0 ? "down" : "up",\n Math.abs(i),\n s\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "down" : "up",\n targetElement: a\n });\n }\n this.lastScrollTime = n;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = Math.ceil(this.doc().scrollTop), e = this.doc().scrollHeight, i = this.wnd.innerHeight, n = Math.max(0, Math.min(1, t / e)), s = Math.max(0, Math.min(1, (t + i) / e));\n this.comms.send("progress", {\n start: n,\n end: s\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new ae(je), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "scrolling");\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = _i, i.textContent = `\n * {\n scrollbar-width: none; /* for Firefox */\n }\n\n body::-webkit-scrollbar {\n display: none; /* for Chrome, Safari, and Opera */\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", U.moduleName, () => {\n Be(this.wnd);\n const n = this.doc().scrollTop;\n n > 1 ? this.doc().scrollTop = n - 1 : this.doc().scrollTop = n + 1, this.doc().scrollTop = n;\n }), e.register("go_progression", U.moduleName, (n, s) => {\n const o = n;\n if (o < 0 || o > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = this.doc().offsetHeight * o, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_id", U.moduleName, (n, s) => {\n const o = t.document.getElementById(n);\n if (!o) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = o.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_text", U.moduleName, (n, s) => {\n let o;\n Array.isArray(n) && (n.length > 1 && (o = n[1]), n = n[0]);\n const a = rt.deserialize(n), l = It(this.wnd.document, new I({\n href: t.location.href,\n type: "text/html",\n text: a,\n locations: o ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", o]\n ])\n }) : void 0\n }));\n if (!l) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = l.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_start", U.moduleName, (n, s) => {\n if (this.doc().scrollTop === 0) return s(!1);\n this.doc().scrollTop = 0, this.reportProgress(), s(!0);\n }), e.register("go_end", U.moduleName, (n, s) => {\n if (this.doc().scrollTop === this.doc().scrollHeight - this.doc().offsetHeight) return s(!1);\n this.doc().scrollTop = this.doc().scrollHeight - this.doc().offsetHeight, this.reportProgress(), s(!0);\n }), e.register("unfocus", U.moduleName, (n, s) => {\n O(this.wnd), s(!0);\n }), e.register("scroll_protection", U.moduleName, (n, s) => {\n this.enableScrollProtection(), s(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], U.moduleName, (n, s) => s(!1)), e.register("focus", U.moduleName, (n, s) => {\n this.reportProgress(), s(!0);\n }), e.register("first_visible_locator", U.moduleName, (n, s) => {\n const o = oe(t, !0);\n this.comms.send("first_visible_locator", o.serialize()), s(!0);\n }), e.log("ScrollSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(U.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), t.document.getElementById(_i)?.remove(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("ScrollSnapper Unmounted"), !0;\n }\n};\nU.moduleName = "scroll_snapper";\nlet _e = U;\nconst H = class H extends vt {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce = null, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollTop = this.doc().scrollTop, this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = this.doc().scrollTop, i = e - this.lastScrollTop;\n if (this.lastScrollTop = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const n = Date.now(), s = n - (this.lastScrollTime || n);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n i > 0 ? "down" : "up",\n Math.abs(i),\n s\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "down" : "up",\n targetElement: a\n });\n }\n this.lastScrollTime = n;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = Math.ceil(this.doc().scrollTop), e = this.doc().scrollHeight, i = this.wnd.innerHeight, n = Math.max(0, Math.min(1, t / e)), s = Math.max(0, Math.min(1, (t + i) / e));\n this.comms.send("progress", {\n start: n,\n end: s\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new ae(je), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollTop = 0, this.isResizing = !1, this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", H.moduleName, () => {\n Be(this.wnd);\n const i = this.doc().scrollTop;\n i > 1 ? this.doc().scrollTop = i - 1 : this.doc().scrollTop = i + 1, this.doc().scrollTop = i;\n }), e.register("go_progression", H.moduleName, (i, n) => {\n const s = i;\n if (s < 0 || s > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), n(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = this.doc().offsetHeight * s, this.reportProgress(), O(this.wnd), n(!0);\n });\n }), e.register("go_id", H.moduleName, (i, n) => {\n const s = t.document.getElementById(i);\n if (!s) {\n n(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = s.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), O(this.wnd), n(!0);\n });\n }), e.register("go_text", H.moduleName, (i, n) => {\n let s;\n Array.isArray(i) && (i.length > 1 && (s = i[1]), i = i[0]);\n const o = rt.deserialize(i), a = It(this.wnd.document, new I({\n href: t.location.href,\n type: "text/html",\n text: o,\n locations: s ? new C({\n otherLocations: /* @__PURE__ */ new Map([\n ["cssSelector", s]\n ])\n }) : void 0\n }));\n if (!a) {\n n(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollTop = a.getBoundingClientRect().top + t.scrollY - t.innerHeight / 2, this.reportProgress(), O(this.wnd), n(!0);\n });\n }), e.register("go_start", H.moduleName, (i, n) => {\n if (this.doc().scrollTop === 0) return n(!1);\n this.doc().scrollTop = 0, this.reportProgress(), n(!0);\n }), e.register("go_end", H.moduleName, (i, n) => {\n if (this.doc().scrollTop === this.doc().scrollHeight - this.doc().offsetHeight) return n(!1);\n this.doc().scrollTop = this.doc().scrollHeight - this.doc().offsetHeight, this.reportProgress(), n(!0);\n }), e.register("unfocus", H.moduleName, (i, n) => {\n O(this.wnd), n(!0);\n }), e.register("scroll_protection", H.moduleName, (i, n) => {\n this.enableScrollProtection(), n(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], H.moduleName, (i, n) => n(!1)), e.register("focus", H.moduleName, (i, n) => {\n this.reportProgress(), n(!0);\n }), e.register("first_visible_locator", H.moduleName, (i, n) => {\n const s = oe(t, !0);\n e.send("first_visible_locator", s.serialize()), n(!0);\n }), e.log("WebPubSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(H.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("WebPubSnapper Unmounted"), !0;\n }\n};\nH.moduleName = "webpub_snapper";\nlet Le = H;\nclass ds {\n constructor(t, e) {\n this.window = t, this.copyHistory = [], this.lastSelectionLength = 0, this.lastSelectionTime = 0, this.options = e;\n }\n cleanupOldHistory(t) {\n this.copyHistory = this.copyHistory.filter(\n (i) => t - i.timestamp < 1e4\n ), this.copyHistory.length > this.options.historySize && (this.copyHistory = this.copyHistory.slice(-this.options.historySize));\n }\n isSuspiciousPattern(t) {\n return this.copyHistory.length < 3 ? !1 : this.copyHistory.filter(\n (n) => t - n.timestamp < 2e3\n // Last 2 seconds\n ).length >= 3 ? !0 : this.copyHistory.slice().sort((n, s) => n.timestamp - s.timestamp).every((n, s, o) => s === 0 ? !0 : n.length > o[s - 1].length * 1.5);\n }\n shouldAllowCopy(t) {\n if (!this.options.enabled) return !0;\n const e = this.window.getSelection();\n if (!e) return !0;\n const n = e.toString().length, s = this.window.document.body.innerText.length, o = Date.now();\n if (this.cleanupOldHistory(o), n < this.options.minThreshold)\n return this.copyHistory.push({\n timestamp: o,\n length: n,\n wasBlocked: !1\n }), !0;\n const l = o - this.lastSelectionTime < 100 && n > this.lastSelectionLength * 1.5, h = Math.min(\n s * this.options.maxSelectionPercent,\n this.options.absoluteMaxChars\n ), c = this.isSuspiciousPattern(o), u = n > h || l || c;\n return this.copyHistory.push({\n timestamp: o,\n length: n,\n wasBlocked: u\n }), u ? (t?.preventDefault(), !1) : (this.lastSelectionLength = n, this.lastSelectionTime = o, !0);\n }\n destroy() {\n this.lastSelectionLength = 0, this.lastSelectionTime = 0, this.copyHistory = [], this.options.enabled = !1;\n }\n}\nclass us {\n constructor(t = ln) {\n this.options = t, this.events = [], this.selectionStartTime = 0, this.lastSelectionTime = 0, this.lastSelectionPosition = 0, this.selectionPatterns = [], this.lastSelectedText = "";\n }\n analyze(t) {\n if (!t)\n return this.clear(), !1;\n const e = t.toString();\n if (e.length === 0)\n return this.clear(), !1;\n if (t.type !== "Range" || !t.rangeCount)\n return !1;\n const i = Date.now();\n if (e.length <= 50 || e === this.lastSelectedText)\n return !1;\n if (this.selectionStartTime === 0)\n return this.selectionStartTime = i, this.lastSelectedText = e, !1;\n if (i - this.selectionStartTime < 500)\n return !1;\n i - this.lastSelectionTime > 1e3 && (this.lastSelectionTime = i), this.selectionStartTime === 0 && (this.selectionStartTime = i), this.lastSelectedText = e;\n const s = this.analyzeSelectionPattern(t, i);\n return this.cleanup(i), s;\n }\n analyzeSelectionPattern(t, e) {\n if (!t.rangeCount) return !1;\n const i = t.getRangeAt(0), n = i.toString(), s = (e - this.selectionStartTime) / 1e3;\n if (n.length / Math.max(1, s) > this.options.maxSelectionsPerSecond) return !0;\n const a = i.startOffset, l = Math.abs(a - this.lastSelectionPosition);\n return this.selectionPatterns.push(l), this.selectionPatterns.length > this.options.historySize && (this.selectionPatterns.shift(), this.calculateVariance(this.selectionPatterns) < this.options.minVariance) ? !0 : (this.lastSelectionPosition = a, !1);\n }\n calculateVariance(t) {\n if (t.length === 0) return 0;\n const e = t.reduce((i, n) => i + n, 0) / t.length;\n return t.reduce((i, n) => i + Math.pow(n - e, 2), 0) / t.length;\n }\n cleanup(t) {\n this.events = this.events.filter((e) => t - e.timestamp <= 1e3);\n }\n clear() {\n this.events = [], this.selectionStartTime = 0, this.lastSelectionTime = 0, this.lastSelectionPosition = 0, this.selectionPatterns = [], this.lastSelectedText = "";\n }\n}\nclass hn {\n /**\n * Checks if the given keyboard event matches any of the provided key combinations\n */\n match(t, e) {\n for (const i of e)\n if (this.matchesCombo(t, i))\n return !0;\n return !1;\n }\n matchesCombo(t, e) {\n return t.keyCode === e.keyCode && this.matchesModifier(t.ctrlKey, e.ctrl) && this.matchesModifier(t.shiftKey, e.shift) && this.matchesModifier(t.altKey, e.alt) && this.matchesModifier(t.metaKey, e.meta);\n }\n matchesModifier(t, e) {\n return e === void 0 ? !t : t === e;\n }\n /**\n * Creates an event handler that will call the provided handler when any of the key combinations match\n */\n createKeyHandler(t, e) {\n return (i) => {\n this.match(i, t) && (i.preventDefault(), i.stopPropagation(), e(i));\n };\n }\n /**\n * Creates a standardized activity event for keyboard shortcuts\n */\n createActivityEvent(t, e, i, n) {\n let s, o;\n if (n) {\n const a = n.getSelection(), l = a?.toString() || "", c = (l && a?.rangeCount ? a.getRangeAt(0)?.getClientRects() : null)?.[0];\n c && l && (s = {\n text: l,\n x: c.x,\n y: c.y,\n width: c.width,\n height: c.height\n });\n const u = n.document.activeElement;\n u && u !== n.document.body && (o = Ve(u)?.outerHTML);\n }\n return {\n type: e,\n timestamp: Date.now(),\n key: t.key,\n code: t.code,\n keyCode: t.keyCode,\n ctrlKey: t.ctrlKey,\n altKey: t.altKey,\n shiftKey: t.shiftKey,\n metaKey: t.metaKey,\n targetFrameSrc: i,\n selectedText: s,\n interactiveElement: o\n };\n }\n /**\n * Creates handlers for keyboard shortcuts with centralized activity event dispatch\n */\n createKeyboardHandlers(t, e, i, n) {\n const s = [];\n return e.forEach((o) => {\n s.push(...o.keyCombos.map((a) => ({\n ...a,\n handler: (l) => {\n const h = o.type, c = this.createActivityEvent(l, h, t, n);\n i(c);\n }\n })));\n }), s;\n }\n /**\n * Creates a unified keyboard event handler that processes all shortcuts\n */\n createUnifiedHandler(t, e, i, n) {\n const s = this.createKeyboardHandlers(t, e, i, n);\n return (o) => {\n for (const a of s)\n if (this.match(o, [a])) {\n const l = a.suppressOnInteractiveElement;\n if (l) {\n const h = (n?.document ?? document).activeElement;\n if (Array.isArray(l) ? l.some((c) => h?.matches(c)) : on(h)) return;\n }\n o.preventDefault(), o.stopPropagation(), a.handler(o);\n return;\n }\n };\n }\n}\nconst yt = class yt extends Et {\n constructor() {\n super(...arguments), this.configApplied = !1, this.cleanupCallbacks = [], this.pointerMoved = !1, this.isContextMenuEnabled = !1, this.isDragAndDropEnabled = !1, this.isSelectionMonitoringEnabled = !1, this.isBulkCopyProtectionEnabled = !1, this.selectionAnalyzer = null, this.currentSelection = null, this.bulkCopyProtector = null, this.keyManager = new hn(), this.keyDownHandler = null, this.preventBulkCopy = (t) => {\n if (!this.isBulkCopyProtectionEnabled || !this.bulkCopyProtector)\n return !0;\n if (!this.bulkCopyProtector.shouldAllowCopy(t)) {\n t.preventDefault();\n const e = this.wnd.getSelection(), i = e?.toString() || "", s = (i ? e?.getRangeAt(0)?.getClientRects() : null)?.[0], o = {\n type: "bulk_copy",\n timestamp: Date.now(),\n clipboardTypes: t.clipboardData?.types ? [...t.clipboardData.types] : [],\n selectedText: s ? {\n text: i,\n x: s.x,\n y: s.y,\n width: s.width,\n height: s.height\n } : void 0,\n selectionLength: i.length,\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", o), !1;\n }\n return !0;\n }, this.handleSelection = (t) => {\n if (!this.isSelectionMonitoringEnabled || !this.wnd || !this.selectionAnalyzer)\n return;\n const e = this.wnd.getSelection();\n if (e) {\n if (this.currentSelection = e.toString(), this.selectionAnalyzer.analyze(e) && this.currentSelection) {\n const n = this.wnd.getSelection(), s = n?.toString() || "", a = (s && n?.rangeCount ? n.getRangeAt(0)?.getClientRects() : null)?.[0], l = {\n type: "suspicious_selection",\n timestamp: Date.now(),\n selectionLength: s.length,\n selectedText: {\n text: s,\n x: a?.x ?? 0,\n y: a?.y ?? 0,\n width: a?.width ?? 0,\n height: a?.height ?? 0\n },\n eventType: t?.type || "selectionchange",\n targetFrameSrc: this.wnd.location.href\n };\n this.comms?.send("content_protection", l);\n }\n } else\n this.currentSelection = null;\n }, this.onDragOver = (t) => {\n this.isDragAndDropEnabled && (t.preventDefault(), t.stopPropagation());\n }, this.onDragStart = (t) => {\n if (this.isDragAndDropEnabled) {\n t.preventDefault();\n const e = {\n type: "drag_detected",\n timestamp: Date.now(),\n dataTransferTypes: t.dataTransfer?.types ? [...t.dataTransfer.types] : [],\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", e), !1;\n } else\n return !0;\n }, this.onDrop = (t) => {\n if (this.isDragAndDropEnabled) {\n t.preventDefault();\n const e = t.dataTransfer, i = {\n type: "drop_detected",\n timestamp: Date.now(),\n dataTransferTypes: e?.types ? [...e.types] : [],\n fileCount: e?.files?.length || 0,\n targetFrameSrc: this.wnd.location.href\n };\n return this.comms?.send("content_protection", i), !1;\n } else\n return !0;\n }, this.onContext = (t) => {\n if (this.isContextMenuEnabled) {\n t.preventDefault();\n const e = this.wnd.getSelection(), i = e?.toString() || "", s = (i && e?.rangeCount ? e.getRangeAt(0)?.getClientRects() : null)?.[0], o = {\n timestamp: Date.now(),\n clientX: t.clientX,\n clientY: t.clientY,\n ...s && {\n selectedText: {\n text: i,\n x: s.x,\n y: s.y,\n width: s.width,\n height: s.height\n }\n },\n targetFrameSrc: this.wnd.location.href\n };\n this.comms?.send("context_menu", o);\n }\n }, this.onPointerUp = this.onPointUp.bind(this), this.onPointerMove = this.onPointMove.bind(this), this.onPointerDown = this.onPointDown.bind(this), this.onClicker = this.onClick.bind(this);\n }\n addContextMenuPrevention() {\n this.isContextMenuEnabled || !this.wnd || (this.wnd.document.addEventListener("contextmenu", this.onContext), this.isContextMenuEnabled = !0);\n }\n removeContextMenuPrevention() {\n !this.isContextMenuEnabled || !this.wnd || (this.wnd.document.removeEventListener("contextmenu", this.onContext), this.isContextMenuEnabled = !1);\n }\n addDragAndDropPrevention() {\n this.isDragAndDropEnabled || !this.wnd || (this.wnd.document.addEventListener("dragstart", this.onDragStart), this.wnd.document.addEventListener("dragover", this.onDragOver), this.wnd.document.addEventListener("drop", this.onDrop), this.isDragAndDropEnabled = !0);\n }\n removeDragAndDropPrevention() {\n !this.isDragAndDropEnabled || !this.wnd || (this.wnd.document.removeEventListener("dragstart", this.onDragStart), this.wnd.document.removeEventListener("dragover", this.onDragOver), this.wnd.document.removeEventListener("drop", this.onDrop), this.isDragAndDropEnabled = !1);\n }\n enableKeyboardPeripherals(t = []) {\n this.disableKeyboardPeripherals();\n const e = (i) => {\n this.comms?.send("keyboard_peripherals", i);\n };\n this.keyDownHandler = this.keyManager.createUnifiedHandler(this.wnd.location.href, t, e, this.wnd), this.wnd && this.wnd.document.addEventListener("keydown", this.keyDownHandler, {\n capture: !0\n });\n }\n disableKeyboardPeripherals() {\n this.wnd && this.keyDownHandler && (this.wnd.document.removeEventListener("keydown", this.keyDownHandler, {\n capture: !0\n }), this.keyDownHandler = null);\n }\n addBulkCopyProtection(t = {}) {\n if (this.isBulkCopyProtectionEnabled || !this.wnd) return;\n const e = hs, i = t ? { ...e, ...t } : e;\n this.bulkCopyProtector = new ds(this.wnd, i), this.wnd.document.addEventListener("copy", this.preventBulkCopy, !0), this.wnd.document.addEventListener("cut", this.preventBulkCopy, !0), this.isBulkCopyProtectionEnabled = !0;\n }\n removeBulkCopyProtection() {\n !this.isBulkCopyProtectionEnabled || !this.wnd || (this.wnd.document.removeEventListener("copy", this.preventBulkCopy, !0), this.wnd.document.removeEventListener("cut", this.preventBulkCopy, !0), this.bulkCopyProtector?.destroy(), this.bulkCopyProtector = null, this.isBulkCopyProtectionEnabled = !1);\n }\n addSelectionMonitoring(t) {\n if (this.isSelectionMonitoringEnabled || !this.wnd) return;\n const e = t || ln;\n this.selectionAnalyzer = new us(e), this.wnd.document.addEventListener("selectionchange", this.handleSelection), this.isSelectionMonitoringEnabled = !0;\n }\n removeSelectionMonitoring() {\n !this.isSelectionMonitoringEnabled || !this.wnd || (this.wnd.document.removeEventListener("selectionchange", this.handleSelection), this.selectionAnalyzer?.clear(), this.selectionAnalyzer = null, this.isSelectionMonitoringEnabled = !1);\n }\n onPointUp(t) {\n const e = this.wnd.getSelection();\n if (e && e.toString()?.length > 0) {\n const n = e.getRangeAt(0)?.getClientRects();\n if (!n || n.length === 0)\n return;\n const s = n[0], o = {\n text: e.toString(),\n x: s.x,\n y: s.y,\n width: s.width,\n height: s.height,\n targetFrameSrc: this.wnd?.location?.href\n };\n this.comms.send("text_selected", o);\n }\n if (this.pointerMoved) {\n this.pointerMoved = !1;\n return;\n }\n if (!e?.isCollapsed || !t.isPrimary) return;\n const i = this.wnd.devicePixelRatio;\n t.preventDefault(), this.comms.send(t.pointerType === "touch" ? "tap" : "click", {\n defaultPrevented: t.defaultPrevented,\n x: t.clientX * i,\n y: t.clientY * i,\n targetFrameSrc: this.wnd.location.href,\n targetElement: t.target.outerHTML,\n interactiveElement: Ve(t.target)?.outerHTML,\n cssSelector: this.wnd._readium_cssSelectorGenerator.getCssSelector(t.target)\n }), this.pointerMoved = !1;\n }\n onPointMove(t) {\n if (t.movementY !== void 0 && t.movementX !== void 0) {\n (Math.abs(t.movementX) > 1 || Math.abs(t.movementY) > 1) && (this.pointerMoved = !0);\n return;\n }\n this.pointerMoved = !0;\n }\n onPointDown() {\n this.pointerMoved = !1;\n }\n onClick(t) {\n if (t.preventDefault(), !t.isTrusted) {\n const e = new PointerEvent("pointerup", {\n isPrimary: !0,\n pointerType: "mouse",\n // Not really a better choice than this\n clientX: t.clientX,\n clientY: t.clientY\n });\n Object.defineProperty(e, "target", { writable: !1, value: t.target }), Object.defineProperty(e, "defaultPrevented", { writable: !1, value: t.defaultPrevented }), this.onPointUp(e);\n }\n }\n registerProtectionHandlers() {\n this.comms?.register("peripherals_protection", yt.moduleName, (t, e) => {\n const i = t;\n if (!this.configApplied) {\n if (this.configApplied = !0, i.monitorSelection) {\n const n = typeof i.monitorSelection == "boolean" ? void 0 : i.monitorSelection;\n this.addSelectionMonitoring(n), this.comms?.log("Selection monitoring enabled");\n }\n typeof i.protectCopy == "object" ? (this.addBulkCopyProtection({\n enabled: !0,\n ...i.protectCopy\n }), this.comms?.log("Copy protection enabled (limited)")) : i.protectCopy === !0 && (this.addBulkCopyProtection({\n enabled: !0,\n maxSelectionPercent: 0,\n minThreshold: 0,\n absoluteMaxChars: 0\n }), this.comms?.log("Copy protection enabled")), i.disableContextMenu && (this.addContextMenuPrevention(), this.comms?.log("Context menu protection enabled")), i.disableDragAndDrop && (this.addDragAndDropPrevention(), this.comms?.log("Drag and drop protection enabled"));\n }\n e(!0);\n }), this.comms?.register("keyboard_peripherals", yt.moduleName, (t, e) => {\n const i = t;\n i && i.length > 0 && (this.enableKeyboardPeripherals(i), this.comms?.log(`Keyboard peripherals enabled: ${i.map((n) => n.type).join(", ")}`)), e(!0);\n });\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.registerProtectionHandlers(), t.document.addEventListener("pointerdown", this.onPointerDown), t.document.addEventListener("pointerup", this.onPointerUp), t.document.addEventListener("pointermove", this.onPointerMove), t.document.addEventListener("click", this.onClicker), e.log("Peripherals Mounted"), !0;\n }\n unmount(t, e) {\n return this.removeBulkCopyProtection(), this.removeSelectionMonitoring(), this.removeContextMenuPrevention(), this.removeDragAndDropPrevention(), this.disableKeyboardPeripherals(), this.cleanupCallbacks.forEach((i) => i()), this.cleanupCallbacks = [], t.document.removeEventListener("pointerdown", this.onPointerDown), t.document.removeEventListener("pointerup", this.onPointerUp), t.document.removeEventListener("pointermove", this.onPointerMove), t.document.removeEventListener("click", this.onClicker), e.unregisterAll(yt.moduleName), this.configApplied = !1, e.log("Peripherals Unmounted"), !0;\n }\n};\nyt.moduleName = "peripherals";\nlet xe = yt;\nconst At = class At extends Et {\n constructor() {\n super(...arguments), this.mediaPlayingCount = 0, this.allAnimations = /* @__PURE__ */ new Set();\n }\n wndOnErr(t) {\n this.comms?.send("error", {\n message: t.message,\n filename: t.filename,\n lineno: t.lineno,\n colno: t.colno\n });\n }\n unblock(t) {\n for (t._readium_blockEvents = !1; t._readium_blockedEvents?.length > 0; ) {\n const e = t._readium_blockedEvents.shift();\n switch (e[0]) {\n case 0:\n Reflect.apply(e[1], e[2], e[3]);\n break;\n case 1:\n const i = e[1], n = e[2];\n t.removeEventListener(i.type, t._readium_eventBlocker, !0);\n const s = new Event(i.type, {\n bubbles: i.bubbles,\n cancelable: i.cancelable\n });\n n ? n.dispatchEvent(s) : t.dispatchEvent(s);\n break;\n }\n }\n }\n onMediaPlayEvent() {\n this.mediaPlayingCount++, this.comms?.send("media_play", this.mediaPlayingCount);\n }\n onMediaPauseEvent() {\n this.mediaPlayingCount > 0 && this.mediaPlayingCount--, this.comms?.send("media_pause", this.mediaPlayingCount);\n }\n pauseAllMedia(t) {\n const e = t.document.querySelectorAll("audio,video");\n for (let i = 0; i < e.length; i++)\n e[i].pause();\n }\n mount(t, e) {\n this.comms = e, t.addEventListener(\n "error",\n this.wndOnErr,\n !1\n ), Reflect.defineProperty(t.navigator, "epubReadingSystem", {\n value: {\n name: "readium-ts-toolkit",\n version: "2.5.5",\n hasFeature: (n, s = "") => {\n switch (n) {\n case "dom-manipulation":\n return !0;\n case "layout-changes":\n return !0;\n case "touch-events":\n return !0;\n case "mouse-events":\n return !0;\n case "keyboard-events":\n return !0;\n case "spine-scripting":\n return !0;\n case "embedded-web-content":\n return !0;\n default:\n return !1;\n }\n }\n },\n writable: !1\n }), "getAnimations" in t.document && t.document.getAnimations().forEach((n) => {\n n.cancel(), this.allAnimations.add(n);\n }), e.register("activate", At.moduleName, (n, s) => {\n this.allAnimations.forEach((o) => {\n o.cancel(), o.play();\n }), s(!0);\n }), e.register("unfocus", At.moduleName, (n, s) => {\n this.pauseAllMedia(t), this.allAnimations.forEach((o) => o.pause()), s(!0);\n });\n const i = t.document.querySelectorAll("audio,video");\n for (let n = 0; n < i.length; n++) {\n const s = i[n];\n s.addEventListener("play", this.onMediaPlayEvent, {\n passive: !0\n }), s.addEventListener("pause", this.onMediaPauseEvent, {\n passive: !0\n });\n }\n return e.log("Setup Mounted"), !0;\n }\n unmount(t, e) {\n return t.removeEventListener("error", this.wndOnErr), t.removeEventListener("play", this.onMediaPlayEvent), t.removeEventListener("pause", this.onMediaPauseEvent), this.allAnimations.forEach((i) => i.cancel()), this.allAnimations.clear(), e.log("Setup Unmounted"), !0;\n }\n};\nAt.moduleName = "setup";\nlet Gt = At;\nconst Li = "readium-viewport", Z = class Z extends Gt {\n onViewportWidthChanged(t) {\n const e = t.target;\n Tt(e, "--RS__viewportWidth", `${e.innerWidth}px`);\n }\n mount(t, e) {\n if (!super.mount(t, e)) return !1;\n const i = t.document.createElement("meta");\n return i.dataset.readium = "true", i.setAttribute("name", "viewport"), i.setAttribute("id", Li), i.setAttribute(\n "content",\n "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no"\n ), t.document.head.appendChild(i), t.addEventListener("orientationchange", this.onViewportWidthChanged), t.addEventListener("resize", this.onViewportWidthChanged), this.onViewportWidthChanged({\n target: t\n }), e.register("get_properties", Z.moduleName, (n, s) => {\n He(t), s(!0);\n }), e.register("update_properties", Z.moduleName, (n, s) => {\n n["--RS__viewportWidth"] = `${t.innerWidth}px`, sn(t, n), s(!0);\n }), e.register("set_property", Z.moduleName, (n, s) => {\n const o = n;\n Tt(t, o[0], o[1]), s(!0);\n }), e.register("remove_property", Z.moduleName, (n, s) => {\n re(t, n), s(!0);\n }), e.register("activate", Z.moduleName, (n, s) => {\n this.unblock(t), s(!0);\n }), e.log("ReflowableSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(Z.moduleName), t.document.head.querySelector(`#${Li}`)?.remove(), t.removeEventListener("orientationchange", this.onViewportWidthChanged), e.log("ReflowableSetup Unmounted"), super.unmount(t, e);\n }\n};\nZ.moduleName = "reflowable_setup";\nlet ke = Z;\nconst xi = "readium-fixed-style", q = class q extends Gt {\n mount(t, e) {\n if (!super.mount(t, e)) return !1;\n t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "paginated");\n const i = t.document.createElement("style");\n return i.id = xi, i.dataset.readium = "true", i.textContent = `\n html, body {\n text-size-adjust: none;\n -ms-text-size-adjust: none;\n -webkit-text-size-adjust: none;\n -moz-text-size-adjust: none;\n\n /* Fight Safari pinches */\n touch-action: none !important;\n min-height: 100%;\n\n /*cursor: var() TODO*/\n }`, t.document.head.appendChild(i), e.register("set_property", q.moduleName, (n, s) => {\n const o = n;\n Tt(t, o[0], o[1]), s(!0);\n }), e.register("remove_property", q.moduleName, (n, s) => {\n re(t, n), s(!0);\n }), e.register("first_visible_locator", q.moduleName, (n, s) => s(!1)), e.register("unfocus", q.moduleName, (n, s) => {\n O(t), s(!0);\n }), e.register([\n "focus",\n "go_next",\n "go_prev",\n "go_id",\n "go_end",\n "go_start",\n "go_text",\n "go_progression"\n ], q.moduleName, (n, s) => s(!0)), e.register("activate", q.moduleName, (n, s) => {\n this.unblock(t), s(!0);\n }), e.log("FixedSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(q.moduleName), t.document.getElementById(xi)?.remove(), e.log("FixedSetup Unmounted"), super.unmount(t, e);\n }\n};\nq.moduleName = "fixed_setup";\nlet Oe = q;\nconst Q = class Q extends Et {\n wndOnErr(t) {\n this.comms?.send("error", {\n message: t.message,\n filename: t.filename,\n lineno: t.lineno,\n colno: t.colno\n });\n }\n mount(t, e) {\n return this.comms = e, t.addEventListener(\n "error",\n this.wndOnErr,\n !1\n ), e.register("get_properties", Q.moduleName, (i, n) => {\n He(t), n(!0);\n }), e.register("update_properties", Q.moduleName, (i, n) => {\n sn(t, i), n(!0);\n }), e.register("set_property", Q.moduleName, (i, n) => {\n const s = i;\n Tt(t, s[0], s[1]), n(!0);\n }), e.register("remove_property", Q.moduleName, (i, n) => {\n re(t, i), n(!0);\n }), e.register("activate", Q.moduleName, (i, n) => {\n n(!0);\n }), e.log("WebPubSetup Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(Q.moduleName), t.removeEventListener("error", this.wndOnErr), e.log("WebPubSetup Unmounted"), !0;\n }\n};\nQ.moduleName = "webpub_setup";\nlet Re = Q;\nvar nt;\nlet ps = (nt = class extends Et {\n constructor() {\n super(...arguments), this.styleElement = null, this.beforePrintHandler = null, this.configApplied = !1;\n }\n setupPrintProtection(t, e) {\n if (!e.disable) return;\n const i = t.document.createElement("style");\n i.textContent = `\n @media print {\n body * {\n display: none !important;\n }\n body::after {\n content: "${e.watermark || "Printing has been disabled"}";\n font-size: 200%;\n display: block;\n text-align: center;\n margin-top: 50vh;\n transform: translateY(-50%);\n }\n }\n `, t.document.head.appendChild(i), this.styleElement = i, this.beforePrintHandler = (n) => (n.preventDefault(), !1), t.addEventListener("beforeprint", this.beforePrintHandler);\n }\n registerPrintHandlers() {\n this.comms?.register("print_protection", nt.moduleName, (t) => {\n const e = t;\n return this.configApplied || (this.configApplied = !0, this.setupPrintProtection(this.wnd, e), this.comms?.log("Print protection configuration applied")), !0;\n });\n }\n mount(t, e) {\n return this.wnd = t, this.comms = e, this.registerPrintHandlers(), !0;\n }\n unmount(t, e) {\n return this.beforePrintHandler && (t.removeEventListener("beforeprint", this.beforePrintHandler), this.beforePrintHandler = null), this.styleElement?.parentNode && (this.styleElement.parentNode.removeChild(this.styleElement), this.styleElement = null), this.comms?.unregisterAll(nt.moduleName), this.configApplied = !1, !0;\n }\n}, nt.moduleName = "print_protection", nt);\nconst ki = "readium-cjk-vertical-snapper-style", B = class B extends vt {\n constructor() {\n super(...arguments), this.patternAnalyzer = null, this.lastScrollTime = 0, this.isScrollProtectionEnabled = !1, this.initialScrollHandled = !1, this.isScrolling = !1, this.lastScrollLeft = 0, this.isResizing = !1, this.resizeDebounce = null, this.verticalLR = !1, this.handleScroll = (t) => {\n if (this.comms.ready && !this.isResizing) {\n if (!this.initialScrollHandled) {\n this.lastScrollLeft = Math.abs(this.doc().scrollLeft), this.initialScrollHandled = !0, this.reportProgress();\n return;\n }\n this.isScrolling || (this.isScrolling = !0, this.wnd.requestAnimationFrame(() => {\n this.reportProgress();\n const e = Math.abs(this.doc().scrollLeft), i = e - this.lastScrollLeft;\n if (this.lastScrollLeft = e, this.isScrollProtectionEnabled && Math.abs(i) > 5) {\n const n = Date.now(), s = n - (this.lastScrollTime || n);\n if (this.patternAnalyzer && this.patternAnalyzer.analyze(\n // In vertical-rl, norm increases when scrolling forward (toward left/end),\n // so deltaX > 0 = going forward.\n i > 0 ? "down" : "up",\n Math.abs(i),\n s\n )) {\n const a = t.target && "tagName" in t.target ? { tagName: t.target.tagName } : null;\n this.comms?.send("content_protection", {\n type: "suspicious_scrolling",\n timestamp: Date.now(),\n scrollDelta: i,\n scrollDirection: i > 0 ? "left" : "right",\n targetElement: a\n });\n }\n this.lastScrollTime = n;\n }\n this.comms.send("scroll", i), this.isScrolling = !1;\n }));\n }\n };\n }\n doc() {\n return this.wnd.document.scrollingElement;\n }\n /** Total horizontally scrollable distance (magnitude). */\n scrollable() {\n return Math.max(0, this.doc().scrollWidth - this.wnd.innerWidth);\n }\n reportProgress() {\n if (!this.comms.ready) return;\n const t = this.doc().scrollWidth, e = this.wnd.innerWidth, i = Math.max(1, t - e), n = Math.abs(this.doc().scrollLeft), s = Math.max(0, Math.min(1, n / i)), o = Math.max(0, Math.min(1, (n + e) / t));\n this.comms.send("progress", {\n start: s,\n end: o\n });\n }\n enableScrollProtection() {\n this.patternAnalyzer || (this.patternAnalyzer = new ae(je), this.isScrollProtectionEnabled = !0, this.comms?.log("Scroll protection enabled"));\n }\n mount(t, e) {\n this.wnd = t, this.comms = e, this.initialScrollHandled = !1, this.lastScrollLeft = 0, this.isResizing = !1, this.verticalLR = ts(t), this.resizeDebounce && (this.wnd.clearTimeout(this.resizeDebounce), this.resizeDebounce = null), t.navigator.epubReadingSystem && (t.navigator.epubReadingSystem.layoutStyle = "scrolling");\n const i = t.document.createElement("style");\n return i.dataset.readium = "true", i.id = ki, i.textContent = `\n * {\n scrollbar-width: none;\n }\n body::-webkit-scrollbar {\n display: none;\n }\n html {\n overflow-x: auto !important;\n overflow-y: hidden !important;\n }\n `, t.document.head.appendChild(i), this.resizeObserver = new ResizeObserver(() => {\n this.resizeDebounce && this.wnd.clearTimeout(this.resizeDebounce), this.isResizing = !0, this.resizeDebounce = this.wnd.setTimeout(() => {\n this.isResizing = !1, this.resizeDebounce = null, this.reportProgress();\n }, 50);\n }), this.resizeObserver.observe(t.document.body), t.addEventListener("scroll", this.handleScroll, { passive: !0 }), e.register("force_webkit_recalc", B.moduleName, () => {\n Be(this.wnd);\n const n = this.doc().scrollLeft;\n this.verticalLR ? this.doc().scrollLeft = n > 1 ? n - 1 : n + 1 : this.doc().scrollLeft = n < -1 ? n + 1 : n - 1, this.doc().scrollLeft = n;\n }), e.register("go_progression", B.moduleName, (n, s) => {\n const o = n;\n if (o < 0 || o > 1) {\n e.send("error", {\n message: "go_progression must be given a position from 0.0 to 1.0"\n }), s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n const a = this.scrollable() * o;\n this.doc().scrollLeft = this.verticalLR ? a : -a, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_id", B.moduleName, (n, s) => {\n const o = t.document.getElementById(n);\n if (!o) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollLeft += o.getBoundingClientRect().left - t.innerWidth / 2, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_text", B.moduleName, (n, s) => {\n let o;\n Array.isArray(n) && (n.length > 1 && (o = n[1]), n = n[0]);\n const a = rt.deserialize(n), l = It(this.wnd.document, new I({\n href: t.location.href,\n type: "text/html",\n text: a,\n locations: o ? new C({\n otherLocations: /* @__PURE__ */ new Map([["cssSelector", o]])\n }) : void 0\n }));\n if (!l) {\n s(!1);\n return;\n }\n this.wnd.requestAnimationFrame(() => {\n this.doc().scrollLeft += l.getBoundingClientRect().left - t.innerWidth / 2, this.reportProgress(), O(this.wnd), s(!0);\n });\n }), e.register("go_start", B.moduleName, (n, s) => {\n if (this.doc().scrollLeft === 0) return s(!1);\n this.doc().scrollLeft = 0, this.reportProgress(), s(!0);\n }), e.register("go_end", B.moduleName, (n, s) => {\n if (Math.abs(this.doc().scrollLeft) === this.scrollable()) return s(!1);\n this.doc().scrollLeft = this.verticalLR ? this.scrollable() : -this.scrollable(), this.reportProgress(), s(!0);\n }), e.register([\n "go_next",\n "go_prev"\n ], B.moduleName, (n, s) => s(!1)), e.register("unfocus", B.moduleName, (n, s) => {\n O(this.wnd), s(!0);\n }), e.register("scroll_protection", B.moduleName, (n, s) => {\n this.enableScrollProtection(), s(!0);\n }), e.register("focus", B.moduleName, (n, s) => {\n this.reportProgress(), s(!0);\n }), e.register("first_visible_locator", B.moduleName, (n, s) => {\n const o = oe(t, !0);\n this.comms.send("first_visible_locator", o.serialize()), s(!0);\n }), e.log("CJKVerticalSnapper Mounted"), !0;\n }\n unmount(t, e) {\n return e.unregisterAll(B.moduleName), this.resizeObserver.disconnect(), this.handleScroll && t.removeEventListener("scroll", this.handleScroll), t.document.getElementById(ki)?.remove(), this.patternAnalyzer && (this.patternAnalyzer.clear(), this.patternAnalyzer = null, this.isScrollProtectionEnabled = !1), e.log("CJKVerticalSnapper Unmounted"), !0;\n }\n};\nB.moduleName = "cjk_vertical_snapper";\nlet Ae = B;\nconst fs = [\n "fixed_setup",\n "decorator",\n "peripherals",\n "print_protection"\n], ms = [\n "reflowable_setup",\n "decorator",\n "peripherals",\n "column_snapper",\n "scroll_snapper",\n "cjk_vertical_snapper",\n "print_protection"\n], gs = [\n "webpub_setup",\n "webpub_snapper",\n "decorator",\n "peripherals",\n "print_protection"\n], Te = new Map([\n // All modules go here\n Oe,\n ke,\n Re,\n Le,\n xe,\n Ee,\n Ce,\n _e,\n Ae,\n ps\n].map((r) => [r.moduleName, r]));\nclass Pt {\n /**\n * @param wnd Window instance to operate on\n * @param initialModules List of initial modules to load\n */\n constructor(t = window, e = []) {\n this.loadedModules = [], this.wnd = t, this.comms = new zn(t);\n const i = [...new Set(e)];\n if (i.length) {\n if (typeof t > "u")\n throw Error("Loader is not in a web browser");\n t.parent !== t && this.comms.log("Loader is probably in a frame"), this.loadedModules = i.map((n) => {\n const s = this.loadModule(n);\n if (s)\n return s.mount(this.wnd, this.comms), s;\n }).filter((n) => n !== void 0);\n }\n }\n loadModule(t) {\n const e = Te.get(t);\n return e === void 0 ? (this.comms.log(`Module "${name}" does not exist in the library`), e) : new e();\n }\n /**\n * Add a module by name\n * @param moduleName Module name\n * @returns Success\n */\n addModule(t) {\n const e = this.loadModule(t);\n return !e || !e.mount(this.wnd, this.comms) ? !1 : (this.loadedModules.push(e), !0);\n }\n /**\n * Remove a module by name\n * @param moduleName Module name\n * @returns Success\n */\n removeModule(t) {\n const e = Te.get(t);\n if (e === void 0)\n return this.comms.log(`Module "${t}" does not exist in the library`), !1;\n const i = this.loadedModules.findIndex((n) => n instanceof e);\n return i < 0 ? !1 : (this.loadedModules[i].unmount(this.wnd, this.comms), this.loadedModules.splice(i, 1), !0);\n }\n /**\n * Unmount and remove all modules\n */\n destroy() {\n this.comms.destroy(), this.loadedModules.forEach((t) => t.unmount(this.wnd, this.comms)), this.loadedModules = [];\n }\n}\nconst ys = {\n type: "developer_tools",\n keyCombos: [\n { keyCode: 73, meta: !0, alt: !0 },\n // Cmd+Option+I\n { keyCode: 73, ctrl: !0, shift: !0 },\n // Ctrl+Shift+I\n { keyCode: 74, meta: !0, alt: !0 },\n // Cmd+Option+J\n { keyCode: 74, ctrl: !0, shift: !0 },\n // Ctrl+Shift+J\n { keyCode: 85, meta: !0, alt: !0 },\n // Cmd+Option+U\n { keyCode: 67, meta: !0, alt: !0 },\n // Cmd+Option+C\n { keyCode: 67, meta: !0, shift: !0 },\n // Cmd+Shift+C\n { keyCode: 67, ctrl: !0, shift: !0 },\n // Ctrl+Shift+C\n { keyCode: 65, meta: !0, alt: !0 },\n // Cmd+Option+A\n { keyCode: 84, meta: !0, shift: !0, alt: !0 },\n // Cmd+Shift+Option+T\n { keyCode: 67, shift: !0, alt: !0 },\n // Shift+Option+C\n { keyCode: 123 },\n // F12\n { keyCode: 123, shift: !0 },\n // Shift+F12\n { keyCode: 123, ctrl: !0, shift: !0 },\n // Ctrl+Shift+F12\n { keyCode: 123, meta: !0, alt: !0 }\n // Cmd+Option+F12\n ]\n}, bs = {\n type: "select_all",\n keyCombos: [\n { keyCode: 65, meta: !0 },\n // Cmd+A\n { keyCode: 65, ctrl: !0 }\n // Ctrl+A\n ]\n}, ws = {\n type: "print",\n keyCombos: [\n { keyCode: 80, meta: !0 },\n // Cmd+P\n { keyCode: 80, ctrl: !0 },\n // Ctrl+P\n { keyCode: 80, meta: !0, shift: !0 },\n // Cmd+Shift+P\n { keyCode: 80, ctrl: !0, shift: !0 },\n // Ctrl+Shift+P\n { keyCode: 80, meta: !0, alt: !0 },\n // Cmd+Alt+P\n { keyCode: 80, ctrl: !0, alt: !0 }\n // Ctrl+Alt+P\n ]\n}, Ss = {\n type: "save",\n keyCombos: [\n { keyCode: 83, meta: !0 },\n // Cmd+S\n { keyCode: 83, ctrl: !0 }\n // Ctrl+S\n ]\n};\nclass cn {\n /**\n * Merges keyboard peripherals from content protection config with user-provided peripherals\n * Content protection peripherals are added first for priority, then user peripherals are added only if they don\'t conflict\n */\n mergeKeyboardPeripherals(t, e = []) {\n const i = [], n = e.filter(\n (s) => !["developer_tools", "select_all", "print", "save"].includes(s.type)\n );\n t.disableSelectAll && i.push(bs), t.disableSave && i.push(Ss), t.monitorDevTools && i.push(ys), t.protectPrinting?.disable && i.push(ws);\n for (const s of n) {\n const o = s.keyCombos.filter(\n (a) => !i.some(\n (l) => l.keyCombos.some(\n (h) => a.keyCode === h.keyCode && a.ctrl === h.ctrl && a.shift === h.shift && a.alt === h.alt && a.meta === h.meta\n )\n )\n );\n o.length > 0 && i.push({\n ...s,\n keyCombos: o\n });\n }\n return i;\n }\n}\nclass dn extends cn {\n /**\n * Moves to the left content portion (eg. page) relative to the reading progression direction.\n */\n goLeft(t = !1, e) {\n this.readingProgression === M.ltr ? this.goBackward(t, e) : this.readingProgression === M.rtl && this.goForward(t, e);\n }\n /**\n * Moves to the right content portion (eg. page) relative to the reading progression direction.\n */\n goRight(t = !1, e) {\n this.readingProgression === M.ltr ? this.goForward(t, e) : this.readingProgression === M.rtl && this.goBackward(t, e);\n }\n}\nclass vs extends cn {\n}\nclass Ps {\n constructor(t, e, i, n) {\n this.injector = null, this.pub = t, this.item = i, this.burl = i.toURL(e) || "", this.cssProperties = n.cssProperties, this.injector = n.injector ?? null;\n }\n async build() {\n if (!this.item.mediaType.isHTML)\n throw new Error(`Unsupported media type for WebPub: ${this.item.mediaType.string}`);\n return await this.buildHtmlFrame();\n }\n async buildHtmlFrame() {\n const t = await this.pub.get(this.item).readAsString();\n if (!t) throw new Error(`Failed reading item ${this.item.href}`);\n const e = new DOMParser().parseFromString(\n t,\n this.item.mediaType.string\n ), i = e.querySelector("parsererror");\n if (i) {\n const n = i.querySelector("div");\n throw new Error(`Failed parsing item ${this.item.href}: ${n?.textContent || i.textContent}`);\n }\n return this.injector && await this.injector.injectForDocument(e, this.item), this.finalizeDOM(e, this.burl, this.item.mediaType, t, this.cssProperties);\n }\n setProperties(t, e) {\n for (const i in t) {\n const n = t[i];\n n && e.documentElement.style.setProperty(i, n);\n }\n }\n finalizeDOM(t, e, i, n, s) {\n if (!t) return "";\n if (s && this.setProperties(s, t), t.body.querySelectorAll("img").forEach((a) => {\n a.setAttribute("fetchpriority", "high");\n }), e !== void 0) {\n const a = t.createElement("base");\n a.href = e, a.dataset.readium = "true", t.head.firstChild.before(a);\n }\n let o;\n return i.string === "application/xhtml+xml" ? o = new XMLSerializer().serializeToString(t) : o = this.serializeAsHTML(t, n || ""), URL.createObjectURL(\n new Blob([o], {\n type: i.isHTML ? i.string : "application/xhtml+xml"\n })\n );\n }\n serializeAsHTML(t, e) {\n const i = e.match(/]*>/i), n = i ? i[0] + `\n` : "";\n let o = t.documentElement.outerHTML;\n return n + o;\n }\n}\nconst Es = 1e4;\nclass Nt {\n constructor(t, e) {\n this.registry = /* @__PURE__ */ new Map(), this._ready = !1, this.listenerBuffer = [], this.handler = this.handle.bind(this), this.wnd = t, this.origin = e;\n try {\n this.channelId = window.crypto.randomUUID();\n } catch {\n this.channelId = we();\n }\n this.gc = setInterval(() => {\n this.registry.forEach((i, n) => {\n performance.now() - i.time > Es && (console.warn(n, "event for", i.key, "was never handled!"), this.registry.delete(n));\n });\n }, 5e3), window.addEventListener("message", this.handler), this.send("_ping", void 0);\n }\n set listener(t) {\n this.listenerBuffer.length > 0 && this.listenerBuffer.forEach((e) => t(e[0], e[1])), this.listenerBuffer = [], this._listener = t;\n }\n clearListener() {\n typeof this._listener == "function" && (this._listener = void 0);\n }\n halt() {\n this._ready = !1, window.removeEventListener("message", this.handler), clearInterval(this.gc), this._listener = void 0, this.registry.clear();\n }\n resume() {\n window.addEventListener("message", this.handler), this._ready = !0;\n }\n handle(t) {\n const e = t.data;\n if (!e._readium) {\n console.warn("Ignoring", e);\n return;\n }\n if (e._channel === this.channelId)\n switch (e.key) {\n case "_ack": {\n if (!e.id) return;\n const i = this.registry.get(e.id);\n if (!i) return;\n this.registry.delete(e.id), i.cb(!!e.data);\n return;\n }\n // @ts-ignore\n case "_pong":\n this._ready = !0;\n default: {\n if (!this.ready) return;\n typeof this._listener == "function" ? this._listener(e.key, e.data) : this.listenerBuffer.push([e.key, e.data]);\n }\n }\n }\n get ready() {\n return this._ready;\n }\n /**\n * Send a message to the window using postMessage-based comms communication\n * @returns Identifier associated with the message\n */\n send(t, e, i, n = !1, s = []) {\n const o = we();\n return i && this.registry.set(o, {\n // Add callback to the registry\n cb: i,\n time: performance.now(),\n key: t\n }), this.wnd.postMessage(\n {\n _readium: ft,\n _channel: this.channelId,\n id: o,\n data: e,\n key: t,\n strict: n\n },\n "/",\n // Same origin\n s\n ), o;\n }\n}\nconst Cs = "\'Iowan Old Style\', Sitka, \'Sitka Text\', Palatino, \'Book Antiqua\', \'URW Palladio L\', P052, serif", _s = {\n oldStyleTf: Cs\n}, Ls = 16, Oi = _s.oldStyleTf;\nclass kt {\n constructor(t) {\n this._optimalLineLength = null, this._canvas = document.createElement("canvas"), this._optimalChars = t.optimalChars, this._minChars = t.minChars, this._maxChars = t.maxChars, this._baseFontSize = t.baseFontSize || Ls, this._fontFace = t.fontFace || Oi, this._sample = t.sample || null, this._padding = t.padding ?? 0, this._letterSpacing = t.letterSpacing ? Math.round(t.letterSpacing * this._baseFontSize) : 0, this._wordSpacing = t.wordSpacing ? Math.round(t.wordSpacing * this._baseFontSize) : 0, this._isCJK = t.isCJK || !1, this._getRelative = t.getRelative || !1, this._minDivider = this._minChars && this._minChars < this._optimalChars ? this._optimalChars / this._minChars : this._minChars === null ? null : 1, this._maxMultiplier = this._maxChars && this._maxChars > this._optimalChars ? this._maxChars / this._optimalChars : this._maxChars === null ? null : 1, this._approximatedWordSpaces = kt.approximateWordSpaces(this._optimalChars, this._sample);\n }\n updateMultipliers() {\n this._minDivider = this._minChars && this._minChars < this._optimalChars ? this._optimalChars / this._minChars : this._minChars === null ? null : 1, this._maxMultiplier = this._maxChars && this._maxChars > this._optimalChars ? this._maxChars / this._optimalChars : this._maxChars === null ? null : 1;\n }\n // Batch update to guarantee up-to-date values\n // Not filtering because pretty much everything can\n // trigger a recomputation anyway.\n update(t) {\n t.optimalChars && (this._optimalChars = t.optimalChars), t.minChars !== void 0 && (this._minChars = t.minChars), t.maxChars !== void 0 && (this._maxChars = t.maxChars), t.baseFontSize && (this._baseFontSize = t.baseFontSize), t.fontFace !== void 0 && (this._fontFace = t.fontFace || Oi), t.letterSpacing && (this._letterSpacing = t.letterSpacing), t.wordSpacing && (this._wordSpacing = t.wordSpacing), t.isCJK != null && (this._isCJK = t.isCJK), t.padding !== void 0 && (this._padding = t.padding ?? 0), t.getRelative && (this._getRelative = t.getRelative), t.sample && (this._sample = t.sample, this._approximatedWordSpaces = kt.approximateWordSpaces(this._optimalChars, this._sample)), this.updateMultipliers(), this._optimalLineLength = this.getOptimalLineLength();\n }\n get baseFontSize() {\n return this._baseFontSize;\n }\n get minimalLineLength() {\n return this._optimalLineLength || (this._optimalLineLength = this.getOptimalLineLength()), this._minDivider !== null ? Math.round(this._optimalLineLength / this._minDivider + this._padding) / (this._getRelative ? this._baseFontSize : 1) : null;\n }\n get maximalLineLength() {\n return this._optimalLineLength || (this._optimalLineLength = this.getOptimalLineLength()), this._maxMultiplier !== null ? Math.round(this._optimalLineLength * this._maxMultiplier + this._padding) / (this._getRelative ? this._baseFontSize : 1) : null;\n }\n get optimalLineLength() {\n return this._optimalLineLength || (this._optimalLineLength = this.getOptimalLineLength()), Math.round(this._optimalLineLength + this._padding) / (this._getRelative ? this._baseFontSize : 1);\n }\n get all() {\n return this._optimalLineLength || (this._optimalLineLength = this.getOptimalLineLength()), {\n min: this.minimalLineLength,\n max: this.maximalLineLength,\n optimal: this.optimalLineLength,\n baseFontSize: this._baseFontSize\n };\n }\n static approximateWordSpaces(t, e) {\n let i = 0;\n if (e && e.length >= t) {\n const n = e.match(/([\\s]+)/gi);\n i = (n ? n.length : 0) * (t / e.length);\n }\n return i;\n }\n getLineLengthFallback() {\n const t = this._letterSpacing * (this._optimalChars - 1), e = this._wordSpacing * this._approximatedWordSpaces;\n return this._optimalChars * (this._baseFontSize * 0.5) + t + e;\n }\n getOptimalLineLength() {\n if (this._fontFace) {\n if (typeof this._fontFace == "string")\n return this.measureText(this._fontFace);\n {\n const t = new FontFace(this._fontFace.name, `url(${this._fontFace.url})`);\n t.load().then(\n () => (document.fonts.add(t), this.measureText(t.family)),\n (e) => {\n }\n );\n }\n }\n return this.getLineLengthFallback();\n }\n measureText(t) {\n const e = this._canvas.getContext("2d");\n if (e && t) {\n let i = this._isCJK ? "水".repeat(this._optimalChars) : "0".repeat(this._optimalChars);\n if (e.font = `${this._baseFontSize}px ${t}`, this._sample && this._sample.length >= this._optimalChars && (i = this._sample.slice(0, this._optimalChars)), Object.hasOwn(e, "letterSpacing") && Object.hasOwn(e, "wordSpacing"))\n return e.letterSpacing = this._letterSpacing.toString() + "px", e.wordSpacing = this._wordSpacing.toString() + "px", e.measureText(i).width;\n {\n const n = this._letterSpacing * (this._optimalChars - 1), s = this._wordSpacing * kt.approximateWordSpaces(this._optimalChars, this._sample);\n return e.measureText(i).width + n + s;\n }\n } else\n return this.getLineLengthFallback();\n }\n}\nconst un = () => typeof navigator > "u" ? "" : navigator.userAgent || "", pn = () => typeof navigator > "u" ? void 0 : navigator.userAgentData || void 0;\nclass fn {\n constructor() {\n const t = pn(), e = un(), i = (s) => (typeof s == "string" || typeof s == "number") && s ? String(s).replace(/_/g, ".").split(".").map((o) => parseInt(o) || 0) : [], n = (s = "") => {\n if (!s) return [];\n const o = new RegExp("^.*" + s + "[ :\\\\/]?(\\\\d+([\\\\._]\\\\d+)*).*$");\n return o.test(e) ? i(e.replace(o, "$1")) : [];\n };\n this.OS = ((s) => (/(macOS|Mac OS X)/.test(e) ? (/\\(iP(hone|od touch);/.test(e) && (s.iOS = n("CPU (?:iPhone )?OS ")), /\\(iPad;/.test(e) ? s.iOS = s.iPadOS = n("CPU (?:iPhone )?OS ") : /(macOS|Mac OS X) \\d/.test(e) && (document.ontouchend !== void 0 ? s.iOS = s.iPadOS = n() : s.macOS = n("(?:macOS|Mac OS X) "))) : /Windows( NT)? \\d/.test(e) ? s.Windows = ((o) => o[0] !== 6 || !o[1] ? o : o[1] === 1 ? [7] : o[1] === 2 ? [8] : [8, 1])(n("Windows(?: NT)?")) : /Android \\d/.test(e) ? s.Android = n("Android") : /CrOS/.test(e) ? s.ChromeOS = n() : /X11;/.test(e) && (s.Linux = n()), s))({}), t && t.getHighEntropyValues(["architecture", "model", "platform", "platformVersion", "uaFullVersion"]).then((s) => ((o) => {\n const a = s.platform, l = s.platformVersion;\n if (!(!a || !l)) {\n if (/^i(OS|P(hone|od touch))$/.test(a)) o.iOS = i(l);\n else if (/^iPad(OS)?$/.test(a)) o.iOS = o.iPadOS = i(l);\n else if (/^(macOS|(Mac )?OS X|Mac(Intel)?)$/.test(a)) document.ontouchend !== void 0 ? o.iOS = o.iPadOS = i() : o.macOS = i(l);\n else if (/^(Microsoft )?Windows$/.test(a)) o.Windows = i(l);\n else if (/^(Google )?Android$/.test(a)) o.Android = i(l);\n else if (/^((Google )?Chrome OS|CrOS)$/.test(a)) o.ChromeOS = i(l);\n else if (/^(Linux|Ubuntu|X11)$/.test(a)) o.Linux = i(l);\n else return;\n Object.keys(this.OS).forEach((h) => delete this.OS[h]), Object.assign(this.OS, o);\n }\n })({})), this.UA = ((s) => {\n let o = !1;\n if (t && Array.isArray(t.brands)) {\n const a = t.brands.reduce((l, h) => (l[h.brand] = [h.version * 1], l), {});\n a["Google Chrome"] ? (o = !0, s.Blink = s.Chromium = a.Chromium || [], s.Chrome = a["Google Chrome"]) : a["Microsoft Edge"] ? (o = !0, s.Blink = s.Chromium = a.Chromium || [], s.Edge = a["Microsoft Edge"]) : a.Opera && (o = !0, s.Blink = s.Chromium = a.Chromium || [], s.Opera = a.Opera);\n }\n return o || (/ Gecko\\/\\d/.test(e) ? (s.Gecko = n("rv"), / Waterfox\\/\\d/.test(e) ? s.Waterfox = n("Waterfox") : / Firefox\\/\\d/.test(e) && (s.Firefox = n("Firefox"))) : / Edge\\/\\d/.test(e) ? (s.EdgeHTML = n("Edge"), s.Edge = s.EdgeHTML) : / Chrom(ium|e)\\/\\d/.test(e) ? (s.Blink = s.Chromium = ((a) => a[0] ? a : n("Chrome"))(n("Chromium")), / EdgA?\\/\\d/.test(e) ? s.Edge = ((a) => a[0] ? a : n("Edg"))(n("EdgA")) : / OPR\\/\\d/.test(e) ? s.Opera = n("OPR") : / Vivaldi\\/\\d/.test(e) ? s.Vivaldi = n("Vivaldi") : / Silk\\/\\d/.test(e) ? s.Silk = n("Silk") : / UCBrowser\\/\\d/.test(e) ? s.UCBrowser = n("UCBrowser") : / Phoebe\\/\\d/.test(e) ? s.Phoebe = n("Phoebe") : s.Chrome = ((a) => a[0] ? a : s.Chromium)(n("Chrome"))) : / AppleWebKit\\/\\d/.test(e) ? (s.WebKit = n("AppleWebKit"), / CriOS \\d/.test(e) ? s.Chrome = n("CriOS") : / FxiOS \\d/.test(e) ? s.Firefox = n("FxiOS") : / EdgiOS\\/\\d/.test(e) ? s.Edge = n("EdgiOS") : / Version\\/\\d/.test(e) && (s.Safari = n("Version"))) : / Trident\\/\\d/.test(e) && (s.Trident = n("Trident"), s.InternetExplorer = ((a) => a[0] ? a : n("MSIE"))(n("rv")))), /[\\[; ]FB(AN|_IAB)\\//.test(e) && (s.Facebook = n("FBAV")), / Line\\/\\d/.test(e) && (s.LINE = n("Line")), s;\n })({}), this.Env = { get: () => [this.OS, this.UA].reduce((s, o) => {\n for (const a in o) o[a] && s.push(a);\n return s;\n }, []) };\n }\n}\nclass xs extends fn {\n get iOSRequest() {\n const t = pn(), e = un();\n if (this.OS.iOS && !this.OS.iPadOS)\n return "mobile";\n if (this.OS.iPadOS)\n return /\\(iPad;/.test(e) || t && /^iPad(OS)?$/.test(t.platform) ? "mobile" : "desktop";\n }\n}\nconst J = new fn(), T = new xs();\nfunction bt(r) {\n const t = r.languages?.[0]?.toLowerCase(), e = r.readingProgression;\n if (t) {\n if (t.startsWith("zh") || t.startsWith("ja") || t.startsWith("ko"))\n return e === M.rtl ? "cjk-vertical" : "cjk-horizontal";\n if (t.startsWith("mn-mong")) return "mongolian-vertical";\n if (t.startsWith("ar") || t.startsWith("fa") || t.startsWith("he")) return "rtl";\n }\n return "ltr";\n}\nclass $e {\n constructor(t, e) {\n this.config = t, this.onUpdate = e, this.unsubs = [], this.conditionValues = /* @__PURE__ */ new Map();\n }\n setup() {\n let t = !0;\n this.config.forEach(\n (e) => e.keyCombos.forEach((i) => {\n if (i.condition) {\n const n = i.condition.subscribe((s) => {\n this.conditionValues.set(i, s), t || this.onUpdate(this.buildSerializable());\n });\n this.unsubs.push(n);\n }\n })\n ), t = !1, this.onUpdate(this.buildSerializable());\n }\n buildSerializable() {\n return this.config.map((t) => ({\n ...t,\n keyCombos: t.keyCombos.filter((e) => !e.condition || this.conditionValues.get(e) === !0).map(({ condition: e, ...i }) => i)\n })).filter((t) => t.keyCombos.length > 0);\n }\n destroy() {\n this.unsubs.forEach((t) => t()), this.unsubs = [], this.conditionValues.clear();\n }\n}\nclass ks {\n constructor(t, e = {}, i = []) {\n this.hidden = !0, this.destroyed = !1, this.currModules = [], this.frame = document.createElement("iframe"), this.frame.classList.add("readium-navigator-iframe"), this.frame.style.visibility = "hidden", this.frame.style.setProperty("aria-hidden", "true"), this.frame.style.opacity = "0", this.frame.style.position = "absolute", this.frame.style.pointerEvents = "none", this.frame.style.transition = "visibility 0s, opacity 0.1s linear", this.frame.style.backgroundColor = "#FFFFFF", this.source = t, this.contentProtectionConfig = { ...e }, this.keyboardPeripheralsConfig = [...i];\n }\n async load(t = []) {\n return new Promise((e, i) => {\n if (this.loader) {\n const n = this.frame.contentWindow;\n if ([...this.currModules].sort().join("|") === [...t].sort().join("|")) {\n try {\n e(n);\n } catch {\n }\n return;\n }\n this.comms?.halt(), this.loader.destroy(), this.loader = new Pt(n, t), this.currModules = t, this.comms = void 0;\n try {\n e(n);\n } catch {\n }\n return;\n }\n this.frame.onload = () => {\n const n = this.frame.contentWindow;\n this.loader = new Pt(n, t), this.currModules = t;\n try {\n e(n);\n } catch {\n }\n }, this.frame.onerror = (n) => {\n try {\n i(n);\n } catch {\n }\n }, this.frame.contentWindow.location.replace(this.source);\n });\n }\n applyContentProtection() {\n this.comms || this.comms.resume(), this.comms.send("peripherals_protection", this.contentProtectionConfig), this.keyboardPeripheralsConfig && this.keyboardPeripheralsConfig.length > 0 && (this.conditionBridge?.destroy(), this.conditionBridge = new $e(\n this.keyboardPeripheralsConfig,\n (t) => {\n t.length > 0 && this.comms.send("keyboard_peripherals", t);\n }\n ), this.conditionBridge.setup()), this.contentProtectionConfig.monitorScrollingExperimental && this.comms.send("scroll_protection", {}), this.contentProtectionConfig.protectPrinting?.disable && this.comms.send("print_protection", this.contentProtectionConfig.protectPrinting);\n }\n async destroy() {\n this.conditionBridge?.destroy(), await this.hide(), this.loader?.destroy(), this.frame.remove(), this.destroyed = !0;\n }\n async hide() {\n if (!this.destroyed) {\n if (this.frame.style.visibility = "hidden", this.frame.style.setProperty("aria-hidden", "true"), this.frame.style.opacity = "0", this.frame.style.pointerEvents = "none", this.hidden = !0, this.frame.parentElement)\n return this.comms === void 0 || !this.comms.ready ? void 0 : new Promise((t, e) => {\n this.comms?.send("unfocus", void 0, (i) => {\n this.comms?.halt(), t();\n });\n });\n this.comms?.halt();\n }\n }\n async show(t) {\n if (this.destroyed) throw Error("Trying to show frame when it doesn\'t exist");\n if (!this.frame.parentElement) throw Error("Trying to show frame that is not attached to the DOM");\n return this.comms ? this.comms.resume() : this.comms = new Nt(this.frame.contentWindow, this.source), new Promise((e, i) => {\n this.comms?.send("activate", void 0, () => {\n this.comms?.send("focus", void 0, () => {\n this.applyContentProtection();\n const n = () => {\n this.frame.style.removeProperty("visibility"), this.frame.style.removeProperty("aria-hidden"), this.frame.style.removeProperty("opacity"), this.frame.style.removeProperty("pointer-events"), this.hidden = !1, J.UA.WebKit && this.comms?.send("force_webkit_recalc", void 0), e();\n };\n t !== void 0 ? this.comms?.send("go_progression", t, n) : n();\n });\n });\n });\n }\n setCSSProperties(t) {\n this.destroyed || !this.frame.contentWindow || (this.hidden && (this.comms ? this.comms?.resume() : this.comms = new Nt(this.frame.contentWindow, this.source)), this.comms?.send("update_properties", t), this.hidden && this.comms?.halt());\n }\n get iframe() {\n if (this.destroyed) throw Error("Trying to use frame when it doesn\'t exist");\n return this.frame;\n }\n get realSize() {\n if (this.destroyed) throw Error("Trying to use frame client rect when it doesn\'t exist");\n return this.frame.getBoundingClientRect();\n }\n get window() {\n if (this.destroyed || !this.frame.contentWindow) throw Error("Trying to use frame window when it doesn\'t exist");\n return this.frame.contentWindow;\n }\n get msg() {\n return this.comms;\n }\n get ldr() {\n return this.loader;\n }\n}\nclass Os {\n constructor(t, e, i, n = {}, s = []) {\n this.pool = /* @__PURE__ */ new Map(), this.blobs = /* @__PURE__ */ new Map(), this.inprogress = /* @__PURE__ */ new Map(), this.pendingUpdates = /* @__PURE__ */ new Map(), this.injector = null, this.container = t, this.currentCssProperties = e, this.injector = i, this.contentProtectionConfig = n, this.keyboardPeripheralsConfig = [...s];\n }\n async destroy() {\n let t = this.inprogress.values(), e = t.next();\n const i = [];\n for (; e.value; )\n i.push(e.value), e = t.next();\n i.length > 0 && await Promise.allSettled(i), this.inprogress.clear();\n let n = this.pool.values(), s = n.next();\n for (; s.value; )\n await s.value.destroy(), s = n.next();\n this.pool.clear(), this.blobs.forEach((o) => {\n this.injector?.releaseBlobUrl?.(o), URL.revokeObjectURL(o);\n }), this.blobs.clear(), this.injector?.dispose(), this.container.childNodes.forEach((o) => {\n (o.nodeType === Node.ELEMENT_NODE || o.nodeType === Node.TEXT_NODE) && o.remove();\n });\n }\n async update(t, e, i) {\n const n = t.readingOrder.items;\n let s = n.findIndex((l) => l.href === e.href);\n if (s < 0) throw Error(`Locator not found in reading order: ${e.href}`);\n const o = n[s].href;\n this.inprogress.has(o) && await this.inprogress.get(o);\n const a = new Promise(async (l, h) => {\n const c = [], u = [];\n t.readingOrder.items.forEach((d, f) => {\n f !== s && f !== s - 1 && f !== s + 1 && (c.includes(d.href) || c.push(d.href)), f === s && (u.includes(d.href) || u.push(d.href));\n }), c.forEach(async (d) => {\n u.includes(d) || this.pool.has(d) && (await this.pool.get(d)?.destroy(), this.pool.delete(d));\n }), this.currentBaseURL !== void 0 && t.baseURL !== this.currentBaseURL && (this.blobs.forEach((d) => {\n this.injector?.releaseBlobUrl?.(d), URL.revokeObjectURL(d);\n }), this.blobs.clear()), this.currentBaseURL = t.baseURL;\n const p = async (d) => {\n if (this.pendingUpdates.has(d) && this.pendingUpdates.get(d)?.inPool === !1) {\n const P = this.blobs.get(d);\n P && (this.injector?.releaseBlobUrl?.(P), URL.revokeObjectURL(P), this.blobs.delete(d), this.pendingUpdates.delete(d));\n }\n if (this.pool.has(d)) {\n const P = this.pool.get(d);\n if (!this.blobs.has(d))\n await P.destroy(), this.pool.delete(d), this.pendingUpdates.delete(d);\n else {\n await P.load(i);\n return;\n }\n }\n const f = t.readingOrder.findWithHref(d);\n if (!f) return;\n if (!this.blobs.has(d)) {\n const R = await new Ps(\n t,\n this.currentBaseURL || "",\n f,\n {\n cssProperties: this.currentCssProperties,\n injector: this.injector\n }\n ).build();\n this.blobs.set(d, R);\n }\n const w = new ks(this.blobs.get(d), this.contentProtectionConfig, this.keyboardPeripheralsConfig);\n d !== o && await w.hide(), this.container.appendChild(w.iframe), await w.load(i), this.pool.set(d, w);\n };\n try {\n await Promise.all(u.map((d) => p(d)));\n } catch (d) {\n h(d);\n }\n const g = this.pool.get(o);\n g?.source !== this._currentFrame?.source && (await this._currentFrame?.hide(), g && await g.load(i), g && await g.show(e.locations.progression), this._currentFrame = g), l();\n });\n this.inprogress.set(o, a), await a, this.inprogress.delete(o);\n }\n setCSSProperties(t) {\n if (!((i, n) => {\n const s = Object.keys(i), o = Object.keys(n);\n if (s.length !== o.length)\n return !1;\n for (const a of s)\n if (i[a] !== n[a])\n return !1;\n return !0;\n })(this.currentCssProperties || {}, t)) {\n this.currentCssProperties = t, this.pool.forEach((i) => {\n i.setCSSProperties(t);\n });\n for (const i of this.blobs.keys())\n this.pendingUpdates.set(i, { inPool: this.pool.has(i) });\n }\n }\n get currentFrames() {\n return [this._currentFrame];\n }\n get currentBounds() {\n const t = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n toJSON() {\n return this;\n }\n };\n return this.currentFrames.forEach((e) => {\n if (!e) return;\n const i = e.realSize;\n t.x = Math.min(t.x, i.x), t.y = Math.min(t.y, i.y), t.width += i.width, t.height = Math.max(t.height, i.height), t.top = Math.min(t.top, i.top), t.right = Math.min(t.right, i.right), t.bottom = Math.min(t.bottom, i.bottom), t.left = Math.min(t.left, i.left);\n }), t;\n }\n}\nvar me, Ri;\nfunction Rs() {\n if (Ri) return me;\n Ri = 1;\n function r(n) {\n if (typeof n != "string")\n throw new TypeError("Path must be a string. Received " + JSON.stringify(n));\n }\n function t(n, s) {\n for (var o = "", a = 0, l = -1, h = 0, c, u = 0; u <= n.length; ++u) {\n if (u < n.length)\n c = n.charCodeAt(u);\n else {\n if (c === 47)\n break;\n c = 47;\n }\n if (c === 47) {\n if (!(l === u - 1 || h === 1)) if (l !== u - 1 && h === 2) {\n if (o.length < 2 || a !== 2 || o.charCodeAt(o.length - 1) !== 46 || o.charCodeAt(o.length - 2) !== 46) {\n if (o.length > 2) {\n var p = o.lastIndexOf("/");\n if (p !== o.length - 1) {\n p === -1 ? (o = "", a = 0) : (o = o.slice(0, p), a = o.length - 1 - o.lastIndexOf("/")), l = u, h = 0;\n continue;\n }\n } else if (o.length === 2 || o.length === 1) {\n o = "", a = 0, l = u, h = 0;\n continue;\n }\n }\n s && (o.length > 0 ? o += "/.." : o = "..", a = 2);\n } else\n o.length > 0 ? o += "/" + n.slice(l + 1, u) : o = n.slice(l + 1, u), a = u - l - 1;\n l = u, h = 0;\n } else c === 46 && h !== -1 ? ++h : h = -1;\n }\n return o;\n }\n function e(n, s) {\n var o = s.dir || s.root, a = s.base || (s.name || "") + (s.ext || "");\n return o ? o === s.root ? o + a : o + n + a : a;\n }\n var i = {\n // path.resolve([from ...], to)\n resolve: function() {\n for (var s = "", o = !1, a, l = arguments.length - 1; l >= -1 && !o; l--) {\n var h;\n l >= 0 ? h = arguments[l] : (a === void 0 && (a = process.cwd()), h = a), r(h), h.length !== 0 && (s = h + "/" + s, o = h.charCodeAt(0) === 47);\n }\n return s = t(s, !o), o ? s.length > 0 ? "/" + s : "/" : s.length > 0 ? s : ".";\n },\n normalize: function(s) {\n if (r(s), s.length === 0) return ".";\n var o = s.charCodeAt(0) === 47, a = s.charCodeAt(s.length - 1) === 47;\n return s = t(s, !o), s.length === 0 && !o && (s = "."), s.length > 0 && a && (s += "/"), o ? "/" + s : s;\n },\n isAbsolute: function(s) {\n return r(s), s.length > 0 && s.charCodeAt(0) === 47;\n },\n join: function() {\n if (arguments.length === 0)\n return ".";\n for (var s, o = 0; o < arguments.length; ++o) {\n var a = arguments[o];\n r(a), a.length > 0 && (s === void 0 ? s = a : s += "/" + a);\n }\n return s === void 0 ? "." : i.normalize(s);\n },\n relative: function(s, o) {\n if (r(s), r(o), s === o || (s = i.resolve(s), o = i.resolve(o), s === o)) return "";\n for (var a = 1; a < s.length && s.charCodeAt(a) === 47; ++a)\n ;\n for (var l = s.length, h = l - a, c = 1; c < o.length && o.charCodeAt(c) === 47; ++c)\n ;\n for (var u = o.length, p = u - c, g = h < p ? h : p, d = -1, f = 0; f <= g; ++f) {\n if (f === g) {\n if (p > g) {\n if (o.charCodeAt(c + f) === 47)\n return o.slice(c + f + 1);\n if (f === 0)\n return o.slice(c + f);\n } else h > g && (s.charCodeAt(a + f) === 47 ? d = f : f === 0 && (d = 0));\n break;\n }\n var w = s.charCodeAt(a + f), P = o.charCodeAt(c + f);\n if (w !== P)\n break;\n w === 47 && (d = f);\n }\n var R = "";\n for (f = a + d + 1; f <= l; ++f)\n (f === l || s.charCodeAt(f) === 47) && (R.length === 0 ? R += ".." : R += "/..");\n return R.length > 0 ? R + o.slice(c + d) : (c += d, o.charCodeAt(c) === 47 && ++c, o.slice(c));\n },\n _makeLong: function(s) {\n return s;\n },\n dirname: function(s) {\n if (r(s), s.length === 0) return ".";\n for (var o = s.charCodeAt(0), a = o === 47, l = -1, h = !0, c = s.length - 1; c >= 1; --c)\n if (o = s.charCodeAt(c), o === 47) {\n if (!h) {\n l = c;\n break;\n }\n } else\n h = !1;\n return l === -1 ? a ? "/" : "." : a && l === 1 ? "//" : s.slice(0, l);\n },\n basename: function(s, o) {\n if (o !== void 0 && typeof o != "string") throw new TypeError(\'"ext" argument must be a string\');\n r(s);\n var a = 0, l = -1, h = !0, c;\n if (o !== void 0 && o.length > 0 && o.length <= s.length) {\n if (o.length === s.length && o === s) return "";\n var u = o.length - 1, p = -1;\n for (c = s.length - 1; c >= 0; --c) {\n var g = s.charCodeAt(c);\n if (g === 47) {\n if (!h) {\n a = c + 1;\n break;\n }\n } else\n p === -1 && (h = !1, p = c + 1), u >= 0 && (g === o.charCodeAt(u) ? --u === -1 && (l = c) : (u = -1, l = p));\n }\n return a === l ? l = p : l === -1 && (l = s.length), s.slice(a, l);\n } else {\n for (c = s.length - 1; c >= 0; --c)\n if (s.charCodeAt(c) === 47) {\n if (!h) {\n a = c + 1;\n break;\n }\n } else l === -1 && (h = !1, l = c + 1);\n return l === -1 ? "" : s.slice(a, l);\n }\n },\n extname: function(s) {\n r(s);\n for (var o = -1, a = 0, l = -1, h = !0, c = 0, u = s.length - 1; u >= 0; --u) {\n var p = s.charCodeAt(u);\n if (p === 47) {\n if (!h) {\n a = u + 1;\n break;\n }\n continue;\n }\n l === -1 && (h = !1, l = u + 1), p === 46 ? o === -1 ? o = u : c !== 1 && (c = 1) : o !== -1 && (c = -1);\n }\n return o === -1 || l === -1 || // We saw a non-dot character immediately before the dot\n c === 0 || // The (right-most) trimmed path component is exactly \'..\'\n c === 1 && o === l - 1 && o === a + 1 ? "" : s.slice(o, l);\n },\n format: function(s) {\n if (s === null || typeof s != "object")\n throw new TypeError(\'The "pathObject" argument must be of type Object. Received type \' + typeof s);\n return e("/", s);\n },\n parse: function(s) {\n r(s);\n var o = { root: "", dir: "", base: "", ext: "", name: "" };\n if (s.length === 0) return o;\n var a = s.charCodeAt(0), l = a === 47, h;\n l ? (o.root = "/", h = 1) : h = 0;\n for (var c = -1, u = 0, p = -1, g = !0, d = s.length - 1, f = 0; d >= h; --d) {\n if (a = s.charCodeAt(d), a === 47) {\n if (!g) {\n u = d + 1;\n break;\n }\n continue;\n }\n p === -1 && (g = !1, p = d + 1), a === 46 ? c === -1 ? c = d : f !== 1 && (f = 1) : c !== -1 && (f = -1);\n }\n return c === -1 || p === -1 || // We saw a non-dot character immediately before the dot\n f === 0 || // The (right-most) trimmed path component is exactly \'..\'\n f === 1 && c === p - 1 && c === u + 1 ? p !== -1 && (u === 0 && l ? o.base = o.name = s.slice(1, p) : o.base = o.name = s.slice(u, p)) : (u === 0 && l ? (o.name = s.slice(1, c), o.base = s.slice(1, p)) : (o.name = s.slice(u, c), o.base = s.slice(u, p)), o.ext = s.slice(c, p)), u > 0 ? o.dir = s.slice(0, u - 1) : l && (o.dir = "/"), o;\n },\n sep: "/",\n delimiter: ":",\n win32: null,\n posix: null\n };\n return i.posix = i, me = i, me;\n}\nvar Xt = Rs();\nconst As = { description: "Attempts to filter out paragraphs that are implicitly headings or part of headers", scope: "RS", value: "readium-experimentalHeaderFiltering-on" }, Ts = { description: "Attempts to filter out elements that are sized using viewport units and should not be scaled directly e.g. tables, images, iframes, etc.", scope: "RS", value: "readium-experimentalZoom-on" }, Ns = {\n experimentalHeaderFiltering: As,\n experimentalZoom: Ts\n}, Ms = { disabled: [], added: [] }, Fs = { disabled: ["bodyHyphens", "a11yNormalize", "letterSpacing"], added: [] }, Is = {\n ltr: Ms,\n rtl: Fs,\n "cjk-horizontal": { disabled: ["textAlign", "bodyHyphens", "a11yNormalize", "ligatures", "paraIndent", "wordSpacing"], added: ["noRuby"] },\n "cjk-vertical": { disabled: ["colCount", "textAlign", "bodyHyphens", "a11yNormalize", "ligatures", "paraIndent", "wordSpacing"], added: ["noRuby"] }\n}, zs = { baseFontFamily: "var(--RS__oldStyleTf)", lineHeightCompensation: 1 }, Ds = { baseFontFamily: "Kefa, Nyala, Roboto, Noto, \'Noto Sans Ethiopic\', serif", lineHeightCompensation: 1.167 }, Ws = { baseFontFamily: "\'Geeza Pro\', \'Arabic Typesetting\', Roboto, Noto, \'Noto Naskh Arabic\', \'Times New Roman\', serif" }, Us = { baseFontFamily: "\'Kohinoor Bangla\', \'Bangla Sangam MN\', Vrinda, Roboto, Noto, \'Noto Sans Bengali\', sans-serif", lineHeightCompensation: 1.067 }, Hs = { baseFontFamily: "Kailasa, \'Microsoft Himalaya\', Roboto, Noto, \'Noto Sans Tibetan\', sans-serif" }, Bs = { baseFontFamily: "\'Plantagenet Cherokee\', Roboto, Noto, \'Noto Sans Cherokee\'", lineHeightCompensation: 1.167 }, Vs = { baseFontFamily: "\'Geeza Pro\', \'Arabic Typesetting\', Roboto, Noto, \'Noto Naskh Arabic\', \'Times New Roman\', serif" }, js = { baseFontFamily: "\'Gujarati Sangam MN\', \'Nirmala UI\', Shruti, Roboto, Noto, \'Noto Sans Gujarati\', sans-serif", lineHeightCompensation: 1.167 }, $s = { baseFontFamily: "\'New Peninim MT\', \'Arial Hebrew\', Gisha, \'Times New Roman\', Roboto, Noto, \'Noto Sans Hebrew\', sans-serif", lineHeightCompensation: 1.1 }, Gs = { baseFontFamily: "\'Kohinoor Devanagari\', \'Devanagari Sangam MN\', Kokila, \'Nirmala UI\', Roboto, Noto, \'Noto Sans Devanagari\', sans-serif", lineHeightCompensation: 1.1 }, Xs = { baseFontFamily: "Mshtakan, Sylfaen, Roboto, Noto, \'Noto Serif Armenian\', serif" }, Ys = { baseFontFamily: "\'Euphemia UCAS\', Euphemia, Roboto, Noto, \'Noto Sans Canadian Aboriginal\', sans-serif" }, qs = { baseFontFamily: "YuGothic, \'Hiragino Maru Gothic ProN\', \'Hiragino Sans\', \'Yu Gothic UI\', \'Meiryo UI\', \'MS Gothic\', Roboto, Noto, \'Noto Sans CJK JP\', sans-serif", lineHeightCompensation: 1.167 }, Ks = { baseFontFamily: "\'Khmer Sangam MN\', \'Leelawadee UI\', \'Khmer UI\', Roboto, Noto, \'Noto Sans Khmer\', sans-serif", lineHeightCompensation: 1.067 }, Js = { baseFontFamily: "\'Kannada Sangam MN\', \'Nirmala UI\', Tunga, Roboto, Noto, \'Noto Sans Kannada\', sans-serif", lineHeightCompensation: 1.1 }, Zs = { baseFontFamily: "\'Nanum Gothic\', \'Apple SD Gothic Neo\', \'Malgun Gothic\', Roboto, Noto, \'Noto Sans CJK KR\', sans-serif", lineHeightCompensation: 1.167 }, Qs = { baseFontFamily: "\'Lao Sangam MN\', \'Leelawadee UI\', \'Lao UI\', Roboto, Noto, \'Noto Sans Lao\', sans-serif" }, tr = { baseFontFamily: "\'Malayalam Sangam MN\', \'Nirmala UI\', Kartika, Roboto, Noto, \'Noto Sans Malayalam\', sans-serif", lineHeightCompensation: 1.067 }, er = { baseFontFamily: "\'Oriya Sangam MN\', \'Nirmala UI\', Kalinga, Roboto, Noto, \'Noto Sans Oriya\', sans-serif", lineHeightCompensation: 1.167 }, ir = { baseFontFamily: "\'Gurmukhi MN\', \'Nirmala UI\', Kartika, Roboto, Noto, \'Noto Sans Gurmukhi\', sans-serif", lineHeightCompensation: 1.1 }, nr = { baseFontFamily: "\'Sinhala Sangam MN\', \'Nirmala UI\', \'Iskoola Pota\', Roboto, Noto, \'Noto Sans Sinhala\', sans-serif", lineHeightCompensation: 1.167 }, sr = { baseFontFamily: "\'Tamil Sangam MN\', \'Nirmala UI\', Latha, Roboto, Noto, \'Noto Sans Tamil\', sans-serif", lineHeightCompensation: 1.067 }, rr = { baseFontFamily: "\'Kohinoor Telugu\', \'Telugu Sangam MN\', \'Nirmala UI\', Gautami, Roboto, Noto, \'Noto Sans Telugu\', sans-serif" }, or = { baseFontFamily: "Thonburi, \'Leelawadee UI\', \'Cordia New\', Roboto, Noto, \'Noto Sans Thai\', sans-serif", lineHeightCompensation: 1.067 }, ar = { baseFontFamily: "\'方体\', \'PingFang SC\', \'黑体\', \'Heiti SC\', \'Microsoft JhengHei UI\', \'Microsoft JhengHei\', Roboto, Noto, \'Noto Sans CJK SC\', sans-serif", lineHeightCompensation: 1.167 }, lr = {\n latin: zs,\n am: Ds,\n ar: Ws,\n bn: Us,\n bo: Hs,\n chr: Bs,\n fa: Vs,\n gu: js,\n he: $s,\n hi: Gs,\n hy: Xs,\n iu: Ys,\n ja: qs,\n km: Ks,\n kn: Js,\n ko: Zs,\n lo: Qs,\n ml: tr,\n or: er,\n pa: ir,\n si: nr,\n ta: sr,\n te: rr,\n th: or,\n zh: ar,\n "zh-Hant": { baseFontFamily: "\'方體\', \'PingFang TC\', \'黑體\', \'Heiti TC\', \'Microsoft JhengHei UI\', \'Microsoft JhengHei\', Roboto, Noto, \'Noto Sans CJK TC\', sans-serif", lineHeightCompensation: 1.167 },\n "zh-TW": { baseFontFamily: "\'方體\', \'PingFang TC\', \'黑體\', \'Heiti TC\', \'Microsoft JhengHei UI\', \'Microsoft JhengHei\', Roboto, Noto, \'Noto Sans CJK TC\', sans-serif", lineHeightCompensation: 1.167 },\n "zh-HK": { baseFontFamily: "\'方體\', \'PingFang HK\', \'方體\', \'PingFang TC\', \'黑體\', \'Heiti TC\', \'Microsoft JhengHei UI\', \'Microsoft JhengHei\', Roboto, Noto, \'Noto Sans CJK TC\', sans-serif", lineHeightCompensation: 1.167 }\n}, Ge = Ns, fo = Is, mo = lr;\nvar tt = /* @__PURE__ */ ((r) => (r.start = "start", r.left = "left", r.right = "right", r.justify = "justify", r))(tt || {});\nconst dt = {\n range: [0, 100],\n step: 1\n}, Yt = {\n range: [0.7, 4],\n step: 0.05\n}, st = {\n range: [100, 1e3],\n step: 100\n}, qt = {\n range: [50, 250],\n step: 10\n}, Kt = {\n range: [0, 1],\n step: 0.125\n}, Jt = {\n range: [1, 2.5],\n step: 0.1\n}, ut = {\n range: [20, 100],\n step: 1\n}, Zt = {\n range: [0, 3],\n step: 0.25\n}, Qt = {\n range: [0, 3],\n step: 0.25\n}, te = {\n range: [0, 2],\n step: 0.125\n}, ee = {\n range: [0.7, 4],\n step: 0.05\n}, ie = {\n range: [0, 1],\n step: 0.1\n}, ne = {\n range: [0.5, 4],\n step: 0.1\n}, it = {\n range: [5, 60],\n step: 5\n};\nclass le {\n constructor() {\n }\n toFlag(t) {\n return `readium-${t}-on`;\n }\n toUnitless(t) {\n return t.toString();\n }\n toPercentage(t, e = !1) {\n return e || t > 0 && t <= 1 ? `${Math.round(t * 100)}%` : `${t}%`;\n }\n toVw(t) {\n const e = Math.round(t * 100);\n return `${Math.min(e, 100)}vw`;\n }\n toVh(t) {\n const e = Math.round(t * 100);\n return `${Math.min(e, 100)}vh`;\n }\n toPx(t) {\n return `${t}px`;\n }\n toRem(t) {\n return `${t}rem`;\n }\n}\nclass mn extends le {\n constructor(t) {\n super(), this.a11yNormalize = t.a11yNormalize ?? null, this.bodyHyphens = t.bodyHyphens ?? null, this.fontFamily = t.fontFamily ?? null, this.fontWeight = t.fontWeight ?? null, this.iOSPatch = t.iOSPatch ?? null, this.iPadOSPatch = t.iPadOSPatch ?? null, this.letterSpacing = t.letterSpacing ?? null, this.ligatures = t.ligatures ?? null, this.lineHeight = t.lineHeight ?? null, this.noRuby = t.noRuby ?? null, this.paraIndent = t.paraIndent ?? null, this.paraSpacing = t.paraSpacing ?? null, this.textAlign = t.textAlign ?? null, this.wordSpacing = t.wordSpacing ?? null, this.zoom = t.zoom ?? null;\n }\n toCSSProperties() {\n const t = {};\n return this.a11yNormalize && (t["--USER__a11yNormalize"] = this.toFlag("a11y")), this.bodyHyphens && (t["--USER__bodyHyphens"] = this.bodyHyphens), this.fontFamily && (t["--USER__fontFamily"] = this.fontFamily), this.fontWeight != null && (t["--USER__fontWeight"] = this.toUnitless(this.fontWeight)), this.iOSPatch && (t["--USER__iOSPatch"] = this.toFlag("iOSPatch")), this.iPadOSPatch && (t["--USER__iPadOSPatch"] = this.toFlag("iPadOSPatch")), this.letterSpacing != null && (t["--USER__letterSpacing"] = this.toRem(this.letterSpacing)), this.ligatures && (t["--USER__ligatures"] = this.ligatures), this.lineHeight != null && (t["--USER__lineHeight"] = this.toUnitless(this.lineHeight)), this.noRuby && (t["--USER__noRuby"] = this.toFlag("noRuby")), this.paraIndent != null && (t["--USER__paraIndent"] = this.toRem(this.paraIndent)), this.paraSpacing != null && (t["--USER__paraSpacing"] = this.toRem(this.paraSpacing)), this.textAlign && (t["--USER__textAlign"] = this.textAlign), this.wordSpacing != null && (t["--USER__wordSpacing"] = this.toRem(this.wordSpacing)), this.zoom !== null && (t["--USER__zoom"] = this.toPercentage(this.zoom, !0)), t;\n }\n}\nclass hr extends le {\n constructor(t) {\n super(), this.experiments = t.experiments ?? null;\n }\n toCSSProperties() {\n const t = {};\n return this.experiments && this.experiments.forEach((e) => {\n t["--RS__" + e] = Ge[e].value;\n }), t;\n }\n}\nclass cr {\n constructor(t) {\n this.rsProperties = t.rsProperties, this.userProperties = t.userProperties;\n }\n update(t) {\n t.experiments && (this.rsProperties.experiments = t.experiments);\n const e = {\n a11yNormalize: t.textNormalization,\n bodyHyphens: typeof t.hyphens != "boolean" ? null : t.hyphens ? "auto" : "none",\n fontFamily: t.fontFamily,\n fontWeight: t.fontWeight,\n iOSPatch: t.iOSPatch,\n iPadOSPatch: t.iPadOSPatch,\n letterSpacing: t.letterSpacing,\n ligatures: typeof t.ligatures != "boolean" ? null : t.ligatures ? "common-ligatures" : "none",\n lineHeight: t.lineHeight,\n noRuby: t.noRuby,\n paraIndent: t.paragraphIndent,\n paraSpacing: t.paragraphSpacing,\n textAlign: t.textAlign,\n wordSpacing: t.wordSpacing,\n zoom: t.zoom\n };\n this.userProperties = new mn(e);\n }\n}\nfunction dr(r, t) {\n return r == null || t == null || r <= t ? r : void 0;\n}\nfunction ur(r, t) {\n return r == null || t == null || r >= t ? r : void 0;\n}\nfunction W(r) {\n return typeof r == "string" ? r : r === null ? null : void 0;\n}\nfunction E(r) {\n return typeof r == "boolean" || r == null ? r : void 0;\n}\nfunction he(r, t) {\n if (r !== void 0)\n return r === null ? null : t[r] !== void 0 ? r : void 0;\n}\nfunction wt(r) {\n return typeof r == "boolean" || typeof r == "number" && r >= 0 ? r : r === null ? null : void 0;\n}\nfunction S(r) {\n if (r !== void 0)\n return r === null ? null : r < 0 ? void 0 : r;\n}\nfunction F(r, t) {\n if (r === void 0)\n return;\n if (r === null)\n return null;\n const e = Math.min(...t), i = Math.max(...t);\n return r >= e && r <= i ? r : void 0;\n}\nfunction ge(r, t) {\n return r === void 0 ? t : r;\n}\nfunction gn(r) {\n if (r !== void 0)\n return r === null ? null : r.filter((t) => t in Ge);\n}\nclass Mt {\n constructor(t = {}) {\n this.fontFamily = W(t.fontFamily), this.fontWeight = F(t.fontWeight, st.range), this.hyphens = E(t.hyphens), this.iOSPatch = E(t.iOSPatch), this.iPadOSPatch = E(t.iPadOSPatch), this.letterSpacing = S(t.letterSpacing), this.ligatures = E(t.ligatures), this.lineHeight = S(t.lineHeight), this.noRuby = E(t.noRuby), this.paragraphIndent = S(t.paragraphIndent), this.paragraphSpacing = S(t.paragraphSpacing), this.textAlign = he(t.textAlign, tt), this.textNormalization = E(t.textNormalization), this.wordSpacing = S(t.wordSpacing), this.zoom = F(t.zoom, ee.range);\n }\n static serialize(t) {\n const { ...e } = t;\n return JSON.stringify(e);\n }\n static deserialize(t) {\n try {\n const e = JSON.parse(t);\n return new Mt(e);\n } catch (e) {\n return console.error("Failed to deserialize preferences:", e), null;\n }\n }\n merging(t) {\n const e = { ...this };\n for (const i of Object.keys(t))\n t[i] !== void 0 && (e[i] = t[i]);\n return new Mt(e);\n }\n}\nclass pr {\n constructor(t) {\n this.fontFamily = W(t.fontFamily) || null, this.fontWeight = F(t.fontWeight, st.range) || null, this.hyphens = E(t.hyphens) ?? null, this.iOSPatch = t.iOSPatch === !1 ? !1 : (T.OS.iOS || T.OS.iPadOS) && T.iOSRequest === "mobile", this.iPadOSPatch = t.iPadOSPatch === !1 ? !1 : T.OS.iPadOS && T.iOSRequest === "desktop", this.letterSpacing = S(t.letterSpacing) || null, this.ligatures = E(t.ligatures) ?? null, this.lineHeight = S(t.lineHeight) || null, this.noRuby = E(t.noRuby) ?? !1, this.paragraphIndent = S(t.paragraphIndent) ?? null, this.paragraphSpacing = S(t.paragraphSpacing) ?? null, this.textAlign = he(t.textAlign, tt) || null, this.textNormalization = E(t.textNormalization) ?? !1, this.wordSpacing = S(t.wordSpacing) || null, this.zoom = F(t.zoom, ee.range) || 1, this.experiments = gn(t.experiments) ?? null;\n }\n}\nclass Ai {\n constructor(t, e, i) {\n this.fontFamily = null, this.fontWeight = null, this.hyphens = null, this.iOSPatch = null, this.iPadOSPatch = null, this.letterSpacing = null, this.ligatures = null, this.lineHeight = null, this.noRuby = null, this.paragraphIndent = null, this.paragraphSpacing = null, this.textAlign = null, this.textNormalization = null, this.wordSpacing = null, i && (this.fontFamily = t.fontFamily || e.fontFamily || null, this.fontWeight = t.fontWeight !== void 0 ? t.fontWeight : e.fontWeight !== void 0 ? e.fontWeight : null, this.hyphens = typeof t.hyphens == "boolean" ? t.hyphens : e.hyphens ?? null, this.iOSPatch = t.iOSPatch === !1 ? !1 : t.iOSPatch === !0 ? (T.OS.iOS || T.OS.iPadOS) && T.iOSRequest === "mobile" : e.iOSPatch, this.iPadOSPatch = t.iPadOSPatch === !1 ? !1 : t.iPadOSPatch === !0 ? T.OS.iPadOS && T.iOSRequest === "desktop" : e.iPadOSPatch, this.letterSpacing = t.letterSpacing !== void 0 ? t.letterSpacing : e.letterSpacing !== void 0 ? e.letterSpacing : null, this.ligatures = typeof t.ligatures == "boolean" ? t.ligatures : e.ligatures ?? null, this.lineHeight = t.lineHeight !== void 0 ? t.lineHeight : e.lineHeight !== void 0 ? e.lineHeight : null, this.noRuby = typeof t.noRuby == "boolean" ? t.noRuby : e.noRuby ?? null, this.paragraphIndent = t.paragraphIndent !== void 0 ? t.paragraphIndent : e.paragraphIndent !== void 0 ? e.paragraphIndent : null, this.paragraphSpacing = t.paragraphSpacing !== void 0 ? t.paragraphSpacing : e.paragraphSpacing !== void 0 ? e.paragraphSpacing : null, this.textAlign = t.textAlign || e.textAlign || null, this.textNormalization = typeof t.textNormalization == "boolean" ? t.textNormalization : e.textNormalization ?? null, this.wordSpacing = t.wordSpacing !== void 0 ? t.wordSpacing : e.wordSpacing !== void 0 ? e.wordSpacing : null), this.zoom = t.zoom !== void 0 ? t.zoom : e.zoom !== void 0 ? e.zoom : null, this.experiments = e.experiments || null;\n }\n}\nclass N {\n constructor({\n initialValue: t = null,\n effectiveValue: e,\n isEffective: i,\n onChange: n\n }) {\n this._value = t, this._effectiveValue = e, this._isEffective = i, this._onChange = n;\n }\n set value(t) {\n this._value = t, this._onChange(this._value);\n }\n get value() {\n return this._value;\n }\n get effectiveValue() {\n return this._effectiveValue;\n }\n get isEffective() {\n return this._isEffective;\n }\n clear() {\n this._value = null;\n }\n}\nclass A extends N {\n set value(t) {\n this._value = t, this._onChange(this._value);\n }\n get value() {\n return this._value;\n }\n get effectiveValue() {\n return this._effectiveValue;\n }\n get isEffective() {\n return this._isEffective;\n }\n clear() {\n this._value = null;\n }\n toggle() {\n this._value = !this._value, this._onChange(this._value);\n }\n}\nclass yn extends N {\n constructor({\n initialValue: t = null,\n effectiveValue: e,\n isEffective: i,\n onChange: n,\n supportedValues: s\n }) {\n super({ initialValue: t, effectiveValue: e, isEffective: i, onChange: n }), this._supportedValues = s;\n }\n set value(t) {\n if (t && !this._supportedValues.includes(t))\n throw new Error(`Value \'${String(t)}\' is not in the supported values for this preference.`);\n this._value = t, this._onChange(this._value);\n }\n get value() {\n return this._value;\n }\n get effectiveValue() {\n return this._effectiveValue;\n }\n get isEffective() {\n return this._isEffective;\n }\n get supportedValues() {\n return this._supportedValues;\n }\n clear() {\n this._value = null;\n }\n}\nclass x extends N {\n constructor({\n initialValue: t = null,\n effectiveValue: e,\n isEffective: i,\n onChange: n,\n supportedRange: s,\n step: o\n }) {\n super({ initialValue: t, effectiveValue: e, isEffective: i, onChange: n }), this._supportedRange = s, this._step = o, this._decimals = this._step.toString().includes(".") ? this._step.toString().split(".")[1].length : 0;\n }\n set value(t) {\n if (t && (t < this._supportedRange[0] || t > this._supportedRange[1]))\n throw new Error(`Value \'${String(t)}\' is out of the supported range for this preference.`);\n this._value = t, this._onChange(this._value);\n }\n get value() {\n return this._value;\n }\n get effectiveValue() {\n return this._effectiveValue;\n }\n get isEffective() {\n return this._isEffective;\n }\n get supportedRange() {\n return this._supportedRange;\n }\n get step() {\n return this._step;\n }\n increment() {\n this._value && this._value < this._supportedRange[1] && (this._value = Math.min(\n Math.round((this._value + this._step) * 10 ** this._decimals) / 10 ** this._decimals,\n this._supportedRange[1]\n ), this._onChange(this._value));\n }\n decrement() {\n this._value && this._value > this._supportedRange[0] && (this._value = Math.max(\n Math.round((this._value - this._step) * 10 ** this._decimals) / 10 ** this._decimals,\n this._supportedRange[0]\n ), this._onChange(this._value));\n }\n format(t) {\n return t.toString();\n }\n clear() {\n this._value = null;\n }\n}\nclass Ti {\n constructor(t, e, i) {\n this.preferences = t, this.settings = e, this.metadata = i;\n }\n clear() {\n this.preferences = new Mt({});\n }\n updatePreference(t, e) {\n this.preferences[t] = e;\n }\n get isDisplayTransformable() {\n return this.metadata?.accessibility?.feature?.some(\n (t) => t.value === Ht.DISPLAY_TRANSFORMABILITY.value\n ) ?? !1;\n }\n get fontFamily() {\n return new N({\n initialValue: this.preferences.fontFamily,\n effectiveValue: this.settings.fontFamily || null,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("fontFamily", t ?? null);\n }\n });\n }\n get fontWeight() {\n return new x({\n initialValue: this.preferences.fontWeight,\n effectiveValue: this.settings.fontWeight || 400,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("fontWeight", t ?? null);\n },\n supportedRange: st.range,\n step: st.step\n });\n }\n get hyphens() {\n return new A({\n initialValue: this.preferences.hyphens,\n effectiveValue: this.settings.hyphens || !1,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("hyphens", t ?? null);\n }\n });\n }\n get iOSPatch() {\n return new A({\n initialValue: this.preferences.iOSPatch,\n effectiveValue: this.settings.iOSPatch || !1,\n isEffective: !0,\n onChange: (t) => {\n this.updatePreference("iOSPatch", t ?? null);\n }\n });\n }\n get iPadOSPatch() {\n return new A({\n initialValue: this.preferences.iPadOSPatch,\n effectiveValue: this.settings.iPadOSPatch || !1,\n isEffective: !0,\n onChange: (t) => {\n this.updatePreference("iPadOSPatch", t ?? null);\n }\n });\n }\n get letterSpacing() {\n return new x({\n initialValue: this.preferences.letterSpacing,\n effectiveValue: this.settings.letterSpacing || 0,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("letterSpacing", t ?? null);\n },\n supportedRange: Kt.range,\n step: Kt.step\n });\n }\n get ligatures() {\n return new A({\n initialValue: this.preferences.ligatures,\n effectiveValue: this.settings.ligatures || !0,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("ligatures", t ?? null);\n }\n });\n }\n get lineHeight() {\n return new x({\n initialValue: this.preferences.lineHeight,\n effectiveValue: this.settings.lineHeight,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("lineHeight", t ?? null);\n },\n supportedRange: Jt.range,\n step: Jt.step\n });\n }\n get noRuby() {\n return new A({\n initialValue: this.preferences.noRuby,\n effectiveValue: this.settings.noRuby || !1,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("noRuby", t ?? null);\n }\n });\n }\n get paragraphIndent() {\n return new x({\n initialValue: this.preferences.paragraphIndent,\n effectiveValue: this.settings.paragraphIndent || 0,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("paragraphIndent", t ?? null);\n },\n supportedRange: Zt.range,\n step: Zt.step\n });\n }\n get paragraphSpacing() {\n return new x({\n initialValue: this.preferences.paragraphSpacing,\n effectiveValue: this.settings.paragraphSpacing || 0,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("paragraphSpacing", t ?? null);\n },\n supportedRange: Qt.range,\n step: Qt.step\n });\n }\n get textAlign() {\n return new yn({\n initialValue: this.preferences.textAlign,\n effectiveValue: this.settings.textAlign || tt.start,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("textAlign", t ?? null);\n },\n supportedValues: Object.values(tt)\n });\n }\n get textNormalization() {\n return new A({\n initialValue: this.preferences.textNormalization,\n effectiveValue: this.settings.textNormalization || !1,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("textNormalization", t ?? null);\n }\n });\n }\n get wordSpacing() {\n return new x({\n initialValue: this.preferences.wordSpacing,\n effectiveValue: this.settings.wordSpacing || 0,\n isEffective: this.isDisplayTransformable,\n onChange: (t) => {\n this.updatePreference("wordSpacing", t ?? null);\n },\n supportedRange: te.range,\n step: te.step\n });\n }\n get zoom() {\n return new x({\n initialValue: this.preferences.zoom,\n effectiveValue: this.settings.zoom || 1,\n isEffective: CSS.supports("zoom", "1") ?? !1,\n onChange: (t) => {\n this.updatePreference("zoom", t ?? null);\n },\n supportedRange: ee.range,\n step: ee.step\n });\n }\n}\nconst bn = (r) => {\n if ("blob" in r && r.blob.type)\n return r.blob.type;\n if (r.as === "script")\n return "text/javascript";\n if (r.as === "link" && "url" in r) {\n const t = r.url.toLowerCase();\n if (t.endsWith(".css")) return "text/css";\n if ([".js", ".mjs", ".cjs"].some((e) => t.endsWith(e))) return "text/javascript";\n }\n}, wn = (r, t) => {\n t.attributes && Object.entries(t.attributes).forEach(([e, i]) => {\n e === "type" || e === "rel" || e === "href" || e === "src" || i != null && (typeof i == "boolean" ? i && r.setAttribute(e, "") : r.setAttribute(e, i));\n });\n}, fr = (r, t, e) => {\n const i = r.createElement("script");\n i.dataset.readium = "true", t.id && (i.id = t.id);\n const n = t.type || bn(t);\n return n && (i.type = n), wn(i, t), i.src = e, i;\n}, Ni = (r, t, e) => {\n const i = r.createElement("link");\n i.dataset.readium = "true", t.id && (i.id = t.id), t.rel && (i.rel = t.rel);\n const n = t.type || bn(t);\n return n && (i.type = n), wn(i, t), i.href = e, i;\n};\nclass Sn {\n constructor(t) {\n this.blobStore = /* @__PURE__ */ new Map(), this.createdBlobUrls = /* @__PURE__ */ new Set(), this.allowedDomains = [], this.injectableIdCounter = 0, this.allowedDomains = (t.allowedDomains || []).map((e) => {\n try {\n return new URL(e), e;\n } catch {\n throw new Error(`Invalid allowed domain: "${e}". Must be a valid URL (e.g., "https://fonts.googleapis.com").`);\n }\n }), this.rules = t.rules.map((e) => {\n const i = { ...e };\n return e.prepend && (i.prepend = e.prepend.map((n) => ({\n ...n,\n id: n.id || `injectable-${this.injectableIdCounter++}`\n })).reverse()), e.append && (i.append = e.append.map((n) => ({\n ...n,\n id: n.id || `injectable-${this.injectableIdCounter++}`\n }))), i;\n });\n }\n dispose() {\n for (const t of this.createdBlobUrls)\n try {\n URL.revokeObjectURL(t);\n } catch (e) {\n console.warn("Failed to revoke blob URL:", t, e);\n }\n this.createdBlobUrls.clear();\n }\n getAllowedDomains() {\n return [...this.allowedDomains];\n }\n async injectForDocument(t, e) {\n for (const i of this.rules)\n this.matchesRule(i, e) && await this.applyRule(t, i);\n }\n matchesRule(t, e) {\n const i = e.href;\n return t.resources.some((n) => n instanceof RegExp ? n.test(i) : i === n);\n }\n async getOrCreateBlobUrl(t) {\n const e = t.id;\n if (this.blobStore.has(e)) {\n const i = this.blobStore.get(e);\n return i.refCount++, i.url;\n }\n if ("blob" in t) {\n const i = URL.createObjectURL(t.blob);\n return this.blobStore.set(e, { url: i, refCount: 1 }), this.createdBlobUrls.add(i), i;\n }\n throw new Error("Resource must have a blob property");\n }\n async releaseBlobUrl(t) {\n if (!this.createdBlobUrls.has(t)) return;\n const e = Array.from(this.blobStore.values()).find((i) => i.url === t);\n if (e && (e.refCount--, e.refCount <= 0)) {\n URL.revokeObjectURL(t), this.createdBlobUrls.delete(t);\n for (const [i, n] of this.blobStore.entries())\n if (n.url === t) {\n this.blobStore.delete(i);\n break;\n }\n }\n }\n async getResourceUrl(t, e) {\n if ("url" in t) {\n const i = new URL(t.url, e.baseURI).toString();\n if (!this.isValidUrl(i, e))\n throw new Error(`Invalid URL: Only HTTPS, data:, blob:, or localhost HTTP URLs are allowed. Got: ${t.url}`);\n return i;\n } else\n return this.getOrCreateBlobUrl(t);\n }\n createPreloadLink(t, e, i) {\n if (e.as !== "link" || e.rel !== "preload") return;\n const n = {\n ...e,\n rel: "preload",\n attributes: {\n ...e.attributes,\n as: e.as\n }\n }, s = Ni(t, n, i);\n t.head.appendChild(s);\n }\n createElement(t, e, i) {\n if (e.as === "script")\n return fr(t, e, i);\n if (e.as === "link")\n return Ni(t, e, i);\n throw new Error(`Unsupported element type: ${e.as}`);\n }\n async applyRule(t, e) {\n const i = [], n = e.prepend ? e.prepend.filter(\n (o) => !o.condition || o.condition(t)\n ) : [], s = e.append ? e.append.filter(\n (o) => !o.condition || o.condition(t)\n ) : [];\n try {\n for (const o of n)\n await this.processInjectable(o, t, i, "prepend");\n for (const o of s)\n await this.processInjectable(o, t, i, "append");\n } catch (o) {\n for (const { element: a, url: l } of i)\n try {\n a.remove(), await this.releaseBlobUrl(l);\n } catch (h) {\n console.error("Error during cleanup:", h);\n }\n throw o;\n }\n }\n async processInjectable(t, e, i, n) {\n const s = t.target === "body" ? e.body : e.head;\n if (!s) return;\n let o = null;\n try {\n if (o = await this.getResourceUrl(t, e), t.rel === "preload" && "url" in t)\n this.createPreloadLink(e, t, o);\n else {\n const a = this.createElement(e, t, o);\n i.push({ element: a, url: o }), n === "prepend" ? s.prepend(a) : s.append(a);\n }\n } catch (a) {\n throw console.error("Failed to process resource:", a), o && "blob" in t && await this.releaseBlobUrl(o), a;\n }\n }\n isValidUrl(t, e) {\n try {\n const i = new URL(t, e.baseURI);\n if (i.protocol === "data:" || i.protocol === "blob:" && this.createdBlobUrls.has(t))\n return !0;\n if (this.allowedDomains.length > 0) {\n const n = i.origin;\n return this.allowedDomains.some((s) => {\n const o = new URL(s).origin;\n return n === o;\n });\n }\n return !1;\n } catch {\n return !1;\n }\n }\n}\nconst St = (r) => r.replace(/\\/\\/.*/g, "").replace(/\\/\\*[\\s\\S]*?\\*\\//g, "").replace(/\\n/g, "").replace(/\\s+/g, " "), _t = (r) => r.replace(/\\/\\*(?:(?!\\*\\/)[\\s\\S])*\\*\\/|[\\r\\n\\t]+/g, "").replace(/ {2,}/g, " "), mr = `/*!\n * Readium CSS v.2.0.5\n * Copyright (c) 2017–2026. Readium Foundation. All rights reserved.\n * Use of this source code is governed by a BSD-style license which is detailed in the\n * LICENSE file present in the project repository where this source code is maintained.\n * Core maintainer: Jiminy Panoz \n * Contributors: \n * Daniel Weck\n * Hadrien Gardeur\n * Innovimax\n * L. Le Meur\n * Mickaël Menu\n * k_taka\n */\n\n:root[style*="--USER__textAlign"]{\n text-align:var(--USER__textAlign);\n}\n\n:root[style*="--USER__textAlign"] body,\n:root[style*="--USER__textAlign"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n),\n:root[style*="--USER__textAlign"] li,\n:root[style*="--USER__textAlign"] dd{\n text-align:var(--USER__textAlign) !important;\n -moz-text-align-last:auto !important;\n -epub-text-align-last:auto !important;\n text-align-last:auto !important;\n}\n\n:root[style*="--USER__bodyHyphens"]{\n -webkit-hyphens:var(--USER__bodyHyphens) !important;\n -moz-hyphens:var(--USER__bodyHyphens) !important;\n -ms-hyphens:var(--USER__bodyHyphens) !important;\n -epub-hyphens:var(--USER__bodyHyphens) !important;\n hyphens:var(--USER__bodyHyphens) !important;\n}\n\n:root[style*="--USER__bodyHyphens"] body,\n:root[style*="--USER__bodyHyphens"] p,\n:root[style*="--USER__bodyHyphens"] li,\n:root[style*="--USER__bodyHyphens"] div,\n:root[style*="--USER__bodyHyphens"] dd{\n -webkit-hyphens:var(--USER__bodyHyphens) !important;\n -moz-hyphens:var(--USER__bodyHyphens) !important;\n -ms-hyphens:var(--USER__bodyHyphens) !important;\n -epub-hyphens:var(--USER__bodyHyphens) !important;\n hyphens:var(--USER__bodyHyphens) !important;\n}\n\n:root[style*="--USER__fontFamily"]{\n font-family:var(--USER__fontFamily) !important;\n}\n\n:root[style*="--USER__fontFamily"] *{\n font-family:revert !important;\n}\n\n:root[style*="readium-a11y-on"]{\n font-style:normal !important;\n font-weight:normal !important;\n}\n\n:root[style*="readium-a11y-on"] body *:not(code):not(var):not(kbd):not(samp){\n font-family:inherit !important;\n font-style:inherit !important;\n font-weight:inherit !important;\n}\n\n:root[style*="readium-a11y-on"] body *:not(a){\n text-decoration:none !important;\n}\n\n:root[style*="readium-a11y-on"] body *{\n font-variant-caps:normal !important;\n font-variant-numeric:normal !important;\n font-variant-position:normal !important;\n}\n\n:root[style*="readium-a11y-on"] sup,\n:root[style*="readium-a11y-on"] sub{\n font-size:1rem !important;\n vertical-align:baseline !important;\n}\n\n:root:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] body{\n zoom:var(--USER__zoom) !important;\n}\n\n:root[style*="readium-iOSPatch-on"][style*="--USER__zoom"] body{\n -webkit-text-size-adjust:var(--USER__zoom) !important;\n}\n\n@supports selector(figure:has(> img)){\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> img),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> video),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> svg),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> canvas),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> iframe),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figure:has(> audio),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> img:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> video:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> svg:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> canvas:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> iframe:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] div:has(> audio:only-child),\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] table{\n zoom:calc(100% / var(--USER__zoom)) !important;\n }\n\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] figcaption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] caption,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] td,\n :root[style*="readium-experimentalZoom-on"]:not([style*="readium-iOSPatch-on"])[style*="--USER__zoom"] th{\n zoom:var(--USER__zoom) !important;\n }\n}\n\n:root[style*="--USER__lineHeight"]{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__lineHeight"] body,\n:root[style*="--USER__lineHeight"] p,\n:root[style*="--USER__lineHeight"] li,\n:root[style*="--USER__lineHeight"] div{\n line-height:var(--USER__lineHeight) !important;\n}\n\n:root[style*="--USER__paraSpacing"] p{\n margin-top:var(--USER__paraSpacing) !important;\n margin-bottom:var(--USER__paraSpacing) !important;\n}\n\n:root[style*="--USER__paraIndent"] p:not(\n blockquote p,\n figcaption p,\n header p,\n hgroup p,\n :root[style*="readium-experimentalHeaderFiltering-on"] p[class*="title"],\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > h1 + p,\n :root[style*="readium-experimentalHeaderFiltering-on"] div:has(+ *) > p:has(+ h1)\n){\n text-indent:var(--USER__paraIndent) !important;\n}\n\n:root[style*="--USER__paraIndent"] p *{\n text-indent:0 !important;\n}\n\n:root[style*="--USER__wordSpacing"] h1,\n:root[style*="--USER__wordSpacing"] h2,\n:root[style*="--USER__wordSpacing"] h3,\n:root[style*="--USER__wordSpacing"] h4,\n:root[style*="--USER__wordSpacing"] h5,\n:root[style*="--USER__wordSpacing"] h6,\n:root[style*="--USER__wordSpacing"] p,\n:root[style*="--USER__wordSpacing"] li,\n:root[style*="--USER__wordSpacing"] div,\n:root[style*="--USER__wordSpacing"] dt,\n:root[style*="--USER__wordSpacing"] dd{\n word-spacing:var(--USER__wordSpacing) !important;\n}\n\n:root[style*="--USER__letterSpacing"] h1,\n:root[style*="--USER__letterSpacing"] h2,\n:root[style*="--USER__letterSpacing"] h3,\n:root[style*="--USER__letterSpacing"] h4,\n:root[style*="--USER__letterSpacing"] h5,\n:root[style*="--USER__letterSpacing"] h6,\n:root[style*="--USER__letterSpacing"] p,\n:root[style*="--USER__letterSpacing"] li,\n:root[style*="--USER__letterSpacing"] div,\n:root[style*="--USER__letterSpacing"] dt,\n:root[style*="--USER__letterSpacing"] dd{\n letter-spacing:var(--USER__letterSpacing) !important;\n font-variant:none !important;\n}\n\n:root[style*="--USER__fontWeight"] body{\n font-weight:var(--USER__fontWeight) !important;\n}\n\n:root[style*="--USER__fontWeight"] b,\n:root[style*="--USER__fontWeight"] strong{\n font-weight:bolder;\n}\n\n:root[style*="--USER__fontWidth"] body{\n font-stretch:var(--USER__fontWidth) !important;\n}\n\n:root[style*="--USER__fontOpticalSizing"] body{\n font-optical-sizing:var(--USER__fontOpticalSizing) !important;\n}\n\n:root[style*="readium-noRuby-on"] body rt,\n:root[style*="readium-noRuby-on"] body rp{\n display:none;\n}\n\n:root[style*="--USER__ligatures"]{\n font-variant-ligatures:var(--USER__ligatures) !important;\n}\n\n:root[style*="--USER__ligatures"] *{\n font-variant-ligatures:inherit !important;\n}\n\n:root[style*="readium-iPadOSPatch-on"] body{\n -webkit-text-size-adjust:none;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p, \n:root[style*="readium-iPadOSPatch-on"] h1, \n:root[style*="readium-iPadOSPatch-on"] h2, \n:root[style*="readium-iPadOSPatch-on"] h3, \n:root[style*="readium-iPadOSPatch-on"] h4, \n:root[style*="readium-iPadOSPatch-on"] h5, \n:root[style*="readium-iPadOSPatch-on"] h6, \n:root[style*="readium-iPadOSPatch-on"] li, \n:root[style*="readium-iPadOSPatch-on"] th, \n:root[style*="readium-iPadOSPatch-on"] td, \n:root[style*="readium-iPadOSPatch-on"] dt, \n:root[style*="readium-iPadOSPatch-on"] dd, \n:root[style*="readium-iPadOSPatch-on"] pre, \n:root[style*="readium-iPadOSPatch-on"] address, \n:root[style*="readium-iPadOSPatch-on"] details, \n:root[style*="readium-iPadOSPatch-on"] summary,\n:root[style*="readium-iPadOSPatch-on"] figcaption,\n:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)),\n:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){\n -webkit-text-zoom:reset;\n}\n\n:root[style*="readium-iPadOSPatch-on"] abbr, \n:root[style*="readium-iPadOSPatch-on"] b, \n:root[style*="readium-iPadOSPatch-on"] bdi, \n:root[style*="readium-iPadOSPatch-on"] bdo, \n:root[style*="readium-iPadOSPatch-on"] cite, \n:root[style*="readium-iPadOSPatch-on"] code, \n:root[style*="readium-iPadOSPatch-on"] dfn, \n:root[style*="readium-iPadOSPatch-on"] em, \n:root[style*="readium-iPadOSPatch-on"] i, \n:root[style*="readium-iPadOSPatch-on"] kbd, \n:root[style*="readium-iPadOSPatch-on"] mark, \n:root[style*="readium-iPadOSPatch-on"] q, \n:root[style*="readium-iPadOSPatch-on"] rp, \n:root[style*="readium-iPadOSPatch-on"] rt, \n:root[style*="readium-iPadOSPatch-on"] ruby, \n:root[style*="readium-iPadOSPatch-on"] s, \n:root[style*="readium-iPadOSPatch-on"] samp, \n:root[style*="readium-iPadOSPatch-on"] small, \n:root[style*="readium-iPadOSPatch-on"] span, \n:root[style*="readium-iPadOSPatch-on"] strong, \n:root[style*="readium-iPadOSPatch-on"] sub, \n:root[style*="readium-iPadOSPatch-on"] sup, \n:root[style*="readium-iPadOSPatch-on"] time, \n:root[style*="readium-iPadOSPatch-on"] u, \n:root[style*="readium-iPadOSPatch-on"] var{\n -webkit-text-zoom:normal;\n}\n\n:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{\n -webkit-text-zoom:normal;\n}`, vn = \'!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports._readium_cssSelectorGenerator=e():t._readium_cssSelectorGenerator=e()}(self,(()=>(()=>{"use strict";var t={d:(e,n)=>{for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function n(t){return"object"==typeof t&&null!==t&&t.nodeType===Node.ELEMENT_NODE}t.r(e),t.d(e,{_readium_cssSelectorGenerator:()=>Z,default:()=>tt,getCssSelector:()=>X});const o={NONE:"",DESCENDANT:" ",CHILD:" > "},r={id:"id",class:"class",tag:"tag",attribute:"attribute",nthchild:"nthchild",nthoftype:"nthoftype"},i="_readium_cssSelectorGenerator";function c(t="unknown problem",...e){console.warn(`${i}: ${t}`,...e)}const s={selectors:[r.id,r.class,r.tag,r.attribute],includeTag:!1,whitelist:[],blacklist:[],combineWithinSelector:!0,combineBetweenSelectors:!0,root:null,maxCombinations:Number.POSITIVE_INFINITY,maxCandidates:Number.POSITIVE_INFINITY,useScope:!1};function u(t){return t instanceof RegExp}function l(t){return["string","function"].includes(typeof t)||u(t)}function a(t){return Array.isArray(t)?t.filter(l):[]}function f(t){const e=[Node.DOCUMENT_NODE,Node.DOCUMENT_FRAGMENT_NODE,Node.ELEMENT_NODE];return function(t){return t instanceof Node}(t)&&e.includes(t.nodeType)}function d(t,e){if(f(t))return t.contains(e)||c("element root mismatch","Provided root does not contain the element. This will most likely result in producing a fallback selector using element\\\'s real root node. If you plan to use the selector using provided root (e.g. `root.querySelector`), it will not work as intended."),t;const n=e.getRootNode({composed:!1});return f(n)?(n!==document&&c("shadow root inferred","You did not provide a root and the element is a child of Shadow DOM. This will produce a selector using ShadowRoot as a root. If you plan to use the selector using document as a root (e.g. `document.querySelector`), it will not work as intended."),n):S(e)}function m(t){return"number"==typeof t?t:Number.POSITIVE_INFINITY}function p(t=[]){const[e=[],...n]=t;return 0===n.length?e:n.reduce(((t,e)=>t.filter((t=>e.includes(t)))),e)}function g(t){const e=t.map((t=>{if(u(t))return e=>t.test(e);if("function"==typeof t)return e=>{const n=t(e);return"boolean"!=typeof n?(c("pattern matcher function invalid","Provided pattern matching function does not return boolean. It\\\'s result will be ignored.",t),!1):n};if("string"==typeof t){const e=new RegExp("^"+t.replace(/[|\\\\\\\\{}()[\\\\]^$+?.]/g,"\\\\\\\\$&").replace(/\\\\*/g,".+")+"$");return t=>e.test(t)}return c("pattern matcher invalid","Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.",t),()=>!1}));return t=>e.some((e=>e(t)))}function h(t,e,n){const o=Array.from(d(n,t[0]).querySelectorAll(e));return o.length===t.length&&t.every((t=>o.includes(t)))}function y(t,e){e=null!=e?e:S(t);const o=[];let r=t;for(;n(r)&&r!==e;)o.push(r),r=r.parentElement;return o}function b(t,e){return p(t.map((t=>y(t,e))))}function S(t){return t.ownerDocument.querySelector(":root")}const N=", ",v=new RegExp(["^$","\\\\\\\\s"].join("|")),E=new RegExp(["^$"].join("|")),x=[r.nthoftype,r.tag,r.id,r.class,r.attribute,r.nthchild],w=g(["class","id","ng-*"]);function I({name:t}){return`[${t}]`}function T({name:t,value:e}){return`[${t}=\\\'${e}\\\']`}function O({nodeName:t,nodeValue:e}){return{name:F(t),value:F(null!=e?e:void 0)}}function C(t){const e=Array.from(t.attributes).filter((e=>function({nodeName:t,nodeValue:e},n){const o=n.tagName.toLowerCase();return!(["input","option"].includes(o)&&"value"===t||"src"===t&&(null==e?void 0:e.startsWith("data:"))||w(t))}(e,t))).map(O);return[...e.map(I),...e.map(T)]}function j(t){var e;return(null!==(e=t.getAttribute("class"))&&void 0!==e?e:"").trim().split(/\\\\s+/).filter((t=>!E.test(t))).map((t=>`.${F(t)}`))}function A(t){var e;const n=null!==(e=t.getAttribute("id"))&&void 0!==e?e:"",o=`#${F(n)}`,r=t.getRootNode({composed:!1});return!v.test(n)&&h([t],o,r)?[o]:[]}function R(t){var e;const n=null===(e=t.parentElement)||void 0===e?void 0:e.children;if(n)for(let e=0;e1?[]:[e[0]]}function k(t){const e=D([t])[0],n=t.parentElement;if(n){const o=Array.from(n.children).filter((t=>t.tagName.toLowerCase()===e)),r=o.indexOf(t);if(r>-1)return[`${e}:nth-of-type(${String(r+1)})`]}return[]}function*P(t=[],{maxResults:e=Number.POSITIVE_INFINITY}={}){let n=0,o=L(1);for(;o.length<=t.length&&nt[e]));yield e,o=_(o,t.length-1)}}function _(t=[],e=0){const n=t.length;if(0===n)return[];const o=[...t];o[n-1]+=1;for(let t=n-1;t>=0;t--)if(o[t]>e){if(0===t)return L(n+1);o[t-1]++,o[t]=o[t-1]+1}return o[n-1]>e?L(n+1):o}function L(t=1){return Array.from(Array(t).keys())}const M=":".charCodeAt(0).toString(16).toUpperCase(),V=/[ !"#$%&\\\'()\\\\[\\\\]{|}<>*+,./;=?@^`~\\\\\\\\]/;function F(t=""){return CSS?CSS.escape(t):function(t=""){return t.split("").map((t=>":"===t?`\\\\\\\\${M} `:V.test(t)?`\\\\\\\\${t}`:escape(t).replace(/%/g,"\\\\\\\\"))).join("")}(t)}const Y={tag:D,id:function(t){return 0===t.length||t.length>1?[]:A(t[0])},class:function(t){return p(t.map(j))},attribute:function(t){return p(t.map(C))},nthchild:function(t){return p(t.map(R))},nthoftype:function(t){return p(t.map(k))}},G={tag:$,id:A,class:j,attribute:C,nthchild:R,nthoftype:k};function W(t){return t.includes(r.tag)||t.includes(r.nthoftype)?[...t]:[...t,r.tag]}function*q(t,e){const n={};for(const o of t){const t=e[o];t&&t.length>0&&(n[o]=t)}for(const t of function*(t={}){const e=Object.entries(t);if(0===e.length)return;const n=[{index:e.length-1,partial:{}}];for(;n.length>0;){const t=n.pop();if(!t)break;const{index:o,partial:r}=t;if(o<0){yield r;continue}const[i,c]=e[o];for(let t=c.length-1;t>=0;t--)n.push({index:o-1,partial:Object.assign(Object.assign({},r),{[i]:c[t]})})}}(n))yield B(t)}function B(t={}){const e=[...x];return t[r.tag]&&t[r.nthoftype]&&e.splice(e.indexOf(r.tag),1),e.map((e=>{return(o=t)[n=e]?o[n].join(""):"";var n,o})).join("")}function H(t,e){return[...t.map((t=>e+o.DESCENDANT+t)),...t.map((t=>e+o.CHILD+t))]}function*U(t,e,n="",o){const r=function*(t,e){const n=new Set,o=function(t,e){const{blacklist:n,whitelist:o,combineWithinSelector:r,maxCombinations:i}=e,c=g(n),s=g(o);return function(t){const{selectors:e,includeTag:n}=t,o=[...e];return n&&!o.includes("tag")&&o.push("tag"),o}(e).reduce(((e,n)=>{const o=function(t,e){return(0,Y[e])(t)}(t,n),u=function(t=[],e,n){return t.filter((t=>n(t)||!e(t)))}(o,c,s),l=function(t=[],e){return t.sort(((t,n)=>{const o=e(t),r=e(n);return o&&!r?-1:!o&&r?1:0}))}(u,s);return e[n]=r?Array.from(P(l,{maxResults:i})):l.map((t=>[t])),e}),{})}(t,e);for(const t of function*(t,e){for(const n of function(t){const{selectors:e,combineBetweenSelectors:n,includeTag:o,maxCandidates:r}=t,i=n?function(t=[],{maxResults:e=Number.POSITIVE_INFINITY}={}){return Array.from(P(t,{maxResults:e}))}(e,{maxResults:r}):e.map((t=>[t]));return o?i.map(W):i}(e))yield*q(n,t)}(o,e))n.has(t)||(n.add(t),yield t)}(t,o);for(const o of function*(t,e){if(""===e)yield*t;else for(const n of t)yield*H([n],e)}(r,n))h(t,o,e)&&(yield o)}function*z(t,e,n="",o){if(0===t.length)return null;const r=[t.length>1?t:[],...b(t,e).map((t=>[t]))];for(const t of r)for(const r of U(t,e,n,o))yield{foundElements:t,selector:r}}function J(t){return{value:t,include:!1}}function K({selectors:t,operator:e}){let n=[...x];t[r.tag]&&t[r.nthoftype]&&(n=n.filter((t=>t!==r.tag)));let o="";return n.forEach((e=>{var n;(null!==(n=t[e])&&void 0!==n?n:[]).forEach((({value:t,include:e})=>{e&&(o+=t)}))})),e+o}function Q(t,e){return t.map((t=>function(t,e){return[e?":scope":":root",...y(t,e).reverse().map((t=>{var e;const n=function(t,e,n=o.NONE){const r={};return e.forEach((e=>{Reflect.set(r,e,function(t,e){return G[e](t)}(t,e).map(J))})),{element:t,operator:n,selectors:r}}(t,[r.nthchild],o.CHILD);return(null!==(e=n.selectors.nthchild)&&void 0!==e?e:[]).forEach((t=>{t.include=!0})),n})).map(K)].join("")}(t,e))).join(N)}function X(t,e={}){return Z(t,Object.assign(Object.assign({},e),{maxResults:1})).next().value}function*Z(t,e={}){var o;const i=function(t){(t instanceof NodeList||t instanceof HTMLCollection)&&(t=Array.from(t));const e=(Array.isArray(t)?t:[t]).filter(n);return[...new Set(e)]}(t),c=function(t,e={}){const n=Object.assign(Object.assign({},s),e);return{selectors:(o=n.selectors,Array.isArray(o)?o.filter((t=>{return e=r,n=t,Object.values(e).includes(n);var e,n})):[]),whitelist:a(n.whitelist),blacklist:a(n.blacklist),root:d(n.root,t),combineWithinSelector:!!n.combineWithinSelector,combineBetweenSelectors:!!n.combineBetweenSelectors,includeTag:!!n.includeTag,maxCombinations:m(n.maxCombinations),maxCandidates:m(n.maxCandidates),useScope:!!n.useScope,maxResults:m(n.maxResults)};var o}(i[0],e),u=null!==(o=c.root)&&void 0!==o?o:S(i[0]);let l=0;for(const t of function*({elements:t,root:e,rootSelector:n="",options:o}){let r=e,i=n,c=!0;for(;c;){let n=!1;for(const c of z(t,r,i,o)){const{foundElements:o,selector:s}=c;if(n=!0,!h(t,s,e)){r=o[0],i=s;break}yield s}n||(c=!1)}}({elements:i,options:c,root:u,rootSelector:""}))if(yield t,l++,l>=c.maxResults)return;i.length>1&&(yield i.map((t=>X(t,c))).join(N),l++,l>=c.maxResults)||(yield Q(i,c.useScope?u:void 0))}const tt=X;return e})()));\', gr = `// WebPub-specific setup - no execution blocking needed\nwindow._readium_blockedEvents = [];\nwindow._readium_blockEvents = false; // WebPub doesn\'t need event blocking\nwindow._readium_eventBlocker = null;\n`, Pn = `(function() {\n if(window.onload) window.onload = new Proxy(window.onload, {\n apply: function(target, receiver, args) {\n if(!window._readium_blockEvents) {\n Reflect.apply(target, receiver, args);\n return;\n }\n _readium_blockedEvents.push([\n 0, target, receiver, args\n ]);\n }\n });\n})();\n`;\nfunction yr(r) {\n const t = r.filter((s) => s.mediaType.isHTML).map((s) => s.href), e = t.length > 0 ? t : [/\\.html$/, /\\.xhtml$/, /\\/$/], i = [\n // CSS Selector Generator - always injected\n {\n id: "css-selector-generator",\n as: "script",\n target: "head",\n blob: new Blob([St(vn)], { type: "text/javascript" })\n },\n // WebPub Execution - always injected (sets up event blocking to false)\n {\n id: "webpub-execution",\n as: "script",\n target: "head",\n blob: new Blob([St(gr)], { type: "text/javascript" })\n }\n ], n = [\n // Onload Proxy - conditional (has executable scripts)\n {\n id: "onload-proxy",\n as: "script",\n target: "head",\n blob: new Blob([St(Pn)], { type: "text/javascript" }),\n condition: (s) => !!(s.querySelector("script") || s.querySelector("body[onload]:not(body[onload=\'\'])"))\n },\n // Readium CSS WebPub - always injected\n {\n id: "readium-css-webpub",\n as: "link",\n target: "head",\n blob: new Blob([_t(mr)], { type: "text/css" }),\n rel: "stylesheet"\n }\n ];\n return [\n {\n resources: e,\n prepend: i,\n append: n\n }\n ];\n}\nclass br {\n constructor(t) {\n if (this.detectedTools = /* @__PURE__ */ new Set(), !t.onDetected)\n throw new Error("onDetected callback is required");\n this.options = t, this.setupDetection();\n }\n isAutomationToolPresent() {\n const t = window;\n return t.domAutomation || t.domAutomationController ? "Selenium" : navigator.webdriver === !0 ? "Puppeteer/Playwright" : t.__webdriver_evaluate || t.__selenium_evaluate ? "Chrome Automation" : t.callPhantom || t._phantom ? "PhantomJS" : t.__nightmare ? "Nightmare" : t.$testCafe ? "TestCafe" : null;\n }\n setupDetection() {\n const t = this.isAutomationToolPresent();\n if (t) {\n this.handleDetected(t);\n return;\n }\n this.observer = new MutationObserver(() => {\n const e = this.isAutomationToolPresent();\n e && !this.detectedTools.has(e) && this.handleDetected(e);\n }), this.observer.observe(document.documentElement, {\n childList: !0,\n subtree: !0,\n attributes: !0\n }), window.addEventListener("unload", () => this.destroy());\n }\n handleDetected(t) {\n this.detectedTools.add(t), this.options.onDetected?.(t);\n }\n destroy() {\n this.observer?.disconnect(), this.observer = void 0, this.detectedTools.clear();\n }\n}\nlet wr = 0;\nfunction Sr() {\n return ++wr;\n}\nconst vr = `\nonmessage = function(event) {\n var action = event.data;\n var startTime = performance.now()\n\n console[action.type](...action.payload);\n postMessage({\n id: action.id,\n time: performance.now() - startTime\n })\n}\n`, Je = class Je {\n constructor(t, e) {\n this.callbacks = /* @__PURE__ */ new Map(), this.worker = t, this.blobUrl = e, this.worker.onmessage = (i) => {\n const n = i.data, s = n.id, o = this.callbacks.get(n.id);\n o && (o({\n time: n.time\n }), this.callbacks.delete(s));\n }, this.log = (...i) => this.send("log", ...i), this.table = (...i) => this.send("table", ...i), this.clear = (...i) => this.send("clear", ...i);\n }\n async send(t, ...e) {\n const i = Sr();\n return new Promise((n, s) => {\n this.callbacks.set(i, n), this.worker.postMessage({\n id: i,\n type: t,\n payload: e\n }), setTimeout(() => {\n s(new Error("timeout")), this.callbacks.delete(i);\n }, 2e3);\n });\n }\n destroy() {\n this.worker.terminate(), URL.revokeObjectURL(this.blobUrl);\n }\n};\nJe.workerScript = vr;\nlet se = Je;\nfunction Xe(r) {\n return typeof window < "u" && console ? console[r] : (...t) => {\n };\n}\nconst Pr = Xe("log"), Mi = Xe("table"), Er = Xe("clear");\nasync function Fi() {\n if (typeof navigator < "u" && navigator.brave && navigator.brave.isBrave)\n try {\n return await Promise.race([\n navigator.brave.isBrave(),\n new Promise((r) => setTimeout(() => r(!1), 1e3))\n ]);\n } catch {\n return !0;\n }\n return !1;\n}\nfunction Cr(r) {\n return r.excludes.some((t) => t()) ? !1 : r.includes.some((t) => t());\n}\nclass _r {\n constructor(t = {}) {\n if (this.isOpen = !1, this.checkCount = 0, this.maxChecks = 10, this.maxPrintTime = 0, this.largeObjectArray = null, this.options = {\n onDetected: t.onDetected || (() => {\n }),\n onClosed: t.onClosed || (() => {\n }),\n interval: t.interval || 1e3,\n enableDebuggerDetection: t.enableDebuggerDetection || !1\n }, !J.UA.Firefox)\n try {\n const e = new Blob([se.workerScript], { type: "application/javascript" }), i = URL.createObjectURL(e), n = new Worker(i);\n this.workerConsole = new se(n, i);\n } catch (e) {\n console.warn("Failed to create Web Worker for DevTools detection:", e);\n }\n this.startDetection();\n }\n /**\n * Create large object array for performance testing\n */\n createLargeObjectArray() {\n const t = {};\n for (let i = 0; i < 500; i++)\n t[`${i}`] = `${i}`;\n const e = [];\n for (let i = 0; i < 50; i++)\n e.push(t);\n return e;\n }\n /**\n * Get cached large object array\n */\n getLargeObjectArray() {\n return this.largeObjectArray === null && (this.largeObjectArray = this.createLargeObjectArray()), this.largeObjectArray;\n }\n /**\n * Performance-based detection using console.table timing\n */\n async calcTablePrintTime() {\n const t = this.getLargeObjectArray();\n if (this.workerConsole)\n try {\n return (await this.workerConsole.table(t)).time;\n } catch {\n const i = performance.now();\n return Mi(t), performance.now() - i;\n }\n else {\n const e = performance.now();\n return Mi(t), performance.now() - e;\n }\n }\n /**\n * Performance-based detection using console.log timing\n */\n async calcLogPrintTime() {\n const t = this.getLargeObjectArray();\n if (this.workerConsole)\n return (await this.workerConsole.log(t)).time;\n {\n const e = performance.now();\n return Pr(t), performance.now() - e;\n }\n }\n /**\n * Check if performance-based detection is enabled for current browser\n */\n isPerformanceDetectionEnabled() {\n return Cr({\n includes: [\n () => !!J.UA.Chrome,\n () => !!J.UA.Chromium,\n () => !!J.UA.Safari,\n () => !!J.UA.Firefox\n ],\n excludes: []\n });\n }\n /**\n * Check if debugger detection is enabled for current browser\n */\n isDebuggerDetectionEnabled() {\n return this.options.enableDebuggerDetection;\n }\n /**\n * Performance-based detection using large object timing differences\n */\n async checkPerformanceBased() {\n if (!this.isPerformanceDetectionEnabled())\n return !1;\n const t = await this.calcTablePrintTime(), e = Math.max(await this.calcLogPrintTime(), await this.calcLogPrintTime());\n return this.maxPrintTime = Math.max(this.maxPrintTime, e), this.workerConsole ? await this.workerConsole.clear() : Er(), t === 0 ? !1 : this.maxPrintTime === 0 ? !!await Fi() : t > this.maxPrintTime * 10;\n }\n /**\n * Debugger-based detection (fallback method)\n * WARNING: This method impacts user experience\n */\n async checkDebuggerBased() {\n if (!this.isDebuggerDetectionEnabled() || await Fi())\n return !1;\n const t = performance.now();\n try {\n (() => {\n }).constructor("debugger")();\n } catch {\n debugger;\n }\n return performance.now() - t > 100;\n }\n /**\n * Main detection method combining multiple approaches\n * Prioritizes performance-based detection\n */\n async detectDevTools() {\n return await this.checkPerformanceBased() ? !0 : this.options.enableDebuggerDetection && this.checkCount >= this.maxChecks ? await this.checkDebuggerBased() : !1;\n }\n /**\n * Start continuous detection monitoring\n */\n startDetection() {\n this.intervalId = window.setInterval(async () => {\n this.checkCount++;\n const t = await this.detectDevTools();\n t !== this.isOpen && (this.isOpen = t, t ? this.options.onDetected() : this.options.onClosed()), this.checkCount > this.maxChecks * 2 && (this.checkCount = 0);\n }, this.options.interval), window.addEventListener("beforeunload", () => this.destroy());\n }\n /**\n * Get current DevTools state\n */\n isDevToolsOpen() {\n return this.isOpen;\n }\n /**\n * Force an immediate check\n */\n async checkNow() {\n const t = this.isOpen;\n return this.isOpen = await this.detectDevTools(), this.isOpen !== t && (this.isOpen ? this.options.onDetected() : this.options.onClosed()), this.isOpen;\n }\n /**\n * Stop detection and cleanup resources\n */\n destroy() {\n this.intervalId && (clearInterval(this.intervalId), this.intervalId = void 0), this.workerConsole && (this.workerConsole.destroy(), this.workerConsole = void 0), this.isOpen = !1, this.checkCount = 0;\n }\n}\nclass Lr {\n constructor(t) {\n if (this.detected = !1, !t.onDetected)\n throw new Error("onDetected callback is required");\n this.options = t, this.setupDetection();\n }\n isIframed() {\n try {\n return window.self !== window.top ? { isEmbedded: !0, isCrossOrigin: !window.top.location.href } : { isEmbedded: !1, isCrossOrigin: !1 };\n } catch {\n return { isEmbedded: !0, isCrossOrigin: !0 };\n }\n }\n setupDetection() {\n const { isEmbedded: t, isCrossOrigin: e } = this.isIframed();\n if (t) {\n this.handleDetected(e);\n return;\n }\n this.observer = new MutationObserver(() => {\n const { isEmbedded: i, isCrossOrigin: n } = this.isIframed();\n i && !this.detected && (this.handleDetected(n), this.observer?.disconnect());\n }), this.observer.observe(document.documentElement, {\n childList: !0,\n subtree: !0,\n attributes: !0\n }), window.addEventListener("unload", () => this.destroy());\n }\n handleDetected(t) {\n this.detected = !0, this.options.onDetected?.(t);\n }\n destroy() {\n this.observer?.disconnect(), this.observer = void 0, this.detected = !1;\n }\n}\nclass xr {\n constructor(t = {}) {\n this.styleElement = null, this.beforePrintHandler = null, this.onPrintAttempt = t.onPrintAttempt, t.disable && this.setupPrintProtection(t.watermark);\n }\n setupPrintProtection(t) {\n const e = document.createElement("style");\n e.textContent = `\n @media print {\n body * {\n display: none !important;\n }\n body::after {\n content: "${t || "Printing has been disabled"}";\n font-size: 200%;\n display: block;\n text-align: center;\n margin-top: 50vh;\n transform: translateY(-50%);\n }\n }\n `, document.head.appendChild(e), this.styleElement = e, this.beforePrintHandler = (i) => (i.preventDefault(), this.onPrintAttempt?.(), !1), window.addEventListener("beforeprint", this.beforePrintHandler);\n }\n destroy() {\n this.beforePrintHandler && (window.removeEventListener("beforeprint", this.beforePrintHandler), this.beforePrintHandler = null), this.styleElement?.parentNode && (this.styleElement.parentNode.removeChild(this.styleElement), this.styleElement = null);\n }\n}\nclass kr {\n constructor(t = {}) {\n this.onContextMenuBlocked = t.onContextMenuBlocked, this.contextMenuHandler = this.handleContextMenu.bind(this), document.addEventListener("contextmenu", this.contextMenuHandler, !0), window.addEventListener("unload", () => this.destroy());\n }\n handleContextMenu(t) {\n t.preventDefault(), t.stopPropagation();\n const e = {\n type: "context_menu",\n timestamp: Date.now(),\n clientX: t.clientX,\n clientY: t.clientY,\n targetFrameSrc: ""\n };\n return this.onContextMenuBlocked && this.onContextMenuBlocked(e), !1;\n }\n destroy() {\n this.contextMenuHandler && (document.removeEventListener("contextmenu", this.contextMenuHandler, !0), this.contextMenuHandler = void 0);\n }\n}\nconst ot = "readium:navigator:suspiciousActivity";\nclass Ye {\n dispatchSuspiciousActivity(t, e) {\n const i = new CustomEvent(ot, {\n detail: {\n type: t,\n timestamp: Date.now(),\n ...e\n }\n });\n window.dispatchEvent(i);\n }\n constructor(t = {}) {\n t.monitorDevTools && (this.devToolsDetector = new _r({\n onDetected: () => {\n this.dispatchSuspiciousActivity("developer_tools", {\n targetFrameSrc: "",\n key: "",\n code: "",\n keyCode: -1,\n ctrlKey: !1,\n altKey: !1,\n shiftKey: !1,\n metaKey: !1\n });\n }\n })), t.checkAutomation && (this.automationDetector = new br({\n onDetected: (e) => {\n this.dispatchSuspiciousActivity("automation_detected", { tool: e });\n }\n })), t.checkIFrameEmbedding && (this.iframeEmbeddingDetector = new Lr({\n onDetected: (e) => {\n this.dispatchSuspiciousActivity("iframe_embedding_detected", { isCrossOrigin: e });\n }\n })), t.protectPrinting?.disable && (this.printProtector = new xr({\n ...t.protectPrinting,\n onPrintAttempt: () => {\n this.dispatchSuspiciousActivity("print", {});\n }\n })), t.disableContextMenu && (this.contextMenuProtector = new kr({\n onContextMenuBlocked: (e) => {\n this.dispatchSuspiciousActivity("context_menu", e);\n }\n }));\n }\n destroy() {\n this.automationDetector?.destroy(), this.devToolsDetector?.destroy(), this.iframeEmbeddingDetector?.destroy(), this.printProtector?.destroy(), this.contextMenuProtector?.destroy();\n }\n}\nconst at = "readium:navigator:keyboardPeripheral";\nclass qe {\n constructor(t = {}) {\n this.keyManager = new hn(), this.setupKeyboardPeripherals(t.keyboardPeripherals || []);\n }\n setupKeyboardPeripherals(t) {\n if (t.length > 0) {\n const e = (i) => {\n const n = new CustomEvent(at, {\n detail: i\n });\n window.dispatchEvent(n);\n };\n this.keydownHandler = this.keyManager.createUnifiedHandler(\n "",\n // Empty string as target frame source for main window\n t,\n e\n ), this.keydownHandler && document.addEventListener("keydown", this.keydownHandler, !0);\n }\n window.addEventListener("unload", () => this.destroy());\n }\n destroy() {\n this.keydownHandler && (document.removeEventListener("keydown", this.keydownHandler, !0), this.keydownHandler = void 0);\n }\n}\nconst Or = (r) => ({\n frameLoaded: r.frameLoaded || (() => {\n }),\n positionChanged: r.positionChanged || (() => {\n }),\n tap: r.tap || (() => !1),\n click: r.click || (() => !1),\n zoom: r.zoom || (() => {\n }),\n scroll: r.scroll || (() => {\n }),\n customEvent: r.customEvent || (() => {\n }),\n handleLocator: r.handleLocator || (() => !1),\n textSelected: r.textSelected || (() => {\n }),\n contentProtection: r.contentProtection || (() => {\n }),\n contextMenu: r.contextMenu || (() => {\n }),\n peripheral: r.peripheral || (() => {\n })\n});\nclass Rr extends dn {\n constructor(t, e, i, n = void 0, s = { preferences: {}, defaults: {} }) {\n super(), this.currentIndex = 0, this._preferencesEditor = null, this._injector = null, this._navigatorProtector = null, this._keyboardPeripheralsManager = null, this._suspiciousActivityListener = null, this._keyboardPeripheralListener = null, this.webViewport = {\n readingOrder: [],\n progressions: /* @__PURE__ */ new Map(),\n positions: null\n }, this.pub = e, this.container = t, this.listeners = Or(i), this._preferences = new Mt(s.preferences), this._defaults = new pr(s.defaults), this._settings = new Ai(this._preferences, this._defaults, this.hasDisplayTransformability), this._css = new cr({\n rsProperties: new hr({ experiments: this._settings.experiments || null }),\n userProperties: new mn({ zoom: this._settings.zoom })\n });\n const o = yr(e.readingOrder.items), a = s.injectables || { rules: [], allowedDomains: [] };\n if (this._injector = new Sn({\n rules: [...o, ...a.rules],\n allowedDomains: a.allowedDomains\n }), this._contentProtection = s.contentProtection || {}, this._keyboardPeripherals = this.mergeKeyboardPeripherals(\n this._contentProtection,\n s.keyboardPeripherals || []\n ), (this._contentProtection.disableContextMenu || this._contentProtection.checkAutomation || this._contentProtection.checkIFrameEmbedding || this._contentProtection.monitorDevTools || this._contentProtection.protectPrinting?.disable) && (this._navigatorProtector = new Ye(this._contentProtection), this._suspiciousActivityListener = (l) => {\n const { type: h, ...c } = l.detail;\n h === "context_menu" ? this.listeners.contextMenu(c) : this.listeners.contentProtection(h, c);\n }, window.addEventListener(ot, this._suspiciousActivityListener)), this._keyboardPeripherals.length > 0 && (this._keyboardPeripheralsManager = new qe({\n keyboardPeripherals: this._keyboardPeripherals\n }), this._keyboardPeripheralListener = (l) => {\n const h = l.detail;\n this.listeners.peripheral(h);\n }, window.addEventListener(at, this._keyboardPeripheralListener)), n && typeof n.copyWithLocations == "function") {\n this.currentLocation = n;\n const l = this.pub.readingOrder.findIndexWithHref(n.href);\n l >= 0 && (this.currentIndex = l);\n } else\n this.currentLocation = this.createCurrentLocator();\n }\n async load() {\n await this.updateCSS(!1);\n const t = this.compileCSSProperties(this._css);\n this.framePool = new Os(\n this.container,\n t,\n this._injector,\n this._contentProtection,\n this._keyboardPeripherals\n ), await this.apply();\n }\n // Configurable interface implementation\n get settings() {\n return Object.freeze({ ...this._settings });\n }\n get preferencesEditor() {\n return this._preferencesEditor === null && (this._preferencesEditor = new Ti(this._preferences, this.settings, this.pub.metadata)), this._preferencesEditor;\n }\n async submitPreferences(t) {\n this._preferences = this._preferences.merging(t), await this.applyPreferences();\n }\n async applyPreferences() {\n this._settings = new Ai(this._preferences, this._defaults, this.hasDisplayTransformability), this._preferencesEditor !== null && (this._preferencesEditor = new Ti(this._preferences, this.settings, this.pub.metadata)), await this.updateCSS(!0);\n }\n async updateCSS(t) {\n this._css.update(this._settings), t && await this.commitCSS(this._css);\n }\n compileCSSProperties(t) {\n const e = {};\n for (const [i, n] of Object.entries(t.rsProperties.toCSSProperties()))\n e[i] = n;\n for (const [i, n] of Object.entries(t.userProperties.toCSSProperties()))\n e[i] = n;\n return e;\n }\n async commitCSS(t) {\n const e = this.compileCSSProperties(t);\n this.framePool.setCSSProperties(e);\n }\n /**\n * Exposed to the public to compensate for lack of implemented readium conveniences\n * TODO remove when settings management is incorporated\n */\n get _cframes() {\n return this.framePool.currentFrames;\n }\n get hasDisplayTransformability() {\n return this.pub.metadata?.accessibility?.feature?.some(\n (t) => t.value === Ht.DISPLAY_TRANSFORMABILITY.value\n ) ?? !1;\n }\n eventListener(t, e) {\n switch (t) {\n case "_pong":\n this.listeners.frameLoaded(this.framePool.currentFrames[0].iframe.contentWindow), this.listeners.positionChanged(this.currentLocation);\n break;\n case "first_visible_locator":\n const i = I.deserialize(e);\n if (!i) break;\n this.currentLocation = new I({\n href: this.currentLocation.href,\n type: this.currentLocation.type,\n title: this.currentLocation.title,\n locations: i?.locations,\n text: i?.text\n }), this.listeners.positionChanged(this.currentLocation);\n break;\n case "text_selected":\n this.listeners.textSelected(e);\n break;\n case "click":\n case "tap":\n const n = e;\n if (n.interactiveElement) {\n const l = new DOMParser().parseFromString(\n n.interactiveElement,\n "text/html"\n ).body.children[0];\n if (l.nodeType === l.ELEMENT_NODE && l.nodeName === "A" && l.hasAttribute("href")) {\n const h = l.attributes.getNamedItem("href")?.value;\n if (h.startsWith("#"))\n this.go(this.currentLocation.copyWithLocations({\n fragments: [h.substring(1)]\n }), !1, () => {\n });\n else if (h.startsWith("mailto:") || h.startsWith("tel:"))\n this.listeners.handleLocator(new $({\n href: h\n }).locator);\n else\n try {\n let c;\n if (h.startsWith("http://") || h.startsWith("https://"))\n c = h;\n else if (this.currentLocation.href.startsWith("http://") || this.currentLocation.href.startsWith("https://")) {\n const p = new URL(this.currentLocation.href);\n c = new URL(h, p).href;\n } else\n c = Xt.join(Xt.dirname(this.currentLocation.href), h);\n const u = this.pub.readingOrder.findWithHref(c);\n u ? this.goLink(u, !1, () => {\n }) : (console.warn(`Internal link not found in readingOrder: ${c}`), this.listeners.handleLocator(new $({\n href: h\n }).locator));\n } catch (c) {\n console.warn(`Couldn\'t resolve internal link for ${h}: ${c}`), this.listeners.handleLocator(new $({\n href: h\n }).locator);\n }\n } else console.log("Clicked on", l);\n } else if (t === "click" ? this.listeners.click(n) : this.listeners.tap(n)) break;\n break;\n case "scroll":\n this.listeners.scroll(e);\n break;\n case "zoom":\n this.listeners.zoom(e);\n break;\n case "progress":\n this.syncLocation(e);\n break;\n case "content_protection":\n const s = e;\n this.listeners.contentProtection(s.type, s);\n break;\n case "context_menu":\n this.listeners.contextMenu(e);\n break;\n case "keyboard_peripherals":\n const o = e, a = { ...o, interactiveElement: void 0 };\n o.interactiveElement && (a.interactiveElement = new DOMParser().parseFromString(\n o.interactiveElement,\n "text/html"\n ).body.children[0]), this.listeners.peripheral(a);\n break;\n case "log":\n console.log(this.framePool.currentFrames[0]?.source?.split("/")[3], ...e);\n break;\n default:\n this.listeners.customEvent(t, e);\n break;\n }\n }\n determineModules() {\n const t = gs.slice(), e = bt(this.pub.metadata);\n return e === "cjk-vertical" || e === "mongolian-vertical" ? t.map((i) => i === "webpub_snapper" ? "cjk_vertical_snapper" : i) : t;\n }\n attachListener() {\n this.framePool.currentFrames[0]?.msg && (this.framePool.currentFrames[0].msg.listener = (t, e) => {\n this.eventListener(t, e);\n });\n }\n async apply() {\n if (await this.framePool.update(this.pub, this.currentLocation, this.determineModules()), this.attachListener(), this.pub.readingOrder.findIndexWithHref(this.currentLocation.href) < 0)\n throw Error("Link for " + this.currentLocation.href + " not found!");\n }\n async destroy() {\n this._suspiciousActivityListener && window.removeEventListener(ot, this._suspiciousActivityListener), this._keyboardPeripheralListener && window.removeEventListener(at, this._keyboardPeripheralListener), this._navigatorProtector?.destroy(), this._keyboardPeripheralsManager?.destroy(), await this.framePool?.destroy();\n }\n async changeResource(t) {\n if (t === 0) return !1;\n const e = this.pub.readingOrder.findIndexWithHref(this.currentLocation.href), i = Math.max(\n 0,\n Math.min(this.pub.readingOrder.items.length - 1, e + t)\n );\n return i === e ? !1 : (this.currentIndex = i, this.currentLocation = this.createCurrentLocator(), await this.apply(), !0);\n }\n updateViewport(t) {\n this.webViewport.readingOrder = [], this.webViewport.progressions.clear(), this.webViewport.positions = null, this.currentLocation && (this.webViewport.readingOrder.push(this.currentLocation.href), this.webViewport.progressions.set(this.currentLocation.href, t), this.currentLocation.locations?.position !== void 0 && (this.webViewport.positions = [this.currentLocation.locations.position]));\n }\n async syncLocation(t) {\n const e = t;\n this.currentLocation && (this.currentLocation = this.currentLocation.copyWithLocations({\n progression: e.start\n })), this.updateViewport(e), this.listeners.positionChanged(this.currentLocation), await this.framePool.update(this.pub, this.currentLocation, this.determineModules());\n }\n goBackward(t, e) {\n this.changeResource(-1).then((i) => {\n e(i);\n });\n }\n goForward(t, e) {\n this.changeResource(1).then((i) => {\n e(i);\n });\n }\n get currentLocator() {\n return this.currentLocation;\n }\n get viewport() {\n return this.webViewport;\n }\n get isScrollStart() {\n const t = this.viewport.readingOrder[0];\n return this.viewport.progressions.get(t)?.start === 0;\n }\n get isScrollEnd() {\n const t = this.viewport.readingOrder[this.viewport.readingOrder.length - 1];\n return this.viewport.progressions.get(t)?.end === 1;\n }\n get canGoBackward() {\n const t = this.pub.readingOrder.items[0]?.href;\n return !(this.viewport.progressions.has(t) && this.viewport.progressions.get(t)?.start === 0);\n }\n get canGoForward() {\n const t = this.pub.readingOrder.items[this.pub.readingOrder.items.length - 1]?.href;\n return !(this.viewport.progressions.has(t) && this.viewport.progressions.get(t)?.end === 1);\n }\n get readingProgression() {\n return this.pub.metadata.effectiveReadingProgression;\n }\n get publication() {\n return this.pub;\n }\n async loadLocator(t, e) {\n let i = !1, n = typeof t.locations.getCssSelector == "function" && t.locations.getCssSelector();\n if (t.text?.highlight ? i = await new Promise((l, h) => {\n this.framePool.currentFrames[0].msg.send(\n "go_text",\n n ? [\n t.text?.serialize(),\n n\n // Include CSS selector if it exists\n ] : t.text?.serialize(),\n (c) => l(c)\n );\n }) : n && (i = await new Promise((l, h) => {\n this.framePool.currentFrames[0].msg.send(\n "go_text",\n [\n "",\n // No text!\n n\n // Just CSS selector\n ],\n (c) => l(c)\n );\n })), i) {\n e(i);\n return;\n }\n const s = typeof t.locations.htmlId == "function" && t.locations.htmlId();\n if (s && (i = await new Promise((l, h) => {\n this.framePool.currentFrames[0].msg.send("go_id", s, (c) => l(c));\n })), i) {\n e(i);\n return;\n }\n const o = t?.locations?.progression;\n o && o > 0 ? i = await new Promise((l, h) => {\n this.framePool.currentFrames[0].msg.send("go_progression", o, (c) => l(c));\n }) : i = !0, e(i);\n }\n go(t, e, i) {\n const n = t.href.split("#")[0];\n if (!this.pub.readingOrder.findWithHref(n))\n return i(this.listeners.handleLocator(t));\n const o = this.pub.readingOrder.findIndexWithHref(n);\n o >= 0 && (this.currentIndex = o), this.currentLocation = this.createCurrentLocator(), this.apply().then(() => this.loadLocator(t, (a) => i(a))).then(() => {\n this.attachListener();\n });\n }\n goLink(t, e, i) {\n return this.go(t.locator, e, i);\n }\n // Specifics to WebPub\n // Util method\n createCurrentLocator() {\n const e = this.pub.readingOrder.items[this.currentIndex];\n if (!e)\n throw new Error("No current resource available");\n const n = this.currentLocation && this.currentLocation.href === e.href && this.currentLocation.locations.progression ? this.currentLocation.locations.progression : 0;\n return this.pub.manifest.locatorFromLink(e) || new I({\n href: e.href,\n type: e.type || "text/html",\n locations: new C({\n fragments: [],\n progression: n,\n position: this.currentIndex + 1\n })\n });\n }\n}\nconst go = Rr, Ar = (r) => {\n const t = r.join(" ");\n return [\n // \'self\' is useless because the document is loaded from a blob: URL\n "upgrade-insecure-requests",\n `default-src ${t} blob:`,\n "connect-src \'none\'",\n // No fetches to anywhere. TODO: change?\n `script-src ${t} blob: \'unsafe-inline\'`,\n // JS scripts\n `style-src ${t} blob: \'unsafe-inline\'`,\n // CSS styles\n `img-src ${t} blob: data:`,\n // Images\n `font-src ${t} blob: data:`,\n // Fonts\n `object-src ${t} blob:`,\n // Despite not being recommended, still necessary in EPUBs for \n `child-src ${t}`,\n //