diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 00000000..6c1047c3 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "Battleborn Brawlers Compiled (Frontend)", + "runtimeExecutable": "bun", + "runtimeArgs": ["run", "dev:compiled"], + "port": 5000, + "autoPort": true + }, + { + "name": "Battleborn Brawlers (Frontend)", + "runtimeExecutable": "bun", + "runtimeArgs": ["run", "dev"], + "port": 5000, + "autoPort": true + }, + { + "name": "Battleborn Brawlers (Backend)", + "runtimeExecutable": "bun", + "runtimeArgs": ["--cwd", "server", "--watch", "--env-file=.env", "index.js"], + "port": 1337, + "autoPort": false + } + ] +} diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..ca2d45b0 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/setup-worktree.sh\"" + } + ] + } + ] + } +} diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..e5119e67 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,12 @@ +#!/bin/sh +files=$(git diff --cached --name-only --diff-filter=ACMR) +[ -z "$files" ] && exit 0 + +git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 bunx prettier --write --ignore-unknown --log-level=warn +git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 git add + +# Keep static/images/*.webp current with the /images masters (regenerate changed, +# prune orphans) and stage them — so committed art always ships, even with no dev +# server or local build having run. +bun scripts/images.js +git add -A static/images diff --git a/.gitignore b/.gitignore index ca38523d..396e91ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,36 @@ node_modules # Output -.output .vercel -/.svelte-kit -/build +dist +compiled # OS .DS_Store -Thumbs.db # Env .env .env.* !.env.example !.env.test - -# Vite -vite.config.js.timestamp-* -vite.config.ts.timestamp-* .env*.local +# Logs +*.log + +# Editor +.vscode +.idea + +# Claude +.claude/* +!.claude/launch.json +!.claude/settings.json + # Stuff _potential -_unused \ No newline at end of file +_unused + +# Test artifacts +test-results +static/audio/Imported Assets diff --git a/.nvmrc b/.nvmrc index 9a7c1e50..b0195acf 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.0 +24.12 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..2368a972 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +node_modules +dist +build +.vercel +.output +test-results +bun.lockb +.env* +.claude/settings.local.json +static +*.svg +_potential +_unused diff --git a/.prettierrc b/.prettierrc index 9f0f7960..5eaff133 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +1,6 @@ { "useTabs": false, "singleQuote": true, - "trailingComma": "none", "printWidth": 100, - "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], - "pluginSearchDirs": ["."], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] + "plugins": ["@ape-egg/prettier-plugin-vibe"] } diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 00000000..187d3623 --- /dev/null +++ b/.vercelignore @@ -0,0 +1 @@ +/images diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..9c2802ab --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,96 @@ +# Battleborn Brawlers + +The world's websites are overengineered. It doesn't have to be that way. Keep it simple Claude. + +Strategy auto-battler. Currently a Multi-Page App with filesystem routing — `pages/x.html` serves `/x`, and a `$param` segment is dynamic (`pages/the-arena/$id.html` serves `/the-arena/:id`). **Subject to change** — could become an SPA later, so don't lean on MPA assumptions in feature code. The game must work responsively down to ~360px wide; reach for Stylecheat's three media queries (`sm:` ≤768px, `md:` 768–1024px, `lg:` >1024px) before any custom `@media`. + +Open work — missing assets, content, and roadmap items — lives in [`TODO.md`](TODO.md). Log new gaps there as you hit them. + +## Stack + +- **Runtime**: Vibe (`@ape-egg/vibe`) — runtime-first reactive framework +- **CSS**: Stylecheat (hybrid build) — attribute-based CSS framework. We use `ChromeOnlyModifiers.css` (the `[g] { gap: calc(attr(g type()) * var(--unit)); }` form), **not** `Modifiers.css` (the `g-4`/`p-2` form). +- **Dev server**: Vite via `vite-plugin-vibe` for HMR. The `mpa-routes` plugin in `vite.config.js` derives routes from the `pages/` tree (a `$param` segment is dynamic, e.g. `pages/the-arena/$id.html` → `/the-arena/:id`, `page.params.id`). It resolves URLs in dev and injects each dynamic page's route template as `window.__ROUTE__` for `boot.js` — no generated file. For prod, add a matching `vercel.json` rewrite by hand when you add a dynamic page (Vercel reads `vercel.json` before it builds). +- **Vibe source**: Symlinked from `/Users/kortes/Projects/webdev/vibe/nodemodules/@ape-egg/vibe` (also `vite-plugin-vibe`). +- **`@ape-egg/async-await-websockets` source**: Symlinked from `/Users/kortes/Projects/webdev/async-await-websockets` (root + `server`). + +## Dogfooding Vibe & Stylecheat + +This project is the **primary dogfood** for `@ape-egg/vibe` and Stylecheat — both live as symlinks (see Stack). Things you'd expect from a mature framework (React/Vue/Svelte) may simply be missing in Vibe. + +**When you hit a Vibe quirk or bug, STOP. Do not work around it.** No `setTimeout`, no `queueMicrotask`, no reaching into `window.__vibe*`, no wrapping in a manual signal. Workarounds in app code hide the gap and let it rot. + +Instead, report it to me in this exact shape: + +1. **The issue** — what Vibe does vs what you expected (one or two sentences). +2. **What you're trying to do** — the actual code you wanted to write, pasted inline as a code block, even if it doesn't run. +3. **Proposed solutions** — 1–3 options: the upstream fix in `webdev/vibe`, and (if applicable) a temporary local workaround. Be explicit that the upstream fix is the right one. + +Frame it as **"Vibe is missing feature parity with modern frontend frameworks"** — because that's what most of these are. I decide whether we fix it upstream now or accept a workaround for this turn. + +The same applies to Stylecheat (but rarer — Stylecheat is more mature). + +## Game Server + +The WebSocket backend lives in `server/`. Frontend integration: + +- Connection lives on `$.socket` (see `js/connectSocket.js`); lifecycle is managed centrally — features should consume `$.socket` rather than open new connections. +- **Calling backend functions**: every file under `server/events/` is a server function, addressed by its path. Invoke from the client with `await $.socket.sendAsync('/', payload)` — e.g. `events/user/authenticate.js` is `$.socket.sendAsync('user/authenticate', { token, … })`, `events/pvp/get-random-opponent.js` is `$.socket.sendAsync('pvp/get-random-opponent', …)`. New backend capabilities → drop a `.js` file in `events//.js` (server auto-registers) and call it the same way from the client. +- Game state seeded onto `$` flows from the server through `sendAsync` responses (mainly in `js/boot.js` and `js/connectSocket.js`). New event handlers should plug into the same place so reactive bindings stay coherent. +- Auth happens via `$.token`; the server validates it on the websocket handshake. Don't store credentials elsewhere. +- Constants (`js/constants/*`) must match the server's expectations — when the backend renames or adds a key, update the constant file in lockstep. +- Helpers belong in `/js/helpers.js`. Tiny utilities (formatters, parsers) should not get their own files. + +## Guidelines for CLAUDE + +`~` = enforce +`-` = avoid +`❌` = forbidden + +### Testing + +- `-` Playwright MCP, unless explicitly asked. +- `~` Prefer the Claude Desktop App Preview for in-app checks over the Playwright test browser. +- `~` Rely on manual browser testing — the user runs the game and reports issues; point out what to check. +- `~` **Preview throttles `requestAnimationFrame`.** The Claude Preview tab runs unfocused, so the browser throttles `rAF` to ~nothing — anything rAF-driven freezes (the combat replay sticks at `elapsedMilliseconds ≈ 166`, animations don't advance). `setTimeout`/`setInterval` still fire, so `preview_eval` and samplers work, but you can't observe rAF-driven UI. To un-throttle for a debugging session, shim it via `preview_eval` **before** the loop starts: + + ```js + window.requestAnimationFrame = (cb) => setTimeout(() => cb(performance.now()), 16); + window.cancelAnimationFrame = (id) => clearTimeout(id); + ``` + + Then trigger the fight/animation and sample with a `setInterval`. The shim is ephemeral page state (gone on reload), so re-apply it after each reload. This is how the compiled-only "status chip stuck at 1" bug was finally observed. + +### Markup & components + +- `❌` HTML comments. The only HTML "comments" allowed are Vibe directives (``, ``, ``, ``, ``) — reactive control flow, not comments. Use JS `// TODO:` for "do later". +- `❌` `
`. Use semantic/custom element names: ``, ``, ``, ``, ``, etc. +- `❌` `class=""`. Exception: `` to give a tag a different visual treatment (Stylecheat keys some looks off `class`). +- `❌` `style=""`. Set CSS custom props via ``; only acceptable for unavoidable cases like tooltip absolute positioning. +- `-` `data-*` prefix. Use plain attributes — CSS `chip[stunned]`, HTML ``. Exception: genuine HTML data semantics like `data-src`. +- `❌` `@[…]` in an **eager-loading URL attribute** (``, ` + Read more + + + + + + + + + diff --git a/components/ActivityBar.html b/components/ActivityBar.html new file mode 100644 index 00000000..ba2132de --- /dev/null +++ b/components/ActivityBar.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + @[activeHint] + + + @[pickHint] + + @[recruitHint] + + + + + + + diff --git a/components/AuthGate.html b/components/AuthGate.html new file mode 100644 index 00000000..a970f9fd --- /dev/null +++ b/components/AuthGate.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + diff --git a/components/Authorization.html b/components/Authorization.html new file mode 100644 index 00000000..fb4d1d00 --- /dev/null +++ b/components/Authorization.html @@ -0,0 +1,54 @@ + + + + + Battleborn Brawlers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/BackButton.html b/components/BackButton.html new file mode 100644 index 00000000..fd995f77 --- /dev/null +++ b/components/BackButton.html @@ -0,0 +1,12 @@ + Back + + diff --git a/components/BasicConfirmation.html b/components/BasicConfirmation.html new file mode 100644 index 00000000..9f79a8dd --- /dev/null +++ b/components/BasicConfirmation.html @@ -0,0 +1,27 @@ + + +

@[overlay.text || 'Are you sure?']

+
+ + + + + + + + + + + + + + +
diff --git a/components/BrawlerDetailContent.html b/components/BrawlerDetailContent.html new file mode 100644 index 00000000..18249c28 --- /dev/null +++ b/components/BrawlerDetailContent.html @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
Equipment
+
+
+ + + +
+
+ + + + + +
+ +
+ + + + diff --git a/components/BrawlerPortrait.html b/components/BrawlerPortrait.html new file mode 100644 index 00000000..9de83420 --- /dev/null +++ b/components/BrawlerPortrait.html @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/components/BrawlerSlot.html b/components/BrawlerSlot.html new file mode 100644 index 00000000..bc04995d --- /dev/null +++ b/components/BrawlerSlot.html @@ -0,0 +1,272 @@ + + + + + + +
@[slot.label]
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
Available abilities
+ + Character sheet + +
+ + +
+
+
+ + diff --git a/components/BrawlerSlotList.html b/components/BrawlerSlotList.html new file mode 100644 index 00000000..360293b4 --- /dev/null +++ b/components/BrawlerSlotList.html @@ -0,0 +1,10 @@ + + + + + diff --git a/components/CardHandDemo.html b/components/CardHandDemo.html new file mode 100644 index 00000000..db4b55e3 --- /dev/null +++ b/components/CardHandDemo.html @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/components/Caret.html b/components/Caret.html new file mode 100644 index 00000000..43a66b2e --- /dev/null +++ b/components/Caret.html @@ -0,0 +1 @@ + diff --git a/components/CharacterAbilitiesSection.html b/components/CharacterAbilitiesSection.html new file mode 100644 index 00000000..0542bc89 --- /dev/null +++ b/components/CharacterAbilitiesSection.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/components/CharacterAvatar.html b/components/CharacterAvatar.html new file mode 100644 index 00000000..53883332 --- /dev/null +++ b/components/CharacterAvatar.html @@ -0,0 +1,28 @@ + + @[name || ''] + + + diff --git a/components/CharacterEquipmentList.html b/components/CharacterEquipmentList.html new file mode 100644 index 00000000..adcbdfca --- /dev/null +++ b/components/CharacterEquipmentList.html @@ -0,0 +1,58 @@ + + + + + + + @[eq.prettyName] + + + + + + + @[eq.itemName] + + + + + + + + + + + + + diff --git a/components/CharacterScalingContent.html b/components/CharacterScalingContent.html new file mode 100644 index 00000000..6620035d --- /dev/null +++ b/components/CharacterScalingContent.html @@ -0,0 +1,562 @@ + + + + +
+ + + + + + + + + + + + + + level @[ch.level] + + + + + + + + + + + + +
Equipment
+
+ + + + @[s.slotLabel] + + + + + + + + Fist + + + @[s.twoHandName] + + + - + + + + +
+ +
+ + +
Compare — stat per level
+ + + + + + + + + + + + @[row.header] + + + + + + + + +
+
+ + diff --git a/components/CharacterSheet.html b/components/CharacterSheet.html new file mode 100644 index 00000000..014ac176 --- /dev/null +++ b/components/CharacterSheet.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + diff --git a/components/CharacterSheetDialog.html b/components/CharacterSheetDialog.html new file mode 100644 index 00000000..f6d75866 --- /dev/null +++ b/components/CharacterSheetDialog.html @@ -0,0 +1,31 @@ + + + +
Equipment
+ + +
+
+ + diff --git a/components/CodeOfConduct.html b/components/CodeOfConduct.html new file mode 100644 index 00000000..21cd05b1 --- /dev/null +++ b/components/CodeOfConduct.html @@ -0,0 +1,30 @@ + + +

By playing the game you agree to the following rules and regulations.

+
Rules:
+
    +
  1. Respect everyone and their opinions
  2. +
  3. Don't spam chat
  4. +
  5. No excessive caps
  6. +
  7. No excessive swearing
  8. +
  9. No NSFW Content in chat
  10. +
  11. Always respect a moderators request
  12. +
+

+ We want to promote a sense of community where conversations and discussion is encouraged. + Therefore we expect everyone to behave in a civil and respectful manner. +

+
Verbal abuse, threatening behaviour, harassment
+

+ Remember this is a game where people come to relax and have fun. Although you may disagree + with other players and their opinions, this does not mean you need to be abusive or offensive. +

+
Racism, discrimination and hate speech
+

Any kind of racism, discrimination or hate speech will not be tolerated.

+
Moderators discretion
+

+ Moderators reserve the right to request conversations to end. Remember everyone is here to + have fun. +

+
+
diff --git a/components/Coins.html b/components/Coins.html new file mode 100644 index 00000000..2edfd98b --- /dev/null +++ b/components/Coins.html @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + @[Math.floor(amount / 100)]× + + + + + + + + + + + @[Math.floor(amount / 100)] + + + + + + + diff --git a/components/Combat.html b/components/Combat.html new file mode 100644 index 00000000..1d72f62f --- /dev/null +++ b/components/Combat.html @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + diff --git a/components/CombatArena.html b/components/CombatArena.html new file mode 100644 index 00000000..b96526a1 --- /dev/null +++ b/components/CombatArena.html @@ -0,0 +1,9 @@ + + + + + diff --git a/components/CombatProjectiles.html b/components/CombatProjectiles.html new file mode 100644 index 00000000..132e8bb2 --- /dev/null +++ b/components/CombatProjectiles.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/components/CombatTeamLabels.html b/components/CombatTeamLabels.html new file mode 100644 index 00000000..d39b45a5 --- /dev/null +++ b/components/CombatTeamLabels.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + diff --git a/components/CombatantCard.html b/components/CombatantCard.html new file mode 100644 index 00000000..872709e9 --- /dev/null +++ b/components/CombatantCard.html @@ -0,0 +1,252 @@ + + + + @[card.name] + + + + + + + + + + Immobilized + + + + + @[card.damage] + + + + + @[card.currentArmor] + + + + + + + + + + + + + diff --git a/components/CombatantImage.html b/components/CombatantImage.html new file mode 100644 index 00000000..eb342867 --- /dev/null +++ b/components/CombatantImage.html @@ -0,0 +1,220 @@ + + + + @[card.name] + + + + + + + + + + + diff --git a/components/CoreStats.html b/components/CoreStats.html new file mode 100644 index 00000000..8c10db60 --- /dev/null +++ b/components/CoreStats.html @@ -0,0 +1,45 @@ + + + + @[hp] + + + + @[armor] + + + + @[damage] + + + + diff --git a/components/CreateTeamplayModal.html b/components/CreateTeamplayModal.html new file mode 100644 index 00000000..addf8a0e --- /dev/null +++ b/components/CreateTeamplayModal.html @@ -0,0 +1,448 @@ + + + + + + + + + +

Create Teamplay

+ level @[teamplayLevelLabel(this.centerLevel, this.levelOffset)] +
+ + + + + ? + + + + + + + + + ? + + + + + + + + ? + + + + + + + + Composition + ? + + + + + + + + + + + + + ? + + + + + + + + + + @[teamplayWinningXp(this.randomizedTeams, this.brawlersPerAccount, + this.amountOfTeams)] + XP to winning team + @[teamplayParticipationXp(this.randomizedTeams, this.brawlersPerAccount, + this.amountOfTeams)] + XP participation + + + +
+
+ +
+ + diff --git a/components/DebugContent.html b/components/DebugContent.html new file mode 100644 index 00000000..e58a2eb2 --- /dev/null +++ b/components/DebugContent.html @@ -0,0 +1,699 @@ + + + + + + + + + + + + Arena + Teams @[this.teamCount] + + Combatants @[this.combatantCount] + + Select fight template + + + + + Roster + + + + @[row.teamLabel] + + + + + + + + + + + Tools + + + + + + + + + + Combat speed + + + @[(elapsedMilliseconds / 1000).toFixed(1)]s + @[(combat.duration / 1000).toFixed(1)]s + + + + + + + + + +

Configure | @[this.modal.name] — Team @[this.modal.team + 1]

+ + + + + +
+ + + + Level @[this.modal.level] + + + Equipment + + + @[row.label] + + + + + + Abilities (id · ticks) + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/components/DevBar.html b/components/DevBar.html new file mode 100644 index 00000000..099dae2a --- /dev/null +++ b/components/DevBar.html @@ -0,0 +1,257 @@ + + + + + State + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tools + Admin + Audio + Characters + Equipment + Imagegen + Test Combat + View Combat + + + + Balance + Ability Scaling + Character Scaling + Equipment Scaling + + + + UI + Colors + Form + Globals + Icons + Rewards Box + Tooltips + + + + Temp + Ability Designs + Achievements + Card Hand + Inventory + SPA Testing + + + + + Server clock + Synced: @[new Date(clock.server).toLocaleString()] + Now: @[new Date(clock.now).toLocaleString()] + Season @[season] · @[seasonName(season)] + + + + + + + + + diff --git a/components/Dialog.html b/components/Dialog.html new file mode 100644 index 00000000..70366970 --- /dev/null +++ b/components/Dialog.html @@ -0,0 +1,57 @@ + + + + + + + + +

@[title]

+
+ + + + +
+ + diff --git a/components/EmperorCutscene.html b/components/EmperorCutscene.html new file mode 100644 index 00000000..bc7cdcc2 --- /dev/null +++ b/components/EmperorCutscene.html @@ -0,0 +1,104 @@ + + + + + + + + + + diff --git a/components/EquipmentCatalogRow.html b/components/EquipmentCatalogRow.html new file mode 100644 index 00000000..266631bd --- /dev/null +++ b/components/EquipmentCatalogRow.html @@ -0,0 +1,85 @@ + + + + + + + + + + @[item.level] + @[item.slotLabel] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @[stat.value] + + + + + @[item.obtainedLabel] + + + + + + diff --git a/components/EquipmentLink.html b/components/EquipmentLink.html new file mode 100644 index 00000000..f9fbe846 --- /dev/null +++ b/components/EquipmentLink.html @@ -0,0 +1,10 @@ + + + + + + + + + @[name] + diff --git a/components/EquipmentScalingContent.html b/components/EquipmentScalingContent.html new file mode 100644 index 00000000..674413a2 --- /dev/null +++ b/components/EquipmentScalingContent.html @@ -0,0 +1,177 @@ + + + + +
+ + + + + + + @[eq.label] + + + + + + + + +
+ + +
Compare — stat per level
+ + + + + + + + + + + + + +
+
+ + diff --git a/components/EquipmentStats.html b/components/EquipmentStats.html new file mode 100644 index 00000000..1cef5d2a --- /dev/null +++ b/components/EquipmentStats.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + + @[props.name] + + + @[props.kind] + + @[props.slotLabel] + + + + + + + + + + + + + + + + + + + + + + + + @[ability.name] + @[$.unsafe(ability.description)] + + + + +
+ + + + + +

@[$.unsafe(props.description)]

+ + + + + LEVEL @[props.level] + + +
+ + diff --git a/components/FightButton.html b/components/FightButton.html new file mode 100644 index 00000000..7a3dd5aa --- /dev/null +++ b/components/FightButton.html @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fight concluded elsewhere! + Press here to see the outcome + + Fight elsewhere in progress... + + + ! + + + + + + diff --git a/components/FightDetailContent.html b/components/FightDetailContent.html new file mode 100644 index 00000000..a9f68114 --- /dev/null +++ b/components/FightDetailContent.html @@ -0,0 +1,526 @@ + + + + + + + + + + + + + @[fightWinPercent === null ? '—' : fightWinPercent + '% win'] + + level @[currentFight.levelText] + + + BOSS FIGHT + + + +
+ + + + + + + + + + + + + + + + + + + +
High
+ + + + @[enemy.bestStat.label] +
+ +
+ + + +
Loot
+ + Level too high + +
+ + + + + + + + + + + + + + @[drop.item.name] + + + + + + @[drop.item.name] + + + + + @[drop.word] + + + @[drop.word] chance + + + + +
+ + + + +

@[$.unsafe(para)]

+ +
+ +
+
+
+ + + + + +
Ability sequence
+
+
+
+ + +
+
+ + + + + + + + + + Edit + + + + +
+
+ +
+ + + + + +
+ + + + + + diff --git a/components/ForgotPassword.html b/components/ForgotPassword.html new file mode 100644 index 00000000..ad2410e4 --- /dev/null +++ b/components/ForgotPassword.html @@ -0,0 +1,46 @@ + + +
+ + + + +

+ + Back to login + +

+
diff --git a/components/GameMenu.html b/components/GameMenu.html new file mode 100644 index 00000000..30400750 --- /dev/null +++ b/components/GameMenu.html @@ -0,0 +1,147 @@ + + + + + Audio + + + + + + + @[Math.round(settings.volume.master * 100)]% + + + + @[Math.round(settings.volume.ambient * 100)]% + + + + @[Math.round(settings.volume.sfx * 100)]% + + + + @[Math.round(settings.volume.combat * 100)]% + + + + + + + + + + + + + + + + diff --git a/components/HealthBar.html b/components/HealthBar.html new file mode 100644 index 00000000..af751a99 --- /dev/null +++ b/components/HealthBar.html @@ -0,0 +1,137 @@ + + + + + + @[card.provocationChance]% + + + + + + + + + + +@[f.amount] + Mended! + FULL + MISS + DODGED + BLOCKED + ABSORBED + @[f.amount] + + + + + + + diff --git a/components/IconCell.html b/components/IconCell.html new file mode 100644 index 00000000..17bbe4fb --- /dev/null +++ b/components/IconCell.html @@ -0,0 +1,3 @@ + + + diff --git a/components/InventoryDrawer.html b/components/InventoryDrawer.html new file mode 100644 index 00000000..f2985cec --- /dev/null +++ b/components/InventoryDrawer.html @@ -0,0 +1,312 @@ + + + + + + +
MY EQUIPMENT
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + No equipment yet + + + + + + +
+ + diff --git a/components/Keystrokes.html b/components/Keystrokes.html new file mode 100644 index 00000000..55b807e5 --- /dev/null +++ b/components/Keystrokes.html @@ -0,0 +1,76 @@ + diff --git a/components/LabeledSwitch.html b/components/LabeledSwitch.html new file mode 100644 index 00000000..1a6858b1 --- /dev/null +++ b/components/LabeledSwitch.html @@ -0,0 +1,4 @@ + diff --git a/components/Layout.html b/components/Layout.html new file mode 100644 index 00000000..ce05fc0d --- /dev/null +++ b/components/Layout.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + @[bossHighscore >= 15 ? 'The Wild' : 'The Arena'] + + + + Random duel + + + + Teamplay + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/LoadingBar.html b/components/LoadingBar.html new file mode 100644 index 00000000..9df11a82 --- /dev/null +++ b/components/LoadingBar.html @@ -0,0 +1,31 @@ + + + + + diff --git a/components/Login.html b/components/Login.html new file mode 100644 index 00000000..612833ac --- /dev/null +++ b/components/Login.html @@ -0,0 +1,93 @@ + + +
+ + + + + + + + + + + + + +
diff --git a/components/MatchupBadge.html b/components/MatchupBadge.html new file mode 100644 index 00000000..57d3fbc7 --- /dev/null +++ b/components/MatchupBadge.html @@ -0,0 +1,11 @@ + + + + @[matchupLabel(ours, theirs, teams)] + diff --git a/components/MaterialCost.html b/components/MaterialCost.html new file mode 100644 index 00000000..d444d764 --- /dev/null +++ b/components/MaterialCost.html @@ -0,0 +1,49 @@ + + + + + + + @[m.count]× + + + @[m.name] + + + @[m.count] + + + + + + + + diff --git a/components/Materials.html b/components/Materials.html new file mode 100644 index 00000000..ce1bd916 --- /dev/null +++ b/components/Materials.html @@ -0,0 +1,44 @@ + + + + + + + @[$.materials?.[m.id] ?? 0]× + + + @[m.name] + + + @[$.materials?.[m.id] ?? 0] + + + + + + + + diff --git a/components/MedicumContent.html b/components/MedicumContent.html new file mode 100644 index 00000000..b9b57f0d --- /dev/null +++ b/components/MedicumContent.html @@ -0,0 +1,79 @@ + + + + + + + + +

Mother Alora

+ + Welcome to the Medicum, child. Bring me one of your brawlers and I will teach them to brew a + healing draught — so the arena need not be the only kindness you know. + +
+
+
+ + +

How the Medicum works

+

+ Assign one of your brawlers below and they will brew a healing potion every 2 minutes. Only one + may tend the brewing pot at a time, and they cannot enter the arena while they work. Remove them + with the ✕ whenever you need them back. +

+
+ + + + diff --git a/components/MerchantCard.html b/components/MerchantCard.html new file mode 100644 index 00000000..cf17160d --- /dev/null +++ b/components/MerchantCard.html @@ -0,0 +1,115 @@ + + + + + + + +

@[name]

+
+ @[description] + There are currently @[vendorItemsAtLevel(level).length] goods in + store. +
+ + Level @[level]@[level < MAX_LEVEL ? '+' : ''] + + + + + + +
+ + + + + + +
+ + diff --git a/components/Modal.html b/components/Modal.html new file mode 100644 index 00000000..33626948 --- /dev/null +++ b/components/Modal.html @@ -0,0 +1,60 @@ + + + + + + + + + diff --git a/components/Mugshot.html b/components/Mugshot.html new file mode 100644 index 00000000..61ec369c --- /dev/null +++ b/components/Mugshot.html @@ -0,0 +1,27 @@ + + @[name || ''] + + + diff --git a/components/Mystery.html b/components/Mystery.html new file mode 100644 index 00000000..80c9e36c --- /dev/null +++ b/components/Mystery.html @@ -0,0 +1,23 @@ + + ? + + + diff --git a/components/Overlay.html b/components/Overlay.html new file mode 100644 index 00000000..e866de4b --- /dev/null +++ b/components/Overlay.html @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + Re-watching historical battle + @[historicalBattleTime(combat.startedAt)] + + + LIVE Spectating + + + + + + + + + + seed + @[combat.seed] + + + + + + + + + + + + + + + + + + diff --git a/components/PageNotFound.html b/components/PageNotFound.html new file mode 100644 index 00000000..4f2697d6 --- /dev/null +++ b/components/PageNotFound.html @@ -0,0 +1,55 @@ + + + + + + + + + + +

@[heading || 'Page not found']

+

+ + @[message] + + Whatever you were looking for isn't here — it may have moved,
or never set foot in the arena at all. + +

+
+ + + + + @[label || 'Take me home'] + +
+ + diff --git a/components/PalaestraContent.html b/components/PalaestraContent.html new file mode 100644 index 00000000..79631e35 --- /dev/null +++ b/components/PalaestraContent.html @@ -0,0 +1,81 @@ + + + + + + + + + + +

Doctore Varro

+ + So you want to grow stronger? Then give me a brawler and the sand. I will drill them until + they bleed wisdom — and every drop of their sweat hardens you, the whole ludus, alike. + +
+
+
+ + +

How the Palaestra works

+

+ Assign one of your brawlers below and they will train for 10 account experience every 2 minutes. + Only one may take the sand at a time, and they cannot enter the arena while they drill. Remove + them with the ✕ whenever you need them back. +

+
+ + + + diff --git a/components/PotionIcon.html b/components/PotionIcon.html new file mode 100644 index 00000000..0b5ff094 --- /dev/null +++ b/components/PotionIcon.html @@ -0,0 +1 @@ + diff --git a/components/ReWatchButton.html b/components/ReWatchButton.html new file mode 100644 index 00000000..56c3ddea --- /dev/null +++ b/components/ReWatchButton.html @@ -0,0 +1,67 @@ + + + + + diff --git a/components/Register.html b/components/Register.html new file mode 100644 index 00000000..8eace01b --- /dev/null +++ b/components/Register.html @@ -0,0 +1,52 @@ + + +
+ + + + + +

+ Already have an account? + + Log in + +

+
diff --git a/components/ReleaseNotes.html b/components/ReleaseNotes.html new file mode 100644 index 00000000..86f03038 --- /dev/null +++ b/components/ReleaseNotes.html @@ -0,0 +1,61 @@ + + + + + +
@[formatReleaseDate(note.date)]
+ @[note.title] +

@[note.text]

+
+ +
+ + +
+
+ + diff --git a/components/ResetPasswordContent.html b/components/ResetPasswordContent.html new file mode 100644 index 00000000..b8c7d021 --- /dev/null +++ b/components/ResetPasswordContent.html @@ -0,0 +1,69 @@ + + + +

Reset Password

+ + + @[this.resetError] + + + + + + + + + + Checking reset link... + +
diff --git a/components/ResultAnnouncement.html b/components/ResultAnnouncement.html new file mode 100644 index 00000000..610a9bd0 --- /dev/null +++ b/components/ResultAnnouncement.html @@ -0,0 +1,610 @@ + + + + + + + + + + + + + + + + rewards + + + + + + +@[combatRewardXp(combat)] XP + + + + + + + + + + + + + + + + @[drop.item.name] + + + + + + @[drop.item.name] + + + + + + + + Your side has fallen + + + Neither side yields + + + + + + + + + + + +@[combatRewardXp(combat)] XP + (for participating) + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/SeasonDowntime.html b/components/SeasonDowntime.html new file mode 100644 index 00000000..9673f180 --- /dev/null +++ b/components/SeasonDowntime.html @@ -0,0 +1,133 @@ + + + Season @[season] has concluded + The arena is being reforged + + + Season @[season + 1] · @[seasonName(season + 1)] begins in + @[formatDuration(msUntilNextSeason(clock.now))] + + + + All account progress resets for the fresh season — a clean slate for everyone. + + + + + + Buy now and you're set the moment the gates reopen. + + + + + + Season Pass secured — see you on the sand. + + + + + + diff --git a/components/SeasonModal.html b/components/SeasonModal.html new file mode 100644 index 00000000..646bff0b --- /dev/null +++ b/components/SeasonModal.html @@ -0,0 +1,315 @@ + + + + + + @[this.name] + @[this.tagline] + + + + This season + + + + + @[point] + + + + + + + Schedule + + + Started + @[this.started] + + + Ends + @[this.ends] + + + Next season + @[this.nextStarts] + + + Time left + @[this.daysLeft] days + + + + + + + + + + + Season Pass active + + @[seasonNumber(premiumUntil) - season] more season@[seasonNumber(premiumUntil) - + season === 1 ? '' : 's'] · expires @[new + Date(premiumUntil).toLocaleDateString('en-US', { year: 'numeric', month: 'short', + day: 'numeric' })] + + + + + + + + Season Pass + + @[passDiscount(clock.now)]% off — the season's nearly over. + + + Unlock extra rewards as you level up this season. + + + + + + @[formatEUR(PASS_PRICE)] + + @[formatEUR(passPrice(clock.now))] + + + + + + + + + + + diff --git a/components/Sidebar.html b/components/Sidebar.html new file mode 100644 index 00000000..30072c64 --- /dev/null +++ b/components/Sidebar.html @@ -0,0 +1,803 @@ + + + + + + + + + +
@[accountName]'s
+ +
Ludus
+
+ + level @[getLevelByExperience(experience)] + +
+ + + + + + Experience + + + + + + + + + Brawlers + Armory + + Medicum + + + + + + + Palaestra + + + + + + + + + + + + @[characters.length] / @[allowedNumberOfBrawlers()] + + + + + + + You have no brawlers yet. + Recruit brawler + + + + + + + + Making potion + + + + + + + + Training + + + + + + + + @[teamplayBrawlerLabel()] + + + + + + + + @[elapsedMilliseconds < combat.duration ? 'Brawling' : 'Fight concluded'] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Making potion + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Potions + @[potions] / @[allowedNumberOfPotions()] + + + + + + +
+
+ + diff --git a/components/SolidBar.html b/components/SolidBar.html new file mode 100644 index 00000000..a38afdef --- /dev/null +++ b/components/SolidBar.html @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + @[String(Math.floor(Math.max(0, (max || 0) - (current || 0)) / 60000)).padStart(2, + '0')]:@[String(Math.floor((Math.max(0, (max || 0) - (current || 0)) % 60000) / + 1000)).padStart(2, '0')] + + + + + + @[text || ''] + + @[current] / @[max] + + + + @[Math.max(0, Math.min(100, ((current || 0) / Math.max(1, max || 1)) * 100)).toFixed(0)]% + + @[current] / @[max] + + + + + + diff --git a/components/Spinner.html b/components/Spinner.html new file mode 100644 index 00000000..36b9144c --- /dev/null +++ b/components/Spinner.html @@ -0,0 +1,23 @@ + + + + + + diff --git a/components/StatGroup.html b/components/StatGroup.html new file mode 100644 index 00000000..62fb1080 --- /dev/null +++ b/components/StatGroup.html @@ -0,0 +1,124 @@ + + +
@[title]
+ + + + + + + + @[row.label] + + @[row.value] + + 0% + + + + + + + +
@[subtitle]
+ + + + + + + @[row.label] + + @[row.value] + + + + +
+ + diff --git a/components/StateInspector.html b/components/StateInspector.html new file mode 100644 index 00000000..dd360727 --- /dev/null +++ b/components/StateInspector.html @@ -0,0 +1,50 @@ + + + + + + + + + + + diff --git a/components/StatusChip.html b/components/StatusChip.html new file mode 100644 index 00000000..56bbb0b2 --- /dev/null +++ b/components/StatusChip.html @@ -0,0 +1,162 @@ + + + + + + + + @[s.value]/@[s.max] + + + @[s.ticks] + + @[s.announce || s.name + '!'] + + + + diff --git a/components/TeamBadge.html b/components/TeamBadge.html new file mode 100644 index 00000000..9c8229ff --- /dev/null +++ b/components/TeamBadge.html @@ -0,0 +1 @@ +@[name] diff --git a/components/TeamplayChat.html b/components/TeamplayChat.html new file mode 100644 index 00000000..7d81bb2a --- /dev/null +++ b/components/TeamplayChat.html @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + @[pvp.teamplay.selecting.length] / @[pvp.teamplay.bpa] selected — @[pvp.teamplay.bpa === 1 + ? 'pick a brawler, then an open slot' : 'pick your brawlers, then a team'] + + + + + + + +
Teamplay Chat
+
+ +
+ + + + + + + No messages yet. Say hello! + + + + + @[msg.name] + @[msg.text] + + + + + + + + + + + +
+
+ + diff --git a/components/TeamplayListContent.html b/components/TeamplayListContent.html new file mode 100644 index 00000000..d348b78e --- /dev/null +++ b/components/TeamplayListContent.html @@ -0,0 +1,380 @@ + + + + + Active Teamplays + Recent Teamplays + + + + + + Min level + + + + Max level + + + + + + + + Name + Level + Teams + Slots + + + + @[t.rules.name] + @[t.levelLabel] + @[t.teamsLabel] + @[t.slotsLabel] + + + + + + + + + + + + + Name + Level + Combatants + + + + + @[t.rules.name] + @[t.levelLabel] + + + @[t.combatantCount] + (@[t.teamsLabel] teams) + + + + + + + + + + + + + + + + + diff --git a/components/TeamplayRoomContent.html b/components/TeamplayRoomContent.html new file mode 100644 index 00000000..528d1a25 --- /dev/null +++ b/components/TeamplayRoomContent.html @@ -0,0 +1,508 @@ + + + + + + + +
+ + + + + +

@[team.label]

+
+ + + level @[team.level] + + + + + +
+ +
+ +
+ + + + Loading teamplay… + +
+ + diff --git a/components/TitleBar.html b/components/TitleBar.html new file mode 100644 index 00000000..3939918c --- /dev/null +++ b/components/TitleBar.html @@ -0,0 +1,26 @@ + + + + + + + + +
@[title]
+ +

@[title]

+ + + @[description] + +
+ + + +
+ + diff --git a/components/Topbar.html b/components/Topbar.html new file mode 100644 index 00000000..1476b782 --- /dev/null +++ b/components/Topbar.html @@ -0,0 +1,204 @@ + + + + + + Battleborn Brawlers + + ALPHA v@[version] + + @[worktree] + + + + Season @[season] + @[seasonName(season)] + + @[seasonLabel(season)] + + + + + Non-compiled + + + + @[isPremiumNow ? 'Battle Pass' : 'No Battle Pass'] + + + + + @[settings.isTester ? 'Test Mode' : 'Normal Mode'] + + + + + + + +
+ + + + + + +
+
+ + + + + + + + +
+ + diff --git a/components/VendorContent.html b/components/VendorContent.html new file mode 100644 index 00000000..d82dde9f --- /dev/null +++ b/components/VendorContent.html @@ -0,0 +1,157 @@ + + + + + Name + Slots in + Race + Ability + Stats + Cost + + + + + + + + + + + + + + @[item.slotLabel] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @[stat.value] + + + + + + + + + + + + + + + + + + + + + + + + + + + + One-Handed @[vendorCount('oneHand', minLevel)] + + + + + Off-Hand @[vendorCount('offHand', minLevel)] + + + + + Two-Handed @[vendorCount('twoHand', minLevel)] + + + + + Armor @[vendorCount('armor', minLevel)] + + + + + Accessory @[vendorCount('accessory', minLevel)] + + + + + Trinket @[vendorCount('trinket', minLevel)] + + + + diff --git a/components/VictoryOrLoss.html b/components/VictoryOrLoss.html new file mode 100644 index 00000000..b5df4ac7 --- /dev/null +++ b/components/VictoryOrLoss.html @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + VICTORY + DEFEAT + DRAW + + + + + + + + + + diff --git a/components/buttons/Cross.html b/components/buttons/Cross.html new file mode 100644 index 00000000..6d9da9fe --- /dev/null +++ b/components/buttons/Cross.html @@ -0,0 +1,16 @@ + + + diff --git a/components/buttons/DropdownButton.html b/components/buttons/DropdownButton.html new file mode 100644 index 00000000..2389e80c --- /dev/null +++ b/components/buttons/DropdownButton.html @@ -0,0 +1,6 @@ + diff --git a/components/buttons/OverlayClose.html b/components/buttons/OverlayClose.html new file mode 100644 index 00000000..a88fd9b2 --- /dev/null +++ b/components/buttons/OverlayClose.html @@ -0,0 +1,31 @@ + + + diff --git a/components/buttons/PhysicalButton.html b/components/buttons/PhysicalButton.html new file mode 100644 index 00000000..e6d4a5c9 --- /dev/null +++ b/components/buttons/PhysicalButton.html @@ -0,0 +1,37 @@ + + + diff --git a/components/remote/AchievementReveal.html b/components/remote/AchievementReveal.html new file mode 100644 index 00000000..2d0f4357 --- /dev/null +++ b/components/remote/AchievementReveal.html @@ -0,0 +1,102 @@ + + + + + Achievement unlocked + + + + + + + + Earned + @[r.title] + @[r.description] + + + Tap to view it in your achievements + + + + + + diff --git a/components/remote/BarGraph.html b/components/remote/BarGraph.html new file mode 100644 index 00000000..a0a2b996 --- /dev/null +++ b/components/remote/BarGraph.html @@ -0,0 +1,60 @@ + + + + @[$.unsafe(barGraphSvg(bars))] + + + diff --git a/components/remote/BoxRange.html b/components/remote/BoxRange.html new file mode 100644 index 00000000..a9ec325a --- /dev/null +++ b/components/remote/BoxRange.html @@ -0,0 +1,76 @@ + + + + + @[n] + + + + diff --git a/components/remote/CardHand.html b/components/remote/CardHand.html new file mode 100644 index 00000000..c3423f7a --- /dev/null +++ b/components/remote/CardHand.html @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + diff --git a/components/remote/DataInspector.html b/components/remote/DataInspector.html new file mode 100644 index 00000000..ff5b62c6 --- /dev/null +++ b/components/remote/DataInspector.html @@ -0,0 +1,388 @@ + + + + + + Vibe state (@[dataInspectorState(data, this.openPaths).shallowCount] | + @[dataInspectorState(data, this.openPaths).totalCount]) + + + + + + + + + + + + + @[row.key] + + @[row.summary] + + + + + + + + diff --git a/components/remote/LineGraph.html b/components/remote/LineGraph.html new file mode 100644 index 00000000..279278f8 --- /dev/null +++ b/components/remote/LineGraph.html @@ -0,0 +1,142 @@ + + + + @[$.unsafe(lineGraphLegend(series))] + + @[$.unsafe(lineGraphSvg(series, percent))] + + + + diff --git a/components/remote/Notifications.html b/components/remote/Notifications.html new file mode 100644 index 00000000..dc22fee1 --- /dev/null +++ b/components/remote/Notifications.html @@ -0,0 +1,640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @[notification.title] + + + @[notification.description] + + + + + + + + diff --git a/components/remote/Pagination.html b/components/remote/Pagination.html new file mode 100644 index 00000000..8a18ee51 --- /dev/null +++ b/components/remote/Pagination.html @@ -0,0 +1,5 @@ + + + Page @[page + 1] of @[pageCount] + + diff --git a/components/remote/PromptModal.html b/components/remote/PromptModal.html new file mode 100644 index 00000000..09db9b8c --- /dev/null +++ b/components/remote/PromptModal.html @@ -0,0 +1,322 @@ + + + + + +

@[promptModal.title]

+ + +
+ + + + + Prompt — sent verbatim to the image model + @[promptModal.preview] + + + @[promptModal.extraLabel] + + + + + + + Reference images — selected are attached to the request + + + + dropped reference + + Drop an image here + + + + + @[image.label] + + Current + + + + + + + + + + + Parallel generations + + + + +
+
+ + diff --git a/components/remote/Table.html b/components/remote/Table.html new file mode 100644 index 00000000..85c9454d --- /dev/null +++ b/components/remote/Table.html @@ -0,0 +1,79 @@ + + + + + + + + + +
+ + diff --git a/components/remote/Tooltip.html b/components/remote/Tooltip.html new file mode 100644 index 00000000..e9b1e98d --- /dev/null +++ b/components/remote/Tooltip.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + diff --git a/components/spa-demo/Fighter.html b/components/spa-demo/Fighter.html new file mode 100644 index 00000000..53412f7e --- /dev/null +++ b/components/spa-demo/Fighter.html @@ -0,0 +1,27 @@ + + + +

Fighter #@[page.params.fighter]

+

+ The param comes straight from the URL path (/fighter/7), parsed into + page.params by the router — the SPA equivalent of a + pages/fighter/$id.html dynamic route. +

+ + Fighter 7 + Fighter 13 + Fighter 42 + + + Switching fighters is a param-only navigation: the route doesn't change, so the component stays + mounted and just re-binds — the console should log no new script run. + +
diff --git a/components/spa-demo/Home.html b/components/spa-demo/Home.html new file mode 100644 index 00000000..0b10fd5c --- /dev/null +++ b/components/spa-demo/Home.html @@ -0,0 +1,44 @@ + + + +

SPA demo

+

+ This page is a fully self-contained SPA: one shell, one + <component src="@[page.src]"> that re-fetches and re-mounts + whenever the bound src changes, a route table mapping names to component files, and a router + that is nothing more than a two-way binding between the URL and $.page. No boot.js, + no game state — clean URLs served by the pages-tree catch-all + (spa-testing/$$route.html). +

+ +

Things to verify

+
    +
  • + Lazy mount — open the console/network tab: Timer and Fighter should only be + fetched on their first visit, never at load. +
  • +
  • + URL sync — back/forward walks the history, refresh restores the current page, + and a copied URL deep-links. +
  • +
  • + Lifecycle teardown — the Timer page runs two tickers: the global one + (shell-owned) keeps counting while you're away; the local one (component-owned) resets to 0 + every visit and its interval is cleared by $.on('unmount', …) — the tick rate + never accelerates, however many times you revisit. +
  • +
  • + Param navigation — switching fighters updates in place: same route, same + component, no script re-run. +
  • +
+ + + + Component-local state — navigate away and back and it resets to 0: a fresh mount, the same clean + slate an MPA reload gives you. + +
diff --git a/components/spa-demo/Timer.html b/components/spa-demo/Timer.html new file mode 100644 index 00000000..8d3aaab7 --- /dev/null +++ b/components/spa-demo/Timer.html @@ -0,0 +1,38 @@ + + + +

Timer

+ + + @[spaDemo.globalTicks] + global ticks — shell-owned, never stops + + + @[this.ticks] + local ticks — component-owned, resets every mount + + + @[spaDemo.timerMounts] + times mounted + + +

+ Two lifetimes, side by side. The global ticker is started once by the page + shell — navigate away and it keeps counting; nothing stacks because no navigation ever re-runs + the shell. The local ticker belongs to this component: + component({ ticks: 0 }) state is evicted on unmount (a fresh 0 every visit) and its + interval is cleared by $.on('unmount', () => clearInterval(timer)) — leave the page + and it genuinely stops. +

+ + Verify in the console: one mount log per visit, and neither tick rate ever accelerates no matter + how many times you come back. Before the unmount event existed, every visit stacked another + unstoppable interval — this page used to be the demonstration of that leak. + +
diff --git a/components/tooltip/Ability.html b/components/tooltip/Ability.html new file mode 100644 index 00000000..baa431c5 --- /dev/null +++ b/components/tooltip/Ability.html @@ -0,0 +1,234 @@ + + + + + + + + + + + + @[props.name] + + @[props.kind] Ability + + + + + + + + @[props.ticks] tick@[props.ticks === 1 ? '' : 's'] + + + + + + @[props.ticks] tick@[props.ticks === 1 ? '' : 's'] + + + + + + @[props.duration] + + + + + + @[props.targets.value] + + + + + + @[props.chainTicks] tick@[props.chainTicks === 1 ? '' : 's'] + + + + + + + @[props.damage.amount](@[props.damage.pct]% of total damage) + + + @[props.damage.pct]% + of total damage + + + + + + + + @[props.healing.amount](@[props.healing.pct]% of max health) + + + @[props.healing.pct]% + of max health + + + + + + + @[props.applications] + + + + + + + Temporarily applies + + + + + + + +

+ This ability inflicts + + + @[fx.amount] + + @[fx.word] + , which builds up to + + + @[fx.convertsAmount] + + @[fx.convertsWord] + . +

+ +
+ + + + +

+ This attack is + + unstoppable. +

+
+ + + + +

+ This ability is + + @[props.uninterruptable.pct]% + uninterruptable. +

+
+ + + +

+ @[$.unsafe(props.description.simple)] + @[$.unsafe(props.description.extended)] +

+ + + + ~ Press alt for more info ~ + ~ Release alt for less info ~ + +
+ + diff --git a/components/tooltip/Countdown.html b/components/tooltip/Countdown.html new file mode 100644 index 00000000..a6827eaa --- /dev/null +++ b/components/tooltip/Countdown.html @@ -0,0 +1,29 @@ + + + + @[char] + + + + + diff --git a/components/tooltip/Display.html b/components/tooltip/Display.html new file mode 100644 index 00000000..32e45e4f --- /dev/null +++ b/components/tooltip/Display.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/components/tooltip/Equipment.html b/components/tooltip/Equipment.html new file mode 100644 index 00000000..e6b093ac --- /dev/null +++ b/components/tooltip/Equipment.html @@ -0,0 +1 @@ + diff --git a/components/tooltip/Stat.html b/components/tooltip/Stat.html new file mode 100644 index 00000000..853fda48 --- /dev/null +++ b/components/tooltip/Stat.html @@ -0,0 +1,5 @@ + + @[label] + + + diff --git a/components/tooltip/Text.html b/components/tooltip/Text.html new file mode 100644 index 00000000..e1dfa991 --- /dev/null +++ b/components/tooltip/Text.html @@ -0,0 +1,33 @@ + + + + + @[props.name] + + + + + @[props.name] + + + +

@[$.unsafe(props.description)]

+ + + + Tooltip + +
+ + diff --git a/css/Iconice.css b/css/Iconice.css new file mode 100644 index 00000000..db98d239 --- /dev/null +++ b/css/Iconice.css @@ -0,0 +1,995 @@ +:root { + --icon-checkmark: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M96%20192%200%20288l192%20192%20320-320-96-96-224%20224z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-maxArmor: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201034%201024%22%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M516.9%2C851.3c-37.1%2C0-72.1-10.1-106.1-22.9-39.9-14.8-78.5-32.4-117.8-48.8-15.2-6.4-23.6-18.1-26.7-34-11.7-60.7-40.6-112.9-78.8-160.4-15.7-19.4-15.7-28.9.4-48.1%2C47.6-56.5%2C75-123.1%2C92.9-193.9%2C6-23.4%2C9.7-47.4%2C13.9-71.3%2C3.3-19%2C9.3-21.6%2C26.9-15%2C29.3%2C10.6%2C58.7%2C21%2C88.9%2C28.7%2C11%2C2.9%2C24.9-.4%2C36-4.6%2C16.1-6%2C30.9-15.2%2C46.1-23.2%2C16.1-8.4%2C32.2-8.4%2C48.5%2C0%2C14.6%2C7.5%2C29.3%2C15%2C44.1%2C22.7%2C13.7%2C7.1%2C27.8%2C9.5%2C42.6%2C4.9%2C27.6-8.8%2C55.4-17.2%2C82.5-27.1%2C20.7-7.7%2C26.3-5.5%2C29.3%2C16.1%2C9.3%2C66%2C26.5%2C129.7%2C57.8%2C188.4%2C14.6%2C26.9%2C32.9%2C52.1%2C51%2C77%2C11.9%2C16.3%2C13.2%2C27.6.2%2C43.2-39.9%2C48.8-69.3%2C102.6-81.6%2C165-2.6%2C13-9.3%2C23.4-21.2%2C29.3-63.1%2C31.8-128.2%2C58.5-198.1%2C71.5-10.1%2C1.5-20.5%2C1.5-30.9%2C2.4h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M613%2C246.2c-7.5-2.4-17.9-4.9-27.4-9.3-14.8-6.6-28.9-14.6-43-22.3-17.2-9.3-34.2-9.3-51.4.2-14.8%2C8.2-29.8%2C15.9-45%2C23.4-13.9%2C7.1-28.5%2C9-43.9%2C5.1-56.9-14.1-111-34.9-156.2-73.2-18.5-15.7-34-35.3-48.5-54.9-12.1-16.3-7.1-33.3%2C10.4-44.1%2C34.9-21.8%2C69.9-43.5%2C105-64.6%2C17-10.4%2C30-7.7%2C46.3%2C8.4%2C75.9%2C74.8%2C202.3%2C84.7%2C288.8%2C22.7%2C10.1-7.3%2C19.2-15.9%2C28.2-24.5%2C15.2-14.3%2C28.2-16.5%2C45.7-5.7%2C34.9%2C21.2%2C69.5%2C42.6%2C104.1%2C64.2%2C17.2%2C10.8%2C21%2C27.1%2C10.4%2C44.6-21.8%2C36.4-53.4%2C62.4-89.6%2C82.9-36.6%2C21-75.7%2C35.5-116.7%2C45-4.6.7-9.3%2C1.1-17.2%2C2.2h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M659.8%2C1024c-14.3.2-22.3-7.3-29.6-16.8-19.6-25.4-43.9-44.3-75-53.6-54.7-16.1-111.4%2C3.1-149.1%2C50.7-17%2C21.2-24.5%2C23.6-50.3%2C15-56.5-18.5-109.2-44.8-157.9-79-14.1-9.9-15.9-21.4-4.6-34.2%2C21-23.8%2C37.9-50.3%2C51-79.4%2C6-13.5%2C15.9-17%2C28.7-10.1%2C71%2C37.7%2C147.8%2C58.5%2C225.7%2C76.1%2C13.7%2C3.1%2C29.6%2C1.8%2C43.5-1.3%2C69.5-15.4%2C138.1-34.9%2C202.7-66%2C6-2.9%2C11.7-6.2%2C17.6-9%2C12.1-5.7%2C22.1-2.9%2C27.4%2C9.3%2C13.5%2C30.2%2C30.9%2C57.4%2C52.7%2C82.3%2C9.9%2C11.2%2C7.7%2C23.4-4.6%2C32-51.8%2C36.4-107.9%2C64.2-168.3%2C82.5-1.8.4-3.5%2C1.1-5.3%2C1.3-2.2.2-4.2.2-4.4.2h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M41.9%2C70.6c.2-14.8%2C6.2-24.3%2C16.8-31.1%2C8.4-5.3%2C17-10.1%2C25.6-15.2%2C15-8.8%2C19.6-7.3%2C24%2C9.5%2C11%2C40.8%2C27.8%2C79%2C51.2%2C114%2C21.4%2C32.2%2C47.4%2C60%2C80.7%2C80.1%2C9.9%2C6%2C13.5%2C13.9%2C11.5%2C24.9-2.9%2C17-5.5%2C34-8.6%2C51-3.5%2C19.2-14.3%2C24-32%2C14.3-69.7-38.2-116-97.1-146-169.4-9-21.8-14.6-45.2-21.6-68.2-1.1-3.8-1.1-7.9-1.5-9.9h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M993.8%2C69.7c-6%2C20.7-11%2C41.9-18.3%2C62.2-27.4%2C74.6-71.3%2C136.3-139.6%2C178.9-6%2C3.8-11.9%2C7.1-18.3%2C10.1-11.5%2C5.3-22.3.9-24.9-11.2-4.4-20.7-7.9-41.9-10.4-62.9-.7-5.1%2C3.8-13.5%2C8.4-16.3%2C72.1-45.9%2C110.3-114.9%2C134.3-193.9.9-3.1%2C1.5-6.4%2C2.6-9.5%2C3.1-7.5%2C8.6-10.4%2C15.9-6.4%2C11.9%2C6.6%2C23.6%2C13.5%2C34.9%2C21.2%2C9.3%2C6.2%2C13.7%2C15.7%2C15.4%2C27.8h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M0%2C295.8c6.8-26.5%2C12.4-51.2%2C19.6-75.2%2C3.3-10.8%2C16.5-11.2%2C23.8-1.8%2C7.1%2C9.3%2C13.2%2C19.4%2C20.1%2C28.9%2C34.9%2C46.5%2C76.8%2C85.8%2C122.9%2C120.9%2C22.5%2C17.2%2C24.9%2C26%2C11.5%2C51.2-6%2C11-12.4%2C21.6-19.4%2C31.8-6.6%2C9.5-16.5%2C11.7-26%2C5.3-52.7-36-102.8-75-138.5-128.8C7.5%2C318.3%2C4.4%2C306.4%2C0%2C295.8h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23335cc1%22%0A%20%20%20%20d%3D%22M1033.9%2C295.6c-4.4%2C10.6-7.1%2C22.3-13.2%2C31.8-29.3%2C45.4-70.1%2C79.6-112.9%2C111.4-7.9%2C6-16.1%2C11.5-24.5%2C17-11.5%2C7.5-21.2%2C6-28.5-5.3-8.2-12.6-15.9-25.6-22.7-38.8-8.2-15.9-5.1-27.6%2C9.3-38.4%2C48.3-36.4%2C92.4-77%2C128.8-125.7%2C7.1-9.5%2C13-19.4%2C20.3-28.9s20.5-8.8%2C23.8%2C2c7.3%2C24.5%2C12.8%2C49%2C19.6%2C75h0Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-criticalChance: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22586%22%20height%3D%22640%22%20viewBox%3D%220%200%20586%20640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M364.101%20544.969l-107.956-96.922-141.020%2033.966%2058.846-132.582-173.976-178.159%20242.413%2069.446%20118.159-240.718%206.31%20272.268%20219.048%2052.247-210.502%2075.864-11.322%20144.589z%22%3E%3C%2Fpath%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M549.868%20513.816l-237.473-85.276-114.085%20211.476%2012.44-246.884-108.496-56.574%20107.306-53.581%2016.009-122.883%2084.951%2090.251%20118.376-19.399-54.807%20109.362%20175.779%20173.507z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-criticalDamage: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22636%22%20height%3D%22640%22%20viewBox%3D%220%200%20636%20640%22%3E%0A%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M66.085%20583.409c29.785-5.026%2061.245-9.494%2092.333-16.196%2012.286-2.606%2024.572-9.122%2035.369-16.009%2024.2-15.451%2029.785-38.906%2017.313-64.596-9.122-18.802-23.642-33.322-39.093-46.911-29.226-25.689-62.362-45.98-96.987-63.665-21.408-10.983-43.56-20.663-65.526-31.088-2.42-1.117-4.654-2.42-9.494-4.84%2024.014%205.212%2045.422%2010.983%2067.016%2013.776%2020.105%202.793%2040.768%204.654%2060.873%202.793%2035.742-3.351%2050.448-25.503%2043.56-61.059-6.329-32.019-20.477-61.059-36.114-89.168-37.976-68.877-83.584-132.542-129.564-196.207-2.047-2.979-4.281-5.957-5.213-10.239%203.537%202.979%207.26%205.771%2010.797%208.749%2060.128%2051.006%20121.373%20100.337%20188.016%20142.781%2033.694%2021.407%2068.132%2041.885%20107.784%2051.192%205.399%201.303%2010.983%202.234%2016.567%202.606%2026.993%202.048%2044.491-12.844%2047.842-40.582%202.979-24.386-1.117-48.214-6.516-71.856-2.047-8.936-4.467-17.871-5.212-27.551%201.303%202.793%202.792%205.584%204.096%208.563%2019.919%2043.56%2042.257%2085.631%2070.366%20124.537%2015.637%2021.594%2032.763%2042.257%2055.288%2057.336%205.399%203.537%2011.169%206.702%2017.313%208.936%2019.733%207.446%2036.673%202.42%2049.331-14.334%2015.265-20.291%2020.477-44.305%2023.828-68.691%203.164-22.897%204.281-46.166%206.516-72.042%206.143%2024.945%2011.914%2047.283%2017.313%2069.622%2015.451%2066.457%2028.482%20133.473%2031.274%20201.792%201.861%2044.305%202.793%2089.168-11.542%20131.797-22.152%2066.643-69.808%20105.922-138.313%20119.325-63.479%2012.472-127.144%208.191-190.809-0.373-76.882-10.424-152.088-28.668-227.109-48.028-1.117-0.186-2.234-0.931-1.303-0.372zM310.32%20425.922c-0.559%200-1.117%200-1.676%200-1.117%208.563-2.606%2017.126-2.979%2025.689-4.096%2096.987%2082.839%20172.193%20178.523%20155.067%2061.059-10.983%20117.278-62.92%20123.421-136.637%204.84-57.894-25.689-120.628-87.121-149.296-54.171-25.317-108.901-3.164-128.261%2051.937-5.584%2016.009-5.957%2032.205-1.303%2048.586%203.723-3.351%207.074-6.143%2010.239-9.122%2016.567-14.52%2035.742-21.966%2058.080-20.105%2028.482%202.234%2044.491%2026.434%2035.742%2053.613-4.467%2014.147-13.776%2024.759-25.317%2033.508-21.78%2016.196-47.097%2018.988-72.601%2016.94-35.742-2.792-63.851-18.802-79.861-52.309-2.979-5.584-4.654-11.728-6.887-17.871z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-spin: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M304%2C480c-114.7%2C0-207.6-99.9-208-223.3%2C0-26.5-21.8-48.9-48.4-48.7-26.3.2-47.6%2C21.6-47.6%2C48%2C0%2C141.4%2C114.6%2C256%2C256%2C256s249.6-108.4%2C255.7-244.3c-5.6%2C118.3-96.5%2C212.3-207.7%2C212.3ZM256%2C0C118.5%2C0%2C6.4%2C108.4.3%2C244.3%2C5.9%2C126%2C96.8%2C32%2C208%2C32s207.6%2C99.9%2C208%2C223.3c0%2C26.5%2C21.8%2C48.9%2C48.4%2C48.7%2C26.3-.2%2C47.6-21.6%2C47.6-48C512%2C114.6%2C397.4%2C0%2C256%2C0Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-blockChance: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20782%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M.3%2C89h100.3c58.9.2%2C116.8-7.4%2C171.3-30%2C36.9-15.3%2C71.9-35.6%2C107.2-54.5%2C8.2-4.4%2C13.3-6.9%2C22.3-.8%2C86.3%2C58.9%2C182.1%2C86.8%2C286.6%2C85.3%2C30.4-.4%2C60.9%2C0%2C93.2%2C0v21.9c0%2C118.9-1.6%2C238%2C.4%2C356.9%2C1.9%2C112.7-32%2C212.8-97.1%2C303.3-75.7%2C105.3-174%2C185.3-284.9%2C250.8-4.3%2C2.5-12.5%2C3.1-16.6.7-127.3-75.6-238.2-168.6-315.8-297.2C21.3%2C649.1%2C1.2%2C565.8.5%2C477.7c-.9-121.8-.2-243.6-.2-365.4v-23.3H.3Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-error: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22768%22%20height%3D%22768%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M448.5%20384v-64.5h-129V384zm0%20127.5v-63h-129v63zm192-255v63H573q3%2021%203%2033V384h64.5v64.5H576V480q0%2010.5-3%2031.5h67.5V576h-90q-25.5%2043.5-69.75%2069.75T384%20672t-96.75-26.25T217.5%20576h-90v-64.5H195q-3-21-3-31.5v-31.5h-64.5V384H192v-31.5q0-12%203-33h-67.5v-63h90q22.5-37.5%2058.5-63L223.5%20141l45-45%2070.5%2069q22.5-4.5%2045-4.5t45%204.5l70.5-69%2045%2045-52.5%2052.5q37.5%2025.5%2058.5%2063z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-defeat: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22640%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M605.632%20178.688c-298.848%20434.176-196.544-8.32-449.184%20203.424l57.44%20225.888h-64.608l-117.28-461.12%2059.2-21.248c283.168-207.072%20135.296%20186.24%20500.384%2040.128%2011.648-4.704%2020.96%202.88%2014.048%2012.928z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-coin: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20346.8%20346.4%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M166.4.3l11.7-.3c128.9%2C4.3%2C210%2C143.3%2C146.7%2C257.7-69.2%2C125-253.5%2C115.9-310.3-15C-34.1%2C130.9%2C45.2%2C5.3%2C166.4.3ZM286.3%2C286.6c83.4-83.4%2C49.9-226.7-61.4-264.4C101.1-19.7-17.2%2C96.4%2C20.9%2C221.2c34.7%2C113.6%2C181.2%2C149.6%2C265.4%2C65.4Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M49.6%2C119c2.8%2C34.9%2C12.9%2C78.6%2C47.6%2C94.9%2C28.7%2C13.5%2C64.1%2C9.1%2C65%2C50.8s-4.4%2C41-11.7%2C47.8-23.1%2C1.1-32.2-2.7C31.3%2C274%2C.3%2C165.3%2C55.8%2C88.7%2C116.5%2C4.9%2C244%2C10.1%2C298.1%2C98.1c48.3%2C78.5%2C11.9%2C183.6-74.9%2C213.9s-20.4%2C8.3-27.9-1.1c-6-7.4-10.9-36.6-10.6-46.5%2C1.2-42.8%2C38-37.2%2C66.7-51.3%2C32.9-16.2%2C45.1-61.1%2C45.3-95.2-9%2C1.5-18.2%2C1.3-27.2%2C3.3-24%2C5.3-47.2%2C20.7-61.3%2C40.7.2-20.9-6.7-39.1-17.5-56.5-5.1-8.3-11.5-15.5-17-23.5-1.5-1-11.8%2C14.6-13%2C16.5-11.8%2C18.4-21.7%2C40.2-21%2C62.5-13.9-16.3-30.7-29.4-51.2-36.3-5.1-1.7-18.5-5.7-23.3-5.7h-15.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M173.3%2C168.2c3.4-.3%2C11.8%2C8%2C13.8%2C10.8%2C9.1%2C12.9%2C6.2%2C33-6%2C42.9s-8.1%2C5.2-14.4.4c-15.1-11.5-15.7-36.9-1.6-49.4%2C1.3-1.2%2C6.7-4.7%2C8.2-4.8Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-menu: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22768%22%20height%3D%22768%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M96%20416h576c17.664%200%2032-14.336%2032-32s-14.336-32-32-32H96c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032m0-192h576c17.664%200%2032-14.336%2032-32s-14.336-32-32-32H96c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032m0%20384h576c17.664%200%2032-14.336%2032-32s-14.336-32-32-32H96c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-info: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M397.824.001c42.88%200%2064.32%2029.184%2064.32%2062.624%200%2041.76-37.248%2080.384-85.728%2080.384-40.608%200-64.288-24-63.168-63.68%200-33.376%2028.192-79.328%2084.576-79.328m-131.936%20640c-33.856%200-58.656-20.864-34.976-112.768l38.848-162.944c6.752-26.048%207.872-36.512%200-36.512-10.144%200-54.048%2017.984-80.064%2035.744l-16.896-28.16c82.304-69.952%20176.992-110.944%20217.632-110.944%2033.824%200%2039.456%2040.736%2022.56%20103.36L368.48%20499.041c-7.872%2030.24-4.512%2040.672%203.392%2040.672%2010.144%200%2043.424-12.544%2076.128-38.624l19.2%2026.048c-80.064%2081.504-167.52%20112.864-201.312%20112.864%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-light: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22768%22%20height%3D%22768%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M576%20384c0-53.024-21.536-101.056-56.224-135.776S437.024%20192%20384%20192s-101.056%2021.536-135.776%2056.224S192%20330.976%20192%20384s21.536%20101.056%2056.224%20135.776S330.976%20576%20384%20576s101.056-21.536%20135.776-56.224S576%20437.024%20576%20384m-64%200c0%2035.36-14.304%2067.296-37.504%2090.496S419.36%20512%20384%20512s-67.296-14.304-90.496-37.504S256%20419.36%20256%20384s14.304-67.296%2037.504-90.496S348.64%20256%20384%20256s67.296%2014.304%2090.496%2037.504S512%20348.64%20512%20384M352%2032v64c0%2017.664%2014.336%2032%2032%2032s32-14.336%2032-32V32c0-17.664-14.336-32-32-32s-32%2014.336-32%2032m0%20640v64c0%2017.664%2014.336%2032%2032%2032s32-14.336%2032-32v-64c0-17.664-14.336-32-32-32s-32%2014.336-32%2032M112.416%20157.664l45.44%2045.44c12.512%2012.512%2032.768%2012.512%2045.248%200s12.512-32.768%200-45.248l-45.44-45.44c-12.512-12.512-32.768-12.512-45.248%200s-12.512%2032.768%200%2045.248m452.48%20452.48%2045.44%2045.44c12.512%2012.512%2032.768%2012.512%2045.248%200s12.512-32.768%200-45.248l-45.44-45.44c-12.512-12.512-32.768-12.512-45.248%200s-12.512%2032.768%200%2045.248M32%20416h64c17.664%200%2032-14.336%2032-32s-14.336-32-32-32H32c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032m640%200h64c17.664%200%2032-14.336%2032-32s-14.336-32-32-32h-64c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032M157.664%20655.584l45.44-45.44c12.512-12.512%2012.512-32.768%200-45.248s-32.768-12.512-45.248%200l-45.44%2045.44c-12.512%2012.512-12.512%2032.768%200%2045.248s32.768%2012.512%2045.248%200m452.48-452.48%2045.44-45.44c12.512-12.512%2012.512-32.768%200-45.248s-32.768-12.512-45.248%200l-45.44%2045.44c-12.512%2012.512-12.512%2032.768%200%2045.248s32.768%2012.512%2045.248%200%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-spinner-circle: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221024%22%20height%3D%221024%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M512%200C229.376%200%200%20229.376%200%20512s229.376%20512%20512%20512%20512-229.376%20512-512S794.624%200%20512%200m0%20869.99c-198.246%200-357.99-159.744-358.81-358.81%200-198.246%20160.563-358.81%20358.81-358.81s358.81%20160.563%20358.81%20358.81S710.247%20869.99%20512%20869.99%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-success: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M265.408%20543.936a44.51%2044.51%200%200%201-35.552-17.696L115.52%20375.168c-14.88-19.616-11.008-47.552%208.64-62.432%2019.68-14.944%2047.616-11.008%2062.496%208.64l75.232%2099.328L451.04%20116.96c13.024-20.864%2040.544-27.264%2061.472-14.24%2020.896%2012.992%2027.328%2040.512%2014.272%2061.44L303.296%20522.88c-7.744%2012.512-21.152%2020.32-35.84%2020.992-.704.064-1.344.064-2.048.064%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-maxHealth: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221106%22%20height%3D%221024%22%0A%20%20viewBox%3D%220%200%201106%201024%22%3E%0A%20%20%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%20%20%3Cpath%20fill%3D%22%239f0712%22%0A%20%20%20%20d%3D%22M815.571%200c-116.202%200-216.204%2094.603-262.642%20193.309-46.437-98.707-146.44-193.309-262.642-193.309-160.263%200-290.288%20130.025-290.288%20290.288%200%20325.926%20328.734%20411.457%20552.93%20733.712%20211.884-320.31%20552.93-418.153%20552.93-733.712%200-160.263-130.025-290.288-290.288-290.288v0z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-__armor: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22803%22%20height%3D%221024%22%20viewBox%3D%220%200%20803%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23335cc1%22%20d%3D%22M745.422%20712.93c-13.379-82.427-10.512-165.092-3.823-247.757%206.212-75.259-6.929-146.934-42.527-213.592-64.747-120.892-168.676-196.629-291.24-250.385-3.823-1.672-9.796-1.434-13.618%200.239-99.867%2043.244-187.311%20103.451-253.491%20191.134-59.013%2077.887-86.249%20166.048-80.276%20263.765%204.301%2064.030%209.079%20127.821%204.062%20192.090-6.212%2078.365-18.636%20154.818-64.269%20221.715%2012.424%2019.113%2035.838%2040.377%2066.419%2059.49%2058.774%2036.793%20123.042%2061.163%20188.984%2081.232%2015.53%204.778%2031.059%208.84%2046.589%2013.14%202.628-140.722%2025.086-278.1%2041.333-416.194-5.734-2.15-10.99-3.823-16.246-5.734-58.057-20.547-115.158-43.722-166.525-78.843-13.379-9.079-16.007-20.786-16.963-35.36h10.273c73.825%201.434%20146.695%2010.512%20219.565%2022.219%2011.707%201.911%2023.892%204.539%2035.36%203.106%2057.579-6.929%20115.158-15.291%20172.737-21.98%2025.564-2.867%2051.606-2.628%2077.409-3.823-1.911%2023.892-1.672%2026.52-19.83%2037.032-31.298%2018.158-62.835%2035.838-95.567%2051.128-27.237%2012.902-56.146%2022.219-84.338%2033.21%2016.246%20137.855%2038.466%20274.755%2041.094%20414.283%202.15-0.239%204.062-0.239%205.973-0.717%2069.525-18.397%20137.139-41.572%20200.452-75.737%2036.315-19.352%2070.242-42.049%2096.045-76.215-33.687-47.783-48.5-101.54-57.579-157.447zM403.293%20455.138l-0.717%200.478-0.717-0.478-28.909-18.636%2029.148-386.329%200.478-6.212%200.478%206.929%2027.476%20385.374-27.237%2018.874z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-dice: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22636%22%20height%3D%22640%22%20viewBox%3D%220%200%20636%20640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M368.226%200c-1.844-0.041-3.835%200.416-6.361%201.272l-279.85%2082.173c-2.329%200.544-2.193%201.172-0.254%202.671l248.419%20198.314c4.574%203.793%206.726%204.262%2013.102%202.289l278.562-96.545c6.391-2.349%206.835-2.92%200.255-7.251l-244.486-178.839c-3.774-2.66-6.341-4.011-9.412-4.070zM336.299%2024.041c5.573-0.041%2011.456%200.571%2017.553%201.908%2024.393%205.348%2041.692%2020.254%2038.542%2033.199s-25.47%2019.086-49.863%2013.737c-24.393-5.348-41.692-20.127-38.542-33.072%202.362-9.709%2015.591-15.691%2032.308-15.773zM178.569%2071.997c5.572-0.041%2011.582%200.571%2017.681%201.908%2024.393%205.348%2041.565%2020.127%2038.415%2033.072s-25.47%2019.214-49.863%2013.865c-24.393-5.348-41.565-20.254-38.415-33.199%202.363-9.709%2015.464-15.563%2032.181-15.646zM417.573%2084.208c5.572-0.041%2011.583%200.699%2017.681%202.036%2024.393%205.348%2041.565%2020.127%2038.415%2033.072s-25.47%2019.086-49.863%2013.737c-24.393-5.348-41.565-20.127-38.415-33.072%202.363-9.708%2015.464-15.691%2032.183-15.773zM64.472%2099.599c-0.511%200.13-0.676%200.928-1.017%202.544l-63.091%20315.579c-0.735%203.282-0.606%204.096%202.417%206.742l239.647%20206.581c5.574%205.327%206.745%205.259%207.505-1.272l69.834-320.035c1.463-4.36-0.043-6.759-2.544-8.777l-250.212-199.811c-1.288-1.086-2.033-1.656-2.544-1.527zM259.096%20135.597c5.572-0.041%2011.582%200.571%2017.681%201.908%2024.393%205.348%2041.565%2020.128%2038.415%2033.072s-25.47%2019.086-49.863%2013.738c-24.393-5.348-41.565-20.127-38.415-33.072%202.362-9.709%2015.464-15.563%2032.181-15.646zM500.658%20146.155c5.573-0.041%2011.583%200.571%2017.681%201.908%2024.393%205.348%2041.565%2020.127%2038.415%2033.072s-25.47%2019.214-49.863%2013.865c-24.393-5.348-41.565-20.254-38.415-33.199%202.363-9.708%2015.464-15.563%2032.182-15.646zM79.996%20157.73c0.94-0.094%201.969-0.051%202.926%200%2011.479%200.608%2023.909%2011.366%2031.164%2028.62%209.674%2023.006%206.448%2048.826-7.123%2057.622s-32.43-2.688-42.102-25.694c-9.674-23.006-6.449-48.826%207.123-57.622%202.544-1.649%205.194-2.647%208.014-2.926zM342.164%20199.197c5.573-0.040%2011.583%200.571%2017.681%201.908%2024.393%205.347%2041.565%2020.127%2038.415%2033.072s-25.47%2019.086-49.863%2013.738c-24.393-5.348-41.565-20.127-38.415-33.072%202.362-9.709%2015.464-15.563%2032.181-15.646zM634.858%20207.974c-0.535%200.11-1.287%200.298-2.163%200.636l-286.081%2099.236c-5.827%202.399-5.652%203.378-6.614%207.759l-69.707%20319.026c-0.237%204.697-1.967%206.834%203.562%204.325l281.886-105.323c5.469-2.617%206.518-3.076%207.123-8.395l73.141-314.57c0.606-2.216%200.459-3.006-1.145-2.671zM588.429%20259.745c8.055%200.13%2014.376%204.048%2017.173%2011.576%205.592%2015.054-5.177%2039.147-24.168%2053.805s-38.928%2014.291-44.52-0.763c-5.593-15.054%205.176-39.148%2024.168-53.807%209.496-7.329%2019.294-10.942%2027.348-10.813zM241.681%20287.347c11.624%200.297%2024.304%2011.223%2031.672%2028.748%209.674%2023.006%206.576%2048.826-6.996%2057.622s-32.43-2.815-42.102-25.822c-9.674-23.006-6.449-48.699%207.123-57.494%202.545-1.649%205.193-2.647%208.014-2.926%200.764-0.079%201.515-0.146%202.289-0.126zM139.539%20324.236c11.624%200.298%2024.304%2011.223%2031.673%2028.748%209.674%2023.006%206.576%2048.826-6.996%2057.622s-32.43-2.815-42.102-25.822c-9.674-23.006-6.448-48.699%207.123-57.494%202.544-1.649%205.193-2.647%208.014-2.926%200.764-0.079%201.515-0.146%202.29-0.126zM38.923%20360.741c0.939-0.094%201.969-0.048%202.926%200%2011.479%200.607%2023.782%2011.493%2031.037%2028.747%209.674%2023.006%206.576%2048.699-6.996%2057.494s-32.43-2.688-42.103-25.694c-9.674-23.006-6.449-48.826%207.123-57.622%202.545-1.649%205.194-2.647%208.014-2.926zM481.079%20391.269c7.882%200.256%2014.165%204.166%2016.917%2011.576%205.593%2015.054-5.304%2039.147-24.296%2053.805-18.991%2014.658-38.928%2014.291-44.52-0.763s5.304-39.147%2024.296-53.805c8.309-6.413%2016.779-9.986%2024.168-10.685%201.188-0.114%202.308-0.163%203.434-0.126zM195.26%20493.413c0.94-0.094%201.969-0.048%202.926%200%2011.479%200.607%2023.909%2011.366%2031.164%2028.62%209.674%2023.006%206.449%2048.826-7.123%2057.622s-32.303-2.688-41.976-25.694c-9.674-23.006-6.576-48.826%206.996-57.622%202.545-1.649%205.194-2.646%208.014-2.926zM364.564%20526.484c8.055%200.13%2014.376%203.921%2017.172%2011.448%205.592%2015.054-5.176%2039.147-24.168%2053.805-18.991%2014.658-38.928%2014.418-44.52-0.636s5.176-39.147%2024.168-53.807c9.496-7.329%2019.294-10.942%2027.348-10.812z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-spinner-inner: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221024%22%20height%3D%221024%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M0%20512C0%20229.376%20229.376%200%20512%200v154.01c-198.246%200-358.81%20160.563-358.81%20358.81z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stun: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221018%22%20height%3D%221024%22%0A%20%20viewBox%3D%220%200%201018%201024%22%3E%0A%20%20%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M105.736%20933.454c47.656-8.042%2097.992-15.19%20147.732-25.913%2019.658-4.17%2039.316-14.595%2056.591-25.615%2038.72-24.721%2047.656-62.25%2027.7-103.353-14.595-30.083-37.827-53.315-62.548-75.058-46.762-41.103-99.779-73.568-155.179-101.864-34.252-17.573-69.696-33.061-104.842-49.741-3.872-1.787-7.446-3.872-15.19-7.744%2038.422%208.34%2072.675%2017.573%20107.225%2022.041%2032.168%204.468%2065.229%207.446%2097.396%204.468%2057.187-5.361%2080.717-40.805%2069.696-97.694-10.127-51.23-32.763-97.694-57.782-142.669-60.761-110.204-133.734-212.067-207.302-313.931-3.276-4.766-6.85-9.531-8.34-16.382%205.659%204.766%2011.616%209.233%2017.275%2013.999%2096.205%2081.61%20194.197%20160.54%20300.826%20228.449%2053.91%2034.252%20109.012%2067.016%20172.454%2081.908%208.638%202.085%2017.573%203.574%2026.508%204.17%2043.188%203.276%2071.186-20.551%2076.547-64.931%204.766-39.018-1.787-77.143-10.425-114.969-3.276-14.297-7.148-28.593-8.34-44.081%202.085%204.468%204.468%208.935%206.553%2013.701%2031.87%2069.696%2067.611%20137.010%20112.586%20199.26%2025.019%2034.55%2052.421%2067.611%2088.461%2091.737%208.638%205.659%2017.871%2010.723%2027.7%2014.297%2031.572%2011.914%2058.676%203.872%2078.93-22.934%2024.424-32.465%2032.763-70.888%2038.124-109.906%205.063-36.635%206.85-73.866%2010.425-115.267%209.829%2039.912%2019.062%2075.653%2027.7%20111.395%2024.721%20106.332%2045.571%20213.557%2050.038%20322.867%202.978%2070.888%204.468%20142.669-18.467%20210.876-35.444%20106.629-111.693%20169.475-221.301%20190.92-101.566%2019.956-203.43%2013.105-305.294-0.596-123.011-16.679-243.341-45.869-363.374-76.845-1.787-0.298-3.574-1.489-2.085-0.596zM496.512%20681.475c-0.894%200-1.787%200-2.681%200-1.787%2013.701-4.17%2027.402-4.766%2041.103-6.553%20155.179%20132.542%20275.509%20285.636%20248.107%2097.694-17.573%20187.644-100.672%20197.473-218.62%207.744-92.631-41.103-193.005-139.393-238.874-86.674-40.507-174.241-5.063-205.217%2083.099-8.935%2025.615-9.531%2051.528-2.085%2077.738%205.957-5.361%2011.318-9.829%2016.382-14.595%2026.508-23.232%2057.187-35.146%2092.928-32.168%2045.571%203.574%2071.186%2042.294%2057.187%2085.78-7.148%2022.636-22.041%2039.614-40.507%2053.613-34.848%2025.913-75.355%2030.38-116.161%2027.104-57.187-4.468-102.162-30.083-127.777-83.695-4.766-8.935-7.446-18.764-11.020-28.593z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-warning: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M288%2064v256h-64V64zm-64%20384h64v-64h-64z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-victory: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22981%22%20height%3D%221024%22%0A%20%20viewBox%3D%220%200%20981%201024%22%3E%0A%20%20%3Cpath%20fill%3D%22%23FFD700%22%0A%20%20%20%20d%3D%22M341.732%20713.688c15.86-6.583%2031.42-11.67%2045.485-19.151%2024.837-12.867%2027.231-29.625%208.678-49.973-3.591-3.89-7.78-7.78-12.269-10.773-31.719-20.947-63.738-41.894-98.151-64.337-10.473%208.977-24.238%2020.947-39.5%2033.814%208.977%208.379%2016.757%2015.86%2026.333%2024.837-10.473%2019.75-21.246%2040.397-32.916%2062.84-169.968-171.764-251.063-375.247-237.896-617.333%2017.356%204.189%2033.814%207.481%2049.674%2012.269%202.992%200.898%205.985%206.883%206.284%2010.773%200.898%2013.466%200.299%2026.932%200.299%2041.594%2019.151%200%2037.704%200%2056.556%200%200-18.553%200.299-36.507%200-54.162-0.598-17.655%205.985-32.617%2022.144-38.602%2025.136-9.576%2050.871-19.451%2077.503-23.939%20116.704-20.049%20234.305-25.136%20352.505-18.553%2061.344%203.292%20122.988%208.678%20184.033%2015.86%2028.727%203.292%2057.155%2011.67%2084.386%2021.246%2026.932%209.276%2034.712%2024.238%2033.814%2052.666-0.598%2014.962-2.095%2029.625-2.992%2046.083%2019.451%200%2037.405%200%2057.155%200%200-12.867-0.299-25.735%200.299-38.602%200.299-4.189%202.693-10.773%205.386-11.97%2016.159-5.686%2032.916-9.576%2052.666-15.261%207.182%20240.589-63.14%20448.262-238.794%20618.53-12.269-22.443-23.64-42.791-35.011-63.738%209.276-8.678%2017.954-16.757%2028.129-26.932-14.064-11.97-27.231-23.64-37.704-32.617-34.113%2022.443-66.132%2043.689-98.45%2065.234-13.167%208.678-26.333%2019.75-25.136%2036.208%200.898%2017.356%2017.057%2024.538%2031.121%2030.523%2011.371%204.788%2023.041%208.379%2034.712%2012.269-13.167%205.985-26.632%2010.174-38.602%2017.356-28.727%2017.356-38.303%2042.791-26.932%2073.912%2018.852%2052.068%2058.651%2086.181%20106.53%20109.522%2020.049%209.875%2045.185%209.276%2067.628%2014.663%209.875%202.394%2020.049%206.583%2028.727%2011.97%2021.845%2013.466%2021.246%2040.697-2.693%2049.973-25.136%209.576-51.469%2017.057-78.102%2021.246-88.874%2013.765-178.646%2014.962-268.119%2011.97-66.431-2.095-133.162-5.087-197.499-23.341-8.379-2.394-17.057-5.686-24.538-9.875-22.144-12.867-22.443-40.098%201.197-50.572%2020.049-8.977%2041.894-17.057%2063.439-19.151%2040.996-3.89%2069.723-26.932%2096.355-54.162%2014.064-14.364%2026.632-31.121%2035.61-49.075%2021.545-42.791%206.883-77.802-38.004-95.757-8.079-2.992-15.86-5.087-23.341-7.481zM163.684%2076.605c13.765%203.89%2025.136%207.78%2036.807%2010.473%2074.212%2016.458%20149.62%2021.246%20225.328%2023.041%2065.833%201.197%20131.666%200.898%20197.199-3.292%2053.564-3.292%20106.53-12.568%20159.794-20.049%2011.072-1.496%2021.545-6.284%2036.208-10.473-117.601-49.674-558.382-46.981-655.336%200.299zM60.746%20196.002c13.466%20135.257%2054.761%20256.15%20141.84%20361.781%2011.97-12.568%2021.845-23.939%2032.916-33.814%207.481-6.883%207.78-11.371%202.095-19.75-14.663-22.443-29.326-44.886-41.894-68.526-37.704-71.818-59.549-149.022-72.416-228.919-0.598-3.89-5.386-10.174-8.678-10.174-17.356-1.197-34.712-0.598-53.863-0.598zM778.025%20551.799c82.59-105.033%20128.973-222.635%20141.84-355.797-15.86%200-29.625%201.197-42.791-0.299-15.86-2.095-19.151%205.686-20.947%2018.852-10.473%2070.621-29.924%20138.847-61.643%20202.885-16.458%2033.216-35.909%2064.935-54.761%2098.45%2011.67%2010.473%2024.238%2022.443%2038.303%2035.909z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-magicChance: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22742%22%20height%3D%22640%22%20viewBox%3D%220%200%20742%20640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M497.898%2069.858c-3.037%2054.021-5.857%20108.257-9.112%20165.532%2030.156-31.674%2058.793-61.397%2087.214-91.119%200.651%200.434%201.302%200.651%201.952%201.085-9.329%2038.4-18.874%2076.583-28.854%20117.369%2031.241-10.414%2060.962-20.176%2093.505-31.024-22.129%2043.39-43.173%2084.393-65.085%20126.698%2021.261-3.905%2040.786-7.593%2060.529-11.498%200.434%200.651%200.651%201.519%201.085%202.169-16.705%2012.366-33.193%2025.166-50.115%2037.098-2.603%201.736-6.942%201.519-10.414%201.519-25.6%200.217-51.417%200-77.017%200.651-51.417%201.302-98.495%2012.366-129.519%2059.878-4.339-5.641-8.027-10.414-11.933-14.969-22.997-26.685-53.586-39.485-87.647-42.305-36.231-2.821-72.895-1.952-109.342-3.471-7.376-0.217-15.403-3.254-21.695-7.376-14.536-9.762-28.203-20.827-41.438-33.41%2026.251%204.773%2052.502%209.546%2081.573%2014.969-30.807-37.749-59.661-73.112-90.685-111.078%2036.881%207.376%2070.291%2013.885%20105.654%2020.827-11.498-26.034-22.346-50.549-34.495-77.885%2027.119%2013.451%2051.417%2025.6%2077.234%2038.4-3.905-47.078-7.81-92.203-11.715-137.329%200.867-0.434%201.519-0.867%202.386-1.085%2028.421%2037.749%2056.841%2075.715%2086.563%20115.417%2015.403-70.726%2030.373-139.715%2045.126-208.922%200.868%200%201.736%200%202.386%200%2020.176%2070.726%2040.136%20141.668%2061.179%20215.864%2024.298-50.983%2047.295-98.712%2070.074-146.657%200.868%200.217%201.736%200.434%202.603%200.651z%22%3E%3C%2Fpath%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M45.343%20459.933c21.261-14.752%2041.221-28.854%2061.397-42.739%202.386-1.736%206.074-2.169%209.112-2.169%2041.221%200.651%2082.224%200.868%20123.444%202.386%2017.139%200.651%2034.712%202.821%2051.2%206.726%2031.241%207.593%2052.502%2027.553%2065.085%2056.841%204.339%209.979%209.329%2019.526%2015.403%2032.109%206.074-11.281%2011.498-19.959%2015.403-29.288%2016.488-40.569%2047.946-61.179%2089.817-64%2041.654-2.821%2083.742-1.953%20125.614-2.603%200.651%200%201.519%200.217%202.169%200%2024.298-7.376%2042.956%203.471%2060.746%2018.224%2010.197%208.461%2021.695%2015.403%2034.061%2024.298-29.288%2010.414-57.057%2020.176-84.827%2029.939-77.885%2027.336-155.769%2054.888-233.871%2082.224-4.773%201.736-10.847%202.169-15.403%200.434-103.485-36.014-206.969-72.461-310.454-108.691-2.603-0.868-4.99-2.169-8.895-3.688z%22%3E%3C%2Fpath%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M732.203%20479.674c3.254%209.329%206.074%2017.573%209.546%2027.553-99.362%2034.712-197.857%2069.207-296.786%20103.919%200%209.762%200%2019.091%200%2028.854-48.162%200-95.674%200-144.488%200%200-5.857-0.651-11.281%200.217-16.488%201.302-8.895-2.821-12.366-10.847-15.186-93.071-32.326-186.142-64.868-278.997-97.41-3.254-1.085-6.726-2.386-10.848-3.905%203.254-9.329%206.291-18.007%209.546-27.336%20108.257%2037.966%20215.647%2075.498%20323.688%20113.464-1.736%205.858-3.254%2011.064-4.99%2016.922%2028.203%200%2055.756%200%2084.61%200-1.519-5.424-3.038-10.414-4.773-16.488%20107.607-37.749%20215.214-75.498%20324.122-113.898z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-damage: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221014%22%20height%3D%221024%22%20viewBox%3D%220%200%201014%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%2315970f%22%20d%3D%22M222.8%20642.4l95.3-95.3%20158.3%20158.4-95.2%2095.2%2086.5%2086.5-77.2%2077.2-130.2-130.1-189.7%20189.7-70.6-70.6%20189.7-189.7-130.2-130.1%2077.2-77.2%2086.1%2086z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%2315970f%22%20d%3D%22M1005.4%2018.6l-57.1%20213.1%201.4%200.4-236.2%20236.2-158.3-158.3%20236.1-236.2%200.4%201.4%20213.1-57.1%200.6%200.5z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%2315970f%22%20d%3D%22M877.1%20538.2l77.1%2077.2-130%20130.1%20189.7%20189.7-70.6%2070.6-189.7-189.7-130.2%20130.2-77.2-77.2%2086.5-86.5-568.6-568.6%201.4-0.4-57-213.2%200.4-0.4%20213.2%2057.1%200.4-1.4%20568.6%20568.6%2086-86.1z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-claw: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221182%22%20height%3D%221024%22%20viewBox%3D%220%200%201182%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M359.226%20108.106c43.918-64.563%2098.346-105.853%20175.672-108.106%2036.786-1.126%2065.314%2013.889%2085.584%2046.921%2075.449%20121.994%20118.24%20252.997%20111.109%20397.889-4.129%2088.211-28.528%20170.792-69.443%20248.868-0.751%201.501-2.252%202.628-8.258%209.76%209.76-254.499-109.607-440.68-294.663-595.331z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M917.021%20794.651c-8.258-61.185-13.513-120.493-24.774-178.674-14.639-77.701-47.296-148.645-93.466-212.457-14.639-19.894-16.891-40.54-19.144-62.686-7.883-75.073-28.528-146.768-59.683-215.836-1.501-3.378-2.252-6.757-3.378-10.886%2031.155-15.765%2063.437-21.396%2096.845-15.765%2026.276%204.504%2046.545%2018.393%2061.185%2041.666%2076.95%20122.745%20120.493%20254.874%20113.361%20400.891-4.129%2088.211-28.152%20170.792-69.067%20248.868-1.126%201.877-1.501%203.754-1.877%204.88z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M295.789%201024c-99.848-24.023-175.296-75.073-224.094-162.909-36.786-66.44-55.179-138.886-70.569-212.457-5.255-25.525%206.757-46.921%2025.15-63.437%2041.666-38.663%2091.965-47.672%20146.393-40.164%2011.636%201.501%2010.51%209.009%2010.51%2017.642-0.375%2063.812-1.877%20127.625%200.751%20191.062%203.003%2073.572%2031.531%20139.261%2068.692%20201.947%2013.138%2021.771%2027.026%2043.167%2043.167%2068.317z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M1108.833%20931.284c-6.006-52.927-9.76-104.727-17.642-155.402-8.633-55.179-27.026-107.73-51.425-158.029-3.378-6.757-6.006-15.765-5.255-22.897%2016.516-121.994-3.378-238.733-49.173-352.094-1.126-3.003-1.877-6.006-3.003-10.51%2034.909%200.375%2063.437%209.76%2082.956%2039.413%2060.809%2094.217%20101.349%20196.317%20113.361%20308.176%2012.762%20123.496-10.51%20240.61-69.818%20351.343z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-logo-apeegg-simple: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22340%22%20height%3D%22448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M305.249%20120.181C273.934%2053.884%20221.742%200%20169.834%200%20117.079%200%2064.323%2058.398%2033.008%20126.106%209.028%20178.861%200%20237.259%200%20278.167c0%2093.944%2076.171%20169.834%20169.834%20169.834s169.834-76.171%20169.834-169.834c0-41.753-9.31-104.383-34.418-157.985zM132.877%20390.166c-37.521.847-37.521-27.647-37.521-27.647%202.257-24.544%2020.03-19.184%2043.164-20.03s42.035%2016.927%2043.164%2026.801c.847%209.874-11.284%2020.03-48.806%2020.877zm115.949-180.272c0%2018.337%2014.952%2027.93%2018.056%2036.957%203.103%209.31%206.489%2027.083-2.821%2030.751-13.824%205.078-26.237-4.514-44.574-16.081s-7.617%2010.721-7.617%2010.721%2017.773%2028.493%2017.773%2055.295-21.441%2018.337-21.441%2018.337-30.468-25.108-69.683-25.108c-39.214%200-40.343%209.028-54.73%209.874-14.67.847-15.234-3.95-15.234-17.773s7.617-22.851%2018.056-34.7c7.335-8.181%206.489-23.134-5.925-16.927s-37.521%2015.234-38.368%200%2022.287-35.265%2022.287-49.934-32.161-29.904-33.854-41.471C29.34%20158.268%2047.678%2094.51%2081.532%2093.664c33.008-.847%2010.438%2028.493%2063.194%2029.904h6.771c7.899-.282%2021.723-.564%2043.728-20.594%2027.647-25.39%2052.192-20.03%2062.912-11.567s32.161%2020.03%2032.161%2057.552c0%2037.804-41.471%2042.317-41.471%2060.937z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M116.232%20208.201c-12.695%201.975-29.058-9.028-34.418-12.977-.847-.564-1.975-.282-2.257.847-6.489%2024.544%206.206%2023.98%2012.413%2025.955%206.489%201.975%202.539%206.489-.282%208.181-3.385%201.693-15.799-1.128-15.799-1.128.564%207.335%2014.388%205.078%2020.03%204.796%201.41%200%202.821-.564%203.95-1.693%206.489-5.642%2029.622-25.955%2016.363-23.98zm69.4%205.643c-11.849-.282%205.078%2014.67%2013.542%2021.723%203.103%202.539%206.771%204.232%2010.721%204.796%206.489.847%2015.799.847%2016.081-5.642%200%200-13.259%203.103-15.799%201.128s-7.053-6.206-.282-8.181c6.489-1.975%2030.186-1.411%2022.569-27.93-.282%200-30.186%2014.388-46.831%2014.106zm-10.72%2020.312c-6.206%200-34.418%2028.212-34.983%2033.008-.282%204.514-7.053-31.033-26.237-30.186-19.184.564-12.977%2013.259-11.003%2019.184s16.645%2017.491%2021.159%2017.773c0%200-13.824-13.541-13.824-18.902s1.41-7.053%205.36-7.053%209.31%203.103%2012.695%2010.72c2.539%205.925%206.206%2013.824%207.617%2017.491.564%201.128%201.411%201.693%202.821%201.693.847%200%201.975-.564%202.257-1.128%203.95-5.642%2021.441-28.776%2031.879-28.776%2011.849%200%207.053%2012.413%203.95%2014.952-3.103%202.821-9.874%207.617-20.03%209.592%200%200%2013.824%203.95%2029.622-11.567%2015.799-14.952-3.385-26.801-11.284-26.801z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-cross: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22m507.331%20411.33-.006-.005L352.003%20256l155.322-155.325.006-.005a15.9%2015.9%200%200%200%203.656-5.708c2.123-5.688.912-12.341-3.662-16.915L433.952%204.674c-4.574-4.573-11.225-5.783-16.914-3.66a15.9%2015.9%200%200%200-5.709%203.655q0%20.002-.004.005L256.001%20160%20100.677%204.675l-.005-.005a15.9%2015.9%200%200%200-5.707-3.655c-5.69-2.124-12.341-.913-16.915%203.66L4.676%2078.049C.102%2082.623-1.108%2089.275%201.015%2094.963a15.9%2015.9%200%200%200%203.656%205.708l.005.005L160.001%20256%204.676%20411.326l-.004.005a15.9%2015.9%200%200%200-3.657%205.707c-2.124%205.688-.913%2012.341%203.661%2016.915l73.374%2073.373c4.575%204.574%2011.226%205.784%2016.915%203.661a15.9%2015.9%200%200%200%205.708-3.656l.005-.005%20155.324-155.325%20155.324%20155.325.006.004a15.9%2015.9%200%200%200%205.707%203.657c5.689%202.123%2012.342.913%2016.914-3.661l73.373-73.374c4.574-4.574%205.785-11.227%203.662-16.915a15.9%2015.9%200%200%200-3.657-5.707%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dodgeChance: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22646%22%20height%3D%22640%22%20viewBox%3D%220%200%20646%20640%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M570.938%20621.746c-134.549%2054.949-330.256-18.254-364.881-168.986-12.984%204.516-26.157%208.28-38.765%2013.549-8.28%203.576-12.984%201.694-18.254-4.892-21.641-26.721-43.658-53.255-65.675-80.164%209.786-12.42%2018.065-23.334%2025.216-32.555%2030.485%208.468%2059.653%2016.748%2088.821%2024.652%209.033%202.446%2018.442%203.952%2027.663%205.081%205.457%200.752%207.527%202.822%209.032%208.468%203.199%2012.42%208.092%2024.652%2012.608%2037.636%208.844-4.893%2015.807-8.468%2020.7-11.291-3.952-17.877-7.151-34.813-11.479-51.561-0.564-2.446-5.834-4.704-9.221-5.457-25.028-5.457-50.621-9.409-75.272-15.807-37.636-9.786-73.578-23.146-101.806-51.749-10.35-10.538-18.254-22.582-20.888-39.518%2064.922%2031.426%20130.597%2055.137%20202.67%2060.782%200.564-4.328%200.941-8.092%201.318-12.044%200.564-3.952%200.941-8.092%201.506-12.232-18.065-3.011-35.566-5.269-53.067-8.844-41.588-8.28-82.046-21.452-119.494-41.211-26.345-13.926-45.916-36.507-59.089-63.981-1.129-2.258-1.317-5.081-2.634-9.597%2074.331%2045.916%20152.238%2074.331%20238.612%2081.67%201.129-8.656%202.070-16.372%203.011-24.275-20.888-3.576-41.588-6.21-62.099-10.538-44.599-9.409-87.88-24.087-127.209-47.045-29.921-17.501-53.443-42.341-63.605-77.154-0.376-1.506-0.564-3.011-0.941-5.834%2082.046%2054.761%20170.868%2088.256%20267.592%20105.569%201.506-8.28%203.199-15.995%204.704-24.463-19.194-4.328-37.824-8.092-56.266-12.796-70.379-18.442-137.183-45.727-197.401-86.939-15.054-10.35-25.028-24.652-26.345-43.657-0.188-1.882%200.376-3.576%200.564-6.398%20106.51%2065.675%20226.381%2090.514%20346.251%20121.564-28.415%2044.411-44.222%2092.584-47.233%20144.711-3.011%2051.749%204.704%20102.182%2016.748%20152.99%207.527-1.506%2014.114-2.822%2020.888-4.328%201.129-0.188%202.258-1.129%202.822-1.506-4.328-25.404-9.409-50.244-12.608-75.272-6.774-54.196-3.952-107.827%2017.877-158.824%206.962-15.995%2016.184-31.050%2024.84-46.104%205.269-9.221%2012.044-17.501%2019.006-27.474-14.302-3.764-27.851-7.151-42.152-10.914%206.21-7.528%2012.42-14.114%2017.501-21.452%2017.501-24.84%2034.625-49.867%2052.126-74.707%202.258-3.199%206.774-7.151%2010.35-7.151%2071.508-0.941%20143.017-1.318%20214.525-1.694%201.129%200%202.446%200.376%204.516%200.752%200%205.081%200%2010.162%200%2015.054%200%2038.577-0.188%2077.154%200.188%20115.731%200%206.963-2.070%2010.162-8.656%2012.796-92.584%2037.259-171.056%2093.714-234.096%20171.432-20.512%2025.404-20.512%2025.404-10.35%2056.454%2023.522%2072.261%2057.207%20138.877%20109.332%20195.143%2019.571%2021.076%2041.964%2039.141%2068.498%2054.384z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-logo-apeegg: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22777%22%20height%3D%22448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M305.249%20120.181C273.934%2053.884%20221.742%200%20169.834%200%20117.079%200%2064.323%2058.398%2033.008%20126.106%209.028%20178.861%200%20237.259%200%20278.167c0%2093.944%2076.171%20169.834%20169.834%20169.834s169.834-76.171%20169.834-169.834c0-41.753-9.31-104.383-34.418-157.985zM132.877%20390.166c-37.521.847-37.521-27.647-37.521-27.647%202.257-24.544%2020.03-19.184%2043.164-20.03s42.035%2016.927%2043.164%2026.801c.847%209.874-11.284%2020.03-48.806%2020.877zm115.949-180.272c0%2018.337%2014.952%2027.93%2018.056%2036.957%203.103%209.31%206.489%2027.083-2.821%2030.751-13.824%205.078-26.237-4.514-44.574-16.081s-7.617%2010.721-7.617%2010.721%2017.773%2028.493%2017.773%2055.295-21.441%2018.337-21.441%2018.337-30.468-25.108-69.683-25.108c-39.214%200-40.343%209.028-54.73%209.874-14.67.847-15.234-3.95-15.234-17.773s7.617-22.851%2018.056-34.7c7.335-8.181%206.489-23.134-5.925-16.927s-37.521%2015.234-38.368%200%2022.287-35.265%2022.287-49.934-32.161-29.904-33.854-41.471C29.34%20158.268%2047.678%2094.51%2081.532%2093.664c33.008-.847%2010.438%2028.493%2063.194%2029.904h6.771c7.899-.282%2021.723-.564%2043.728-20.594%2027.647-25.39%2052.192-20.03%2062.912-11.567s32.161%2020.03%2032.161%2057.552c0%2037.804-41.471%2042.317-41.471%2060.937z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M116.232%20208.201c-12.695%201.975-29.058-9.028-34.418-12.977-.847-.564-1.975-.282-2.257.847-6.489%2024.544%206.206%2023.98%2012.413%2025.955%206.489%201.975%202.539%206.489-.282%208.181-3.385%201.693-15.799-1.128-15.799-1.128.564%207.335%2014.388%205.078%2020.03%204.796%201.41%200%202.821-.564%203.95-1.693%206.489-5.642%2029.622-25.955%2016.363-23.98zm69.4%205.643c-11.849-.282%205.078%2014.67%2013.542%2021.723%203.103%202.539%206.771%204.232%2010.721%204.796%206.489.847%2015.799.847%2016.081-5.642%200%200-13.259%203.103-15.799%201.128s-7.053-6.206-.282-8.181c6.489-1.975%2030.186-1.411%2022.569-27.93-.282%200-30.186%2014.388-46.831%2014.106zm-10.72%2020.312c-6.206%200-34.418%2028.212-34.983%2033.008-.282%204.514-7.053-31.033-26.237-30.186-19.184.564-12.977%2013.259-11.003%2019.184s16.645%2017.491%2021.159%2017.773c0%200-13.824-13.541-13.824-18.902s1.41-7.053%205.36-7.053%209.31%203.103%2012.695%2010.72c2.539%205.925%206.206%2013.824%207.617%2017.491.564%201.128%201.411%201.693%202.821%201.693.847%200%201.975-.564%202.257-1.128%203.95-5.642%2021.441-28.776%2031.879-28.776%2011.849%200%207.053%2012.413%203.95%2014.952-3.103%202.821-9.874%207.617-20.03%209.592%200%200%2013.824%203.95%2029.622-11.567%2015.799-14.952-3.385-26.801-11.284-26.801zm309.199-77.3H451.95l-14.388%2043.446h-42.599l48.524-165.038h49.652l48.242%20165.038h-42.317zM601.189%2035.265c7.053%200%2013.542%201.128%2019.184%203.668s10.72%206.206%2014.67%2010.721c3.95%204.796%207.335%2010.156%209.31%2016.927q3.385%209.734%203.385%2022.005c0%207.899-1.128%2015.234-3.385%2021.723s-5.36%2012.131-9.31%2016.927-9.028%208.463-14.67%2011.003-12.131%203.95-19.184%203.95h-12.413v58.116h-37.803V35.267h50.217zm160.806%2037.239h-63.758v26.801h46.831v37.239h-46.831v26.519h63.758v37.239H660.998V35.264h100.997zM502.73%20279.013h-64.04v26.519h47.114v37.239h-47.113v26.519h64.04v37.239H401.452V241.773h101.279zm134.005%2097.048c-2.821%203.95-6.206%207.899-10.156%2011.567s-8.181%207.053-12.977%209.874-10.156%205.078-15.799%206.771-11.849%202.539-18.056%202.539h-.282c-9.874%200-18.62-1.693-26.237-4.796-7.617-3.385-13.824-7.899-18.902-13.541s-9.028-12.695-11.849-20.594-4.232-16.645-4.796-26.237v-34.136c0-8.746%201.41-17.209%203.95-25.39%202.539-7.899%206.489-14.952%2011.849-20.877%205.078-5.925%2011.567-10.721%2019.184-14.388s16.645-5.36%2026.519-5.36h.282q15.234.846%2024.544%205.078c6.206%203.103%2011.284%206.489%2014.952%2010.438s6.489%207.899%208.463%2011.849q2.963%205.925%205.078%209.31l-30.468%2020.312c-.847-1.693-1.693-3.385-2.539-5.642s-2.257-3.95-3.95-5.642-3.95-3.385-6.206-4.514c-2.539-1.128-5.642-1.975-9.592-1.975-7.335%200-13.259%202.539-17.491%207.335-4.232%205.078-6.489%2011.567-6.489%2019.748v32.161c0%203.95.564%207.617%201.975%2011.284%201.411%203.385%203.103%206.489%205.36%208.746%202.257%202.539%205.078%204.514%208.181%205.925s6.489%202.257%2010.156%202.257c5.078.282%209.31-.847%2012.413-2.539%203.103-1.975%205.642-4.232%207.335-7.335v-8.181h-17.491v-31.879h53.32v57.834zm140.212%200c-2.821%203.95-6.206%207.899-10.156%2011.567s-8.181%207.053-12.977%209.874-10.156%205.078-15.799%206.771-11.849%202.539-18.056%202.539h-.564c-9.874%200-18.62-1.693-26.237-4.796-7.617-3.385-13.824-7.899-18.902-13.541s-9.028-12.695-11.849-20.594-4.232-16.645-4.514-26.237v-34.136c0-8.746%201.41-17.209%203.95-25.39%202.539-7.899%206.489-14.952%2011.849-20.877%205.078-5.925%2011.567-10.721%2019.184-14.388s16.645-5.36%2026.519-5.36h.282q15.234.846%2024.544%205.078c6.206%203.103%2011.284%206.489%2014.952%2010.438s6.489%207.899%208.463%2011.849q2.963%205.925%205.078%209.31l-30.468%2020.312c-.847-1.693-1.693-3.385-2.539-5.642s-2.257-3.95-3.95-5.642-3.95-3.385-6.206-4.514c-2.539-1.128-5.642-1.975-9.592-1.975-7.335%200-13.259%202.539-17.491%207.335-4.232%205.078-6.489%2011.567-6.489%2019.748v32.161c0%203.95.564%207.617%201.975%2011.284%201.41%203.385%203.103%206.489%205.36%208.746%202.257%202.539%205.078%204.514%208.181%205.925s6.489%202.257%2010.156%202.257c5.078.282%209.31-.847%2012.413-2.539%203.103-1.975%205.642-4.232%207.335-7.335v-8.181h-17.491v-31.879h53.32v57.834z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dark: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22448%22%20height%3D%22448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M355.656%20325.63c-9%201.5-18.25%202.25-27.5%202.25-92.75%200-168-75.25-168-168%200-31.75%209.25-62.75%2026-89.25-66.5%2019.75-114%2080.75-114%20153.25%200%2088.25%2071.75%20160%20160%20160%2048.25%200%2093.5-22%20123.5-58.25m50.75-21.249c-31.25%2067.75-99.75%20111.5-174.25%20111.5-105.75%200-192-86.25-192-192%200-103.75%2081.25-188%20184.75-191.75%207-.25%2012.75%203.75%2015.25%209.75%202.75%206.25%201%2013.5-3.75%2018-28.5%2026-44.25%2061.5-44.25%20100%200%2075%2061%20136%20136%20136q29.625%200%2057-12.75c6.25-2.75%2013.25-1.5%2018%203.25s6%2012%203.25%2018%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-bite: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20342.4%20336%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M299.7%2C15.2c5.4%2C6.2%2C15.6%2C23.8%2C19.8%2C31.7%2C18%2C33.6%2C24.8%2C69.9%2C22.5%2C108-1.4.1-1.6-2.4-2-3.5-3.2-9.5-5.6-19.4-9.2-28.8-8.3-21.3-20.5-41.5-35.5-58.8-3.5-2.1-10.4%2C0-12.1-1.1s-4-7.4-5.3-9.2c-5.9-7.9-13.2-15.6-22.8-18.7%2C23.6%2C37.5%2C19.7%2C86.5%2C17%2C129-2.8.5-1.6-.7-2.2-2.2-7.9-19.8-13.2-42.6-21-63-3.9-10.3-8.2-21.2-13.4-30.7-2.6-.7-11.5%2C7.7-13.9%2C9.9-68.6%2C62.5-68.6%2C129.7.5%2C191.5%2C3.8%2C3.4%2C15%2C13.4%2C19.5%2C13.6l41.5-88.1c-3.7%2C37.3-5.6%2C75.5-18.5%2C111l-9.5%2C18c4.7-2.8%2C9.3-6.4%2C13-10.5%2C3.3-3.8%2C12.9-21.3%2C14-22%2C3.5-2.1%2C10.5%2C3.3%2C14.9-2.1%2C1.8-2.2%2C5.8-11.4%2C7.3-14.7%2C10.7-23%2C16.7-47.3%2C24.8-71.2.4-1.1.6-3.6%2C2-3.5.5%2C30.1.4%2C59.5-5.5%2C89-5.7%2C28.5-8.1%2C41.9-40%2C46-66.1%2C8.4-152.1-29.7-205.8-66.2-9.8-6.6-37-25-41.9-34.1-15.3-29%2C7.3-82-8.8-102.2s-19.2-6-29-6C2.8%2C91.4%2C17.6%2C55.7%2C47.7%2C36.1c27-17.5%2C61-23.8%2C90.7-9.2%2C34.9-15.6%2C132.4-44.9%2C161.3-11.7ZM60%2C65.9h20.5c6.6%2C0%2C23.1-5.5%2C29.2-8.8s17.4-12.8%2C19.2-17.8-.4-1.2-1.2-1.6c-16.6-9.5-39.8-5.7-56.5%2C1.5-1.9%2C9.7-6.8%2C18.2-11.2%2C26.8ZM204%2C75.9c-38.6%2C10.1-100.6%2C38-108.8%2C81.7s-.8%2C16.7-.2%2C25.3l-4.7-9.8c-5.3-18.3-2.5-33.6%2C4.5-50.9.9-2.3%2C6.2-10.7%2C5.1-12.2l-11.9-5.1c-8.9%2C18-15.7%2C35.8-14%2C56.5%2C4.7%2C57.3%2C81.2%2C92.2%2C128.5%2C108.5l-22.3-26.7c-27.6-38.7-32.3-79.7-9.7-122.3%2C8.8-16.7%2C21.1-31%2C33.5-45Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-block: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20782%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M.3%2C89h100.3c58.9.2%2C116.8-7.4%2C171.3-30%2C36.9-15.3%2C71.9-35.6%2C107.2-54.5%2C8.2-4.4%2C13.3-6.9%2C22.3-.8%2C86.3%2C58.9%2C182.1%2C86.8%2C286.6%2C85.3%2C30.4-.4%2C60.9%2C0%2C93.2%2C0v21.9c0%2C118.9-1.6%2C238%2C.4%2C356.9%2C1.9%2C112.7-32%2C212.8-97.1%2C303.3-75.7%2C105.3-174%2C185.3-284.9%2C250.8-4.3%2C2.5-12.5%2C3.1-16.6.7-127.3-75.6-238.2-168.6-315.8-297.2C21.3%2C649.1%2C1.2%2C565.8.5%2C477.7c-.9-121.8-.2-243.6-.2-365.4v-23.3H.3Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-bowshot: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20345.7%20347%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M227.7%2C24l-6.6%2C14.1-139.8%2C5.9-4.4%2C25.3%2C149.9%2C143.2%2C94.7%2C20.8%2C24.2%2C113.8-112.6-24.9-21.6-94.4L69%2C76l-22.6%2C3.2-1.5%2C1.5-7.1%2C140.6-14%2C6.7%2C8-159.5L1.7%2C31l32%2C2L30.7%2C0l39.5%2C31%2C157.5-6.9ZM295.7%2C241l-70-15%2C15%2C70%2C19-34.5c11.4-7.8%2C24.9-12.5%2C36-20.5ZM311.7%2C249l-40.9%2C21.6-22.1%2C41.4%2C80%2C17-17-80Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M213.7%2C298c-21.8%2C3.3-43.9-.8-65-6.5-24.9-6.7-72.5-29.3-96-23-24.8%2C6.5-33.3%2C28.7-15.5%2C48.6%2C10.6%2C11.8%2C19.1%2C10.3%2C32.8%2C6.8s2.6-1.8%2C1.7.7c-8.6%2C24.5-40.3%2C22-56%2C5s-21.7-61.3%2C3-82c37.3-31.4%2C74.5-3.8%2C112.5%2C8.5s49.8%2C12.6%2C73%2C2l9.5%2C39.9Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M322.7%2C72c6.7-16%2C2-30.1-13-38.5-16.9-9.5-30.5-5.2-38.9%2C12.1-12.4%2C25.4%2C7.6%2C63.8%2C15.6%2C89.2%2C8.2%2C26.3%2C14.6%2C51.2%2C12.3%2C79.2l-41-8c17.7-42.6-7.1-81.4-20-120.5-6.1-18.5-9.4-31.3-.8-49.9%2C16-34.8%2C52.6-45.2%2C85-24.3%2C23.4%2C15.1%2C30.3%2C48.7.9%2C60.6Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-demoShout: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20340.3%20332.2%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M161.2.5c68-7.7%2C98.3%2C79.9%2C98.3%2C134.2%2C0%2C55.5-34.5%2C152.4-106.6%2C132.5-54.9-15.1-74.3-96-71.5-145.5C83.9%2C77.8%2C110.4%2C6.3%2C161.2.5ZM159%2C110.6c-15.6-14.8-39.7-15.8-57.7-4.8l5.1%2C12.4c16.2-10%2C35.3-8%2C47.6%2C6.9l10.3-8.4c-2.3-1.4-3.7-4.6-5.3-6.1ZM234.4%2C118.2l4.6-12c-20.4-12.7-47.9-8.8-62.5%2C10.5l9.5%2C9.5c12.8-16.3%2C30.9-17%2C48.5-8ZM165.2%2C147.5c-44.7%2C4.2-66.7%2C57.4-37.3%2C91.7%2C27.8%2C32.6%2C82%2C21.8%2C95-19%2C12.1-37.9-18.1-76.4-57.7-72.7Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M207.4%2C332.2l32.5-23c59.2-53.9%2C86.3-138.3%2C75.4-217.3l-4.3-22.7c67.9%2C97.7%2C12.1%2C238.2-103.5%2C263Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M133.4%2C331.2c-1.1%2C2.3-6.8-.2-8.8-.8C13.6%2C299.6-35.9%2C165.8%2C28.9%2C70.2l-6.5%2C44.5c-2.5%2C83.5%2C34.7%2C176.2%2C111%2C216.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M143.4%2C288.2c.2%2C1.8-2.2%2C1-3.3.8-9.3-1.8-23.4-8.5-31.7-13.4-61.2-36.4-79.7-118.2-39.6-177.4l-4.5%2C26.5c-4.2%2C62.5%2C22.5%2C132.4%2C79%2C163.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M195.4%2C290.2c7.1-5.5%2C15.2-9.6%2C22-15.5%2C40.5-34.7%2C60.9-91.2%2C59-144l-4.5-31.5c48.7%2C71.8%2C7.4%2C172.5-76.5%2C191Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-fillArmor: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20299.2%20339.9%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M113.1%2C13v35h75V13h21v37h34l-3.9%2C45.4%2C1.6%2C1.4%2C34.3%2C7.2-8%2C30-29.3-3.8-37.6%2C77.4%2C23%2C20.1-16.6%2C24.3-29.9-20.9-27%2C29-25.5-30h-1.4c-8.9%2C5.2-19.3%2C16.7-28%2C21.1-1%2C.5-2.3%2C1.5-3.5.8l-15-24.3%2C22.8-20.9-37.5-76.5-29.3%2C3.8-8.1-30%2C34.3-7.2%2C1.6-1.4-3.9-45.4h36V13h21ZM223.1%2C66H76.1c-4.3%2C65.6%2C27.8%2C125.5%2C73.5%2C170%2C45.9-44.2%2C77.9-104.5%2C73.5-170Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M119.8%2C249.1c1.2-.3%2C2%2C0%2C2.9.8l26.9%2C30.1%2C29-30.7%2C30.5%2C22.3c-17.9%2C24.2-37.6%2C46.9-58.6%2C68.4-23-20-41.9-44.2-60.3-68.4l29.6-22.4Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M79.1%2C36h-36l2%2C50-36%2C7.6C1.4%2C63.1-.5%2C31.4.1%2C0h77.5l1.5%2C1.5v34.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M299.1%2C0c.6%2C31.4-1.7%2C63-9%2C93.6l-36-7.6c2.5-16.5%2C2-33.3%2C2-50h-33V0h76Z%22%20%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23000%22%20points%3D%22284.1%20150%20245.6%20230%20217.1%20204.4%20245.1%20144%20284.1%20150%22%20%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23000%22%20points%3D%2252.1%20230%2015.1%20150%2054.2%20144.4%2081.7%20202%2081.7%20205%2052.1%20230%22%20%2F%3E%0A%20%20%3Crect%20fill%3D%22%23000%22%20x%3D%22127.1%22%20y%3D%221%22%20width%3D%2247%22%20height%3D%2234%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M210.1%2C80c-1.3%2C51.4-24.9%2C99.8-60.5%2C136-35.7-36.4-59-84.3-60.5-136h121Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-cheese: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20342%20293.1%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23f7d857%22%0A%20%20%20%20d%3D%22M342%2C55.1v148.5l-111.4%2C29.4c-1.4-.4-3.2-7.5-4.4-9.6-25-45.4-104.8-20.2-86.2%2C33.7L.5%2C293.1l-.5-10c11.9-.9%2C23.5-8.5%2C30.9-17.6%2C22.4-27.5%2C3.8-60.2-31-52.5v-70l49-12c-1%2C14.6%2C10.7%2C26.4%2C24.6%2C28.9%2C27.2%2C4.9%2C58.9-19.9%2C51.4-48.9l217-56ZM268.8%2C150.4c-38.2%2C5.6-24.6%2C61.5%2C15%2C49%2C31.2-9.8%2C19.7-54.1-15-49Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23ccb34c%22%0A%20%20%20%20d%3D%22M330%2C44.1l-213%2C54.5c-22.3-19.5-53.3-4.1-66.7%2C18.3L1%2C129.1%2C89%2C54.6c12.6%2C7.4%2C24.5%2C10.1%2C39.1%2C7.1%2C28.1-5.7%2C45.8-35.7%2C18-55.1%2C0-.4%2C6-5.1%2C6.7-5.3%2C2.1-.6%2C16.2-1.2%2C19.7-1.3%2C45.9-.9%2C109.3%2C9.2%2C147.7%2C35.4%2C1.2.8%2C10.6%2C7.6%2C9.9%2C8.6Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23ccb34c%22%0A%20%20%20%20d%3D%22M66.3%2C141.8c-10.1-10.1-.4-26.2%2C9.3-32.5%2C22.8-14.9%2C50.2%2C2%2C30.8%2C25.8s-29.4%2C17.5-40.1%2C6.7Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23ccb34c%22%0A%20%20%20%20d%3D%22M215%2C231.1c-22.8-3-46.2-.6-62.5%2C17-3.7-5.8-.9-15.3%2C3.1-20.9%2C14.3-19.9%2C47.7-17.7%2C59.4%2C3.9Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23ccb34c%22%0A%20%20%20%20d%3D%22M268.7%2C164.3c6.6-1.4%2C17.9.3%2C19.2%2C8.3%2C2.9%2C18.1-27.1%2C19.2-28.8%2C3.7s4.6-11%2C9.6-12Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-lacerate: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20345.8%20350.3%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M0%2C257v-39c72.4-20.1%2C148.1-42.5%2C213.7-79.8%2C34.2-19.5%2C77.3-48.7%2C81.8-91.2%2C19.6-11.8%2C35.7-27.7%2C48-47%2C6.9%2C38.2-1.8%2C77.3-24.3%2C108.7-16.7%2C23.3-31.1%2C32.9-42%2C62s-13.7%2C41.6-13.3%2C51.7c.8%2C23.6%2C28.3%2C50.9%2C30.9%2C76.1%2C5%2C47.2-65.8%2C47.5-64.9%2C5.9.5-23.2%2C22.8-49.9%2C28.6-73.5%2C2-8%2C2.6-10-1.7-17.3-20.6-35.6-93.8-24.1-92.9%2C19.8s18.2%2C20.1%2C6.6%2C34.6c-6.8%2C8.5-19.2%2C9.6-27%2C2-14.9-14.5%2C13.8-28.7%2C2-42-9.9-11.2-37.1-2.2-48.6%2C3.5-18.5%2C9.3-44.6%2C33.2-45.8%2C55.3-.8%2C14.9%2C17%2C33.1%2C16.8%2C48.7s-22%2C20.1-31.4%2C8.4%2C12.5-38%2C13.4-54.6-6.4-25.1-13-30.8c-12-10.2-23.7-5.6-36.9-1.6Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M0%2C204v-51.5c7.9-3.7%2C17.4-4.6%2C26-7%2C43-12.1%2C88.8-31.7%2C128-53s31-20.3%2C36.9-22.1%2C15.5.8%2C20.6.6c6.6-.2%2C15-1.4%2C21.7-2.3%2C16.2-2.4%2C31.6-7.4%2C46.8-13.2-12.4%2C36.4-53.5%2C60.9-86%2C78C133.2%2C165.6%2C66%2C185.5%2C0%2C204Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M320%2C130l5.5%2C18c5.1%2C14.4%2C24.6%2C38.8%2C11%2C53s-36.7%2C6.1-37.6-12.5c-.9-19.8%2C19.8-38.1%2C21.1-58.5Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-kick: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20772.8%20803.3%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M432.2%2C727.4c-59.6%2C7.8-125.8%2C5.3-176.6-30.6-47.1-33.3-69.8-89.1-113.3-126.3-19.4-16.6-40.7-23.8-62.2-36-22.8-12.9-65.3-42.1-75.9-65.9-17.4-38.9%2C23.4-82.3%2C50.2-106.3%2C22.6-20.2%2C49.3-35%2C75.4-49.9%2C14%2C15.8%2C21.4%2C37.9%2C26.7%2C58.1%2C2%2C7.8%2C6.6%2C38.2%2C10%2C42.2%2C3.9%2C4.6%2C6.4%2C4.4%2C11.7%2C4.8%2C18.9%2C1.5%2C40.3-.3%2C60%2C.8%2C26.2%2C1.4%2C52.5%2C3.9%2C78.1%2C10%2C0%2C10.4%2C0%2C21%2C3.4%2C30.9%2C5.6%2C15.9%2C14.1%2C32.4%2C20%2C48.8%2C14.5%2C39.8%2C24.4%2C105.3%2C64.9%2C125.2s53.7%2C12.1%2C86.9%2C11.3c50-1.2%2C27.3%2C43%2C2.7%2C61.6-17.2%2C13-41%2C18.3-61.9%2C21.1Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M140.2%2C306c27.5-18.2%2C49.8-43.1%2C69.4-69.6%2C47.1-72.8%2C91-147.8%2C138.6-220.3%2C2.4-3.6%2C8.6-14.1%2C11.6-15.7s3.9-.6%2C5-.3l197.2%2C152.5c5.8%2C4.8%2C3.9%2C9.3-.4%2C14.3-15.1%2C17.6-36.6%2C35.6-53.3%2C52.4-37.3%2C37.5-73.9%2C75.8-111.3%2C113.2-19.3%2C19.3-44.4%2C39.6-61.7%2C59.9-6.3%2C7.4-9.7%2C15.5-14.1%2C23.9-34-7.4-68.7-10.6-103.4-11.9s-37.6.7-39.3-.4c-2.6-1.6-2.1-8-2.8-11.1-6.6-30.6-14.7-62.8-35.4-87.2Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M543.9%2C524.4l141.5-104.1c3.1.2%2C3.1%2C3.7%2C2%2C6l-100.5%2C156%2C175.7-28.9c4.2-.8%2C7.6%2C3.5%2C3.3%2C6.4l-143.9%2C85%2C150.9%2C76.1-.8%2C2.9-155-8.5%2C50%2C85.5c-2.5%2C7-10.6-3.5-13.5-6.5-16.3-17-31.9-34.8-48-52-13.3-14.3-28.5-27.2-39.4-43.7l.3-2.3%2C45.6-10-52.4-28.1c-1-.5-1.7-1.2-1.7-2.4%2C0-3.5%2C45.9-33.9%2C51.1-39.5l-64.5%2C3c-1.2%2C0-2-.5-2.4-1.6-1.7-5%2C31.1-67.2%2C33.9-77.3-2.2-2.1-46.6%2C32.6-52.5%2C32.1s-2.3-1.6-2.8-3.2c-2.9-9.3-2.7-22.4-5.6-32.4-.4-1.5.6-1.7-2-1.5l-18.6%2C43c-1.4.2-3-2-3.8-3-7.1-9.3-11.1-21.9-18.6-30.9l-8.2%2C50.3c-.9%2C2.6-5.4%2C1.6-7.8%2C1.6l-36.1-198.5h3s69%2C115.5%2C69%2C115.5l55-169.5c.7-2%2C2.5-4.7%2C4.6-2.5l-7.6%2C183.1Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-punch: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22705%22%20height%3D%221024%22%20viewBox%3D%220%200%20705%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M379.019%201023.979c-43.565%200-87.131%200.106-130.696-0.106-6.652-0.021-13.622-0.489-19.87-2.508-14.047-4.548-20.72-16.3-20.805-34.491-0.298-71.894-0.744-143.787-0.723-215.702%200-26.777-7.629-50.727-22.782-72.659-57.358-82.966-114.609-166.037-171.818-249.13-16.427-23.844-16.364-42.248-0.234-66.581%2040.696-61.353%2081.393-122.706%20122.111-184.037%2015.556-23.419%2032.387-29.093%2059.249-19.806%2067.155%2023.228%20134.373%2046.264%20201.336%2070.023%2011.476%204.080%2022.484%2010.349%2032.6%2017.214%2012.623%208.564%2018.085%2021.676%2016.449%2036.956-2.083%2019.615-9.669%2036.935-24.29%2050.536-14.663%2013.643-33.003%2015.981-50.77%2010.626-35.15-10.541-70.278-21.74-104.217-35.617-34.47-14.090-54.149%206.12-62.203%2035.15-3.634%2013.070%204.42%2026.394%2018.85%2033.301%2022.016%2010.519%2044.245%2020.571%2066.368%2030.878%2026.479%2012.347%2045.351%2031.24%2055.53%2059.44%2018.744%2051.853%2038.784%20103.261%2058.271%20154.859%200.871%202.316%201.573%204.718%202.656%206.928%204.314%208.819%2012.857%2012.56%2021.081%209.351%207.906-3.081%2010.966-10.562%207.672-20.486-9.946-29.858-20.125-59.61-30.22-89.426-4.76-14.068-9.669-28.073-14.217-42.227-2.423-7.544-7.927-17.256%200.51-22.186%204.888-2.848%2014.982%200.043%2021.251%203.251%2037.785%2019.339%2075.166%2039.464%20112.633%2059.398%2027.202%2014.472%2044.713%2011.922%2066.708-9.903%2013.325-13.218%2026.543-26.564%2040.038-39.613%205.44-5.249%2011.773-14.408%2019.169-9.096%204.888%203.528%206.652%2014.153%206.482%2021.506-1.488%2063.584-19.466%20122.727-51.195%20177.534-10.009%2017.299-22.484%2033.258-34.619%2049.261-11.731%2015.471-18.85%2032.153-18.829%2051.79%200.106%2065.178%200.106%20130.335%200.043%20195.513-0.021%2028.732-11.157%2039.953-39.783%2040.016-43.905%200.128-87.832%200.043-131.738%200.043z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M460.518%20455.843c-26.224-0.128-49.346-23.632-44.437-45.627%201.19-5.355%203.889-10.647%206.949-15.28%2036.51-55.169%2073.147-110.231%20109.912-165.23%2014.047-21.018%2030.623-23.313%2049.75-7.183%209.733%208.203%2019.573%2016.364%2028.881%2025.034%2014.961%2013.941%2016.321%2032.6%203.124%2048.326-40.951%2048.793-82.201%2097.353-123.343%20145.976-8.054%209.521-18.404%2014.090-30.836%2013.983z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M298.731%20174.75c-3.634-1.041-9.521-2.231-15.046-4.378-23.355-9.074-46.647-18.319-69.875-27.712-21.464-8.692-26.118-23.653-13.197-42.822%2018.574-27.542%2037.275-54.999%2056.125-82.349%2013.048-18.935%2030.772-22.59%2050.493-10.498%2021.974%2013.473%2043.905%2027.074%2065.709%2040.866%2018.191%2011.518%2021.719%2028.668%209.287%2046.137-14.961%2021.018-30.347%2041.738-45.542%2062.585-8.819%2012.071-21.145%2017.129-37.955%2018.17z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M552.537%20516.665c-20.401-1.233-32.961-8.373-40.378-22.654-7.098-13.686-4.080-26.586%205.292-38.508%2033.662-42.8%2067.133-85.771%20100.817-128.55%2014.323-18.191%2030.793-18.85%2046.413-2.083%2010.371%2011.114%2020.805%2022.186%2030.815%2033.641%2013.261%2015.174%2012.347%2032.812-2.805%2045.882-39.613%2034.215-79.332%2068.323-119.518%20101.858-6.673%205.568-15.917%208.097-20.635%2010.413z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M463.026%20240.672c-1.934-0.298-4.888-0.255-7.459-1.211-25.459-9.457-51.088-18.51-76.165-28.881-12.942-5.334-16.406-18.446-8.416-29.986%2018.085-26.139%2036.616-51.981%2055.615-77.483%209.287-12.475%2025.289-15.577%2039.039-7.863%2022.165%2012.453%2044.075%2025.353%2065.667%2038.763%2014.132%208.777%2016.661%2023.122%206.8%2036.467-13.856%2018.765-28.179%2037.169-42.545%2055.53-7.969%2010.179-19.020%2014.217-32.536%2014.663z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-shieldBash: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20671.6%20567.1%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M541.6%2C0l-24%2C172c32.4-11.8%2C64.8-23.9%2C97.5-35s26.3-9.5%2C39-13c2.5-.7%2C10.6-4.1%2C10.6.5l-114%2C124%2C121%2C45c-10.5%2C7.3-24.3%2C11.2-36.5%2C15.5-32.9%2C11.7-66.3%2C22.2-99.5%2C33l83.2%2C133.3c1%2C3.3%2C6%2C7.8%2C2.3%2C10.7l-148.5-76c-1.1%2C10.5-.5%2C21-1%2C31.5-1.6%2C36.9-2.3%2C74-4%2C111s-.6%2C9.6-1%2C13-4.9-.4-5.8-2.2l-70.2-123.3c-1.3-.9-5.4%2C3.9-6.5%2C5-9.8%2C10.2-18.3%2C21.8-28%2C32s-12.7%2C13.9-14.5%2C12v-2.4c0%2C0%2C43.2-110.8%2C43.2-110.8l3.3-3.7%2C43%2C62%2C9.1-78.9%2C81.4%2C35-41-69.5c0-2.4%2C2.9-3.5%2C4.7-4.3%2C13.9-5.9%2C34-10.1%2C49.1-14.9%2C7.1-2.3%2C14.5-4.4%2C21.2-7.8l-64.1-25.1c-.6-3%2C6-11%2C8.1-13.8%2C9.3-12.3%2C21-24.1%2C30.9-36.1.8-1%2C6.8-7.8%2C6-8.5-7.9-.1-54.7%2C20.1-58.1%2C17.6s-1-2.7-1-4c1-21.6%2C5.1-45.2%2C7-67.1%2C0-1%2C0-2%2C0-3l-2-.5-43.5%2C55-19-37-25.4%2C48.3-4.1.7c3.7-28%2C10.7-55.6%2C14.8-83.7%2C2.9-20%2C4.6-40.2%2C7.2-60.3l34.5%2C67L537.5%2C1.4l4.1-1.4Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M.1%2C109.6h48c28.2%2C0%2C55.9-3.5%2C82-14.4%2C17.7-7.3%2C34.4-17%2C51.3-26.1%2C3.9-2.1%2C6.4-3.3%2C10.7-.4%2C41.3%2C28.2%2C87.2%2C41.6%2C137.3%2C40.8%2C14.6-.2%2C29.2%2C0%2C44.6%2C0v10.5c0%2C56.9-.8%2C114%2C.2%2C170.9.9%2C54-15.3%2C101.9-46.5%2C145.2-36.3%2C50.4-83.3%2C88.7-136.4%2C120.1-2.1%2C1.2-6%2C1.5-7.9.3-61-36.2-114.1-80.7-151.2-142.3C10.2%2C377.9.6%2C338%2C.2%2C295.8c-.4-58.3%2C0-116.7%2C0-175v-11.2H.1Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-slam: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20201.2%20149.8%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M48.2%2C96.3c-1.2%2C4.1-3.3-.1-3.7-.5-2.1-1.7-12.7-11.3-14.3-10%2C2.9%2C4.6%2C10.9%2C18.2%2C4.4%2C21.9-2.6%2C1.4-6.2.4-7.4%2C3.1l36.5%2C13c3.8.6-1.3-5.6-1.5-7%2C1.7-1.3%2C8.2%2C5%2C10.3%2C6.2%2C7.7%2C4.5%2C20%2C12%2C28.7%2C9.4l32-17.5c1.2%2C1-9.7%2C8.3-10.3%2C8.9-1%2C1.1-.8%2C1.6-.7%2C3%2C5.1-1.1%2C19.8-2.7%2C23.1%2C1.5s-10.1%2C7-11.1%2C10.5l24%2C11c.2-3.2-2.3-5.1-2.1-8.5.5-8.8%2C21.4-10.4%2C28.1-11.5l-18.7-4.8c-6.9-3.4-1.5-11.4%2C1.3-16.1%2C9.1-15.8%2C23.5-27.9%2C34.4-42.1-5.2%2C2-8.7%2C6.2-14%2C8.5-3.5%2C1.5-11%2C2.4-12%2C3-2.9%2C1.7-5.7%2C17-14.6%2C17.5-7.7.5-4.3-16.3-3.9-21s1.5-2.4-1.1-2l-8%2C20c-2.1-1.3-.9-2.3-.9-3.8.4-14.2%2C2.1-23.8%2C1.3-38.7-.2-3%2C1.6-17-2.3-16.5l-43.1%2C21.9-7%2C53c-1.7-1.1-1.4-2.7-1.6-4.4-1.1-14.8%2C1.1-30.6-1.4-45.6-7.8-6.1-16.8-10.4-24.8-16.2s-5.6-3.2-5.7-5.8l33.4%2C14%2C49.6-21.5c.3-1.3-4.3-4.4-5.5-5.4-5.3-4.3-11.6-8.9-17.1-12.9s-10.9-8.4-13.9-10.1-6.5-.5-10.3.5l-43.9%2C21.6c-4.4%2C4-2.3%2C21.3-4.8%2C21.8L13.5%2C22.1C.3%2C18.6-2.7%2C35.4%2C2.2%2C44.3c14.1%2C11.5%2C30.8%2C19.9%2C46%2C30l.8%2C1.1c.2.9-.9%2C1.6-.9%2C1.9%2C0%2C4.2.8%2C16.1%2C0%2C19Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M187.7%2C21.8c-1.1-.2-17.3%2C12-17.9%2C13-1.3%2C1.9-4.4%2C16.3-4.3%2C18.7s.3%2C1.5%2C1.3%2C2.2c2.8-2.5%2C8.6-2%2C10.9-5s8.5-21.2%2C10.6-26.4%2C1.5-2.1-.6-2.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M190.2%2C107.8c-5.7.7-11.1%2C1.1-13%2C7.5%2C5.4%2C4.9%2C12-2.2%2C13-7.5Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stab: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20346.5%20348.7%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M39.7%2C26l42.4%2C29.1c11.5-7.2%2C21.9-15.7%2C33.8-22.2s16.2-8.7%2C18.3-8.8%2C1.9.3%2C3%2C1%2C16.9%2C16.4%2C17.4%2C17.6c-10.6%2C5.9-21.4%2C11.6-31.5%2C18.5s-16%2C10.5-15.5%2C12.5l215.7%2C152.8%2C23.2%2C120.8-120.6-23.9L73%2C108.1l-7.9%2C9.1c-7.8%2C11.4-15.4%2C23-20.6%2C35.9-1.5.4-1.7-.4-2.5-1-2-1.4-15.3-14.6-16.6-16.5s-.9-1.1-.5-2.5c.7-2.6%2C5.8-12.6%2C7.4-15.7%2C6.4-12.3%2C15-23.5%2C22.9-34.8l-29.2-41.5c-3.5-3.3-9.1%2C4.7-12.5%2C2.5S2.4%2C26.9%2C1.4%2C24.8C-4.4%2C13.2%2C9.3-1.4%2C21%2C.1c1.4.2%2C21.5%2C12.9%2C22.1%2C14%2C2%2C3.8-4.9%2C9.3-3.4%2C11.8ZM274.5%2C275.1l-19.5-49L94.9%2C84.2c-.9-.2-10.3%2C8.7-10.9%2C9.9s-.7%2C1.2%2C0%2C2l143.3%2C160.8%2C47.2%2C18.3Z%22%20%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23000%22%0A%20%20%20%20points%3D%22241.5%20112.1%20261%20146.1%20275.5%2097.1%20293.5%20153.1%20313.5%2065.1%20319.6%20175.1%20345.5%20148.1%20345.5%20277.1%20334.6%20219.5%20241.5%20152.6%20241.5%20112.1%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M140%2C227.1c.7%2C0%2C4%2C1.2%2C4.6%2C1.7l74.2%2C108%2C59.7%2C10.3c.2%2C1.7-2.3.9-3.5%2C1-25.9%2C1.1-54%2C.4-80.1%2C0s-5.3-1.1-7.9-1.1c-18.5-.3-37%2C.3-55.5%2C0l48-32-91-18%2C71-14-80-19%2C10.5-2%2C62.5-2-39-13c-.2-1.5%2C2.6-1.7%2C3.6-1.9%2C6.6-1%2C13.8-.8%2C20.4-2.1l-18-15.5c-.3-3.1%2C1.1-.5%2C1.5-.5%2C5.8%2C0%2C13.6-.7%2C19%2C0Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-slash: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20356%20364%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M105.1%2C72.9l-26.7-31.9C152.9-11.5%2C254.3%2C4.2%2C311%2C74.5c38.5%2C47.8%2C47.6%2C114.6%2C24.8%2C171.7-1.9%2C4.8-7.8%2C17.7-10.8%2C21.2s-1.3%2C1.9-2%2C1l-84.8-85.8c1.6-3.9%2C3.7-8.2%2C4.8-12.2%2C20-72.2-53.3-139.6-122.6-105.6-2.8%2C1.4-13.5%2C9-15.2%2C8.1Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M39.9%2C16.1l74.8%2C86.8%2C39-37.9%2C13.9%2C12.9-26.5%2C27.5%2C194%2C194%2C17%2C55.5-57.5-15L100.5%2C146l-25%2C25c-2.5-3.8-11.3-9.6-13.1-13s-.5-1.7.5-2.5l38-38L12%2C42.5l24.4-25.5%2C3.4-.8ZM113.3%2C141.7c5.5%2C6%2C12%2C4.7%2C19.2%2C4.3l171%2C171.1%2C9.5-9.5-172-173c1-8.6-1.5-15.8-10-18.9-16.4-6.1-29%2C13.8-17.6%2C26.1Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M187%2C353c-76%2C3.9-147.1-42.7-172-114.5S5.3%2C127.6%2C37%2C81l33.9%2C28.6c-6.6%2C11.1-14%2C21.8-19.1%2C33.7-40.4%2C94.1%2C27.8%2C193.8%2C124.8%2C207.6%2C3.4.5%2C8.6-1.3%2C10.4%2C2.1Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-exposed: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%236c7cd8%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%232b3eaf%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M1024%2C512c0%2C282.6-229.4%2C512-512%2C512S0%2C794.6%2C0%2C512%2C229.4%2C0%2C512%2C0s512%2C229.4%2C512%2C512Z%22%2F%3E%0A%20%20%3Ccircle%20class%3D%22st1%22%20cx%3D%22512%22%20cy%3D%22512%22%20r%3D%22401.7%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-concussed: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23ab31c9%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%236d219e%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M1024%2C512c0%2C282.6-229.4%2C512-512%2C512S0%2C794.6%2C0%2C512%2C229.4%2C0%2C512%2C0s512%2C229.4%2C512%2C512Z%22%2F%3E%0A%20%20%3Ccircle%20class%3D%22st1%22%20cx%3D%22512%22%20cy%3D%22512%22%20r%3D%22401.7%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-wounded: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23f85656%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23e20000%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M1024%2C512c0%2C282.6-229.4%2C512-512%2C512S0%2C794.6%2C0%2C512%2C229.4%2C0%2C512%2C0s512%2C229.4%2C512%2C512Z%22%2F%3E%0A%20%20%3Ccircle%20class%3D%22st1%22%20cx%3D%22512%22%20cy%3D%22512%22%20r%3D%22401.7%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-cog: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14.59%209.535c-0.839-1.454-0.335-3.317%201.127-4.164l-1.572-2.723c-0.449%200.263-0.972%200.414-1.529%200.414-1.68%200-3.042-1.371-3.042-3.062h-3.145c0.004%200.522-0.126%201.051-0.406%201.535-0.839%201.454-2.706%201.948-4.17%201.106l-1.572%202.723c0.453%200.257%200.845%200.634%201.123%201.117%200.838%201.452%200.336%203.311-1.12%204.16l1.572%202.723c0.448-0.261%200.967-0.41%201.522-0.41%201.675%200%203.033%201.362%203.042%203.046h3.145c-0.001-0.517%200.129-1.040%200.406-1.519%200.838-1.452%202.7-1.947%204.163-1.11l1.572-2.723c-0.45-0.257-0.839-0.633-1.116-1.113zM8%2011.24c-1.789%200-3.24-1.45-3.24-3.24s1.45-3.24%203.24-3.24c1.789%200%203.24%201.45%203.24%203.24s-1.45%203.24-3.24%203.24z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-h1h1: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201014%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M791.1%2C642.4l86.1-86%2C77.2%2C77.2-130.2%2C130.1%2C189.7%2C189.7-70.6%2C70.6-189.7-189.7-130.2%2C130.1-77.2-77.2%2C86.5-86.5-95.2-95.2%2C158.3-158.4%2C95.3%2C95.3h0Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M9.1%2C18.1l213.1%2C57.1.4-1.4%2C236.1%2C236.2-158.3%2C158.3L64.2%2C232.1l1.4-.4L8.5%2C18.6s.6-.5.6-.5Z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M222.8%2C624.3L791.4%2C55.7l.4%2C1.4L1005%2C0l.4.4-57%2C213.2%2C1.4.4L381.2%2C782.6l86.5%2C86.5-77.2%2C77.2-130.2-130.2-189.7%2C189.7L0%2C935.2l189.7-189.7-130-130.1%2C77.1-77.2%2C86%2C86.1Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-h1: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201014%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.7.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%208)%20%20--%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M222.8%2C624.3L791.4%2C55.7l.4%2C1.4L1005%2C0l.4.4-57%2C213.2%2C1.4.4L381.2%2C782.6l86.5%2C86.5-77.2%2C77.2-130.2-130.2-189.7%2C189.7L0%2C935.2l189.7-189.7-130-130.1%2C77.1-77.2%2C86%2C86.1Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-h2: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221024%22%20height%3D%221024%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M720.418%20903.097c26.475-11.178%2050.891-21.474%2075.601-31.476-0.294-1.471-0.294-2.942-0.588-4.413-22.063-8.825-44.419-17.062-66.188-26.769-8.237-3.53-16.473-9.119-22.357-15.591-67.070-74.13-133.847-148.555-200.623-222.98-5.001-5.589-10.296-11.473-16.768-18.238-15.297%2030.299-25.004%2060.305-30.888%2091.486-8.237%2045.008-6.472%2088.839%2015.885%20130.022%2022.357%2040.889%2058.54%2063.54%20101.194%2077.366%207.648%202.648%2015.885%204.707%2025.004%207.354-28.534%2037.065-61.187%2067.365-100.606%2090.604-80.896%2047.949-167.676%2052.95-257.103%2031.476-81.485-19.709-154.438-58.54-222.98-105.901-1.471-0.883-2.648-2.648-2.942-2.942%2018.533%201.177%2037.359%204.118%2056.186%203.236%2073.248-3.824%20107.077-64.423%2072.365-128.846-7.060-12.943-15.591-24.71-23.239-36.477%2016.179%203.236%2032.359%208.237%2049.126%209.413%2037.948%202.648%2068.835-11.473%2087.074-45.596%2018.533-34.124%2013.532-67.953-7.648-100.017-1.765-2.942-3.53-5.589-4.707-7.060%2021.18%202.059%2042.949%206.178%2064.717%205.589%2071.483-2.353%2094.428-64.129%2089.133-113.843-0.588-5.001-5.295-10.296-9.119-14.414-33.829-37.948-67.953-75.895-102.076-113.843-2.648-2.942-5.001-5.883-9.708-11.767%2024.122-23.239%2047.655-46.479%2072.66-70.6%2016.768%2015.003%2032.359%2028.828%2047.949%2042.949%2023.828%2021.18%2047.067%2042.949%2071.189%2063.835%206.178%205.295%2015.003%209.119%2022.945%2010.002%2065.011%207.354%20112.961-38.536%20108.548-103.547-1.177-16.473-4.707-32.653-7.354-50.597%2040.007%2027.652%2081.485%2036.183%20120.609%203.236%2041.478-35.006%2037.359-80.602%2020.298-127.081%2016.473%209.708%2031.182%2020.592%2047.655%2027.652%2058.54%2025.593%20109.725-4.118%20116.785-67.659%201.177-11.178%201.471-22.357%200.588-33.535s-3.236-22.063-5.589-35.889c6.766%2010.002%2012.649%2017.944%2018.238%2026.475%2047.067%2072.954%2084.426%20150.32%2098.546%20236.806%2020.003%20122.668-15.297%20226.215-108.842%20309.465-5.589%204.707-11.178%209.413-17.944%2015.591-4.118-12.943-7.060-24.71-11.473-35.889-32.947-84.426-100.017-122.374-190.033-108.548-35.594%205.589-69.424%2016.473-107.666%2035.006%206.472%203.824%2011.473%205.295%2015.003%208.531%2078.837%2070.6%20157.38%20141.495%20235.923%20212.684%205.295%204.707%209.413%2011.178%2012.061%2017.65%209.708%2022.945%2018.827%2046.184%2027.946%2069.424%201.471%200.588%202.942%200.883%204.413%201.471%2011.178-25.887%2022.063-51.774%2033.535-78.249%2038.83%20100.017%2077.366%20199.74%20117.667%20303.582-101.488-41.184-201.505-80.014-302.405-119.138z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M389.479%2068.835c27.063%2027.063%2050.303%2050.597%2074.719%2075.013-130.022%2082.661-235.335%20190.915-318.584%20321.232-24.122-25.298-47.655-49.714-71.777-75.013%201.177-1.177%204.413-5.001%208.237-8.531%2035.3-35.3%2070.306-70.895%20106.195-105.901%208.237-7.943%208.237-13.826%203.53-23.533-38.536-77.66-97.37-135.317-172.677-177.089-6.766-3.824-13.532-7.648-19.121-10.59%2021.474-21.474%2042.654-42.654%2064.129-64.423%2011.473%2018.238%2022.651%2037.948%2035.594%2056.774%2040.007%2058.54%2089.721%20105.901%20154.733%20135.906%208.531%203.824%2013.532%203.236%2020.003-3.53%2035.3-35.889%2071.189-71.483%20106.783-107.371%203.824-3.53%205.883-8.825%208.237-12.943z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-chevron: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22448%22%20height%3D%22448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22m420.75%20202-185.5%20185.25a15.844%2015.844%200%200%201-22.5%200L27.25%20202c-6.25-6.25-6.25-16.5%200-22.75L68.75%20138a15.844%2015.844%200%200%201%2022.5%200L224%20270.75%20356.75%20138a15.844%2015.844%200%200%201%2022.5%200l41.5%2041.25c6.25%206.25%206.25%2016.5%200%2022.75%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-vulnerable: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%20%20%3Cg%20id%3D%22Original_Art%22%20class%3D%22st2%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%236c7cd8%22%20d%3D%22M-513.4%2C868.7c2.8%2C8.9%2C1.2%2C14.2-6.8%2C20.3-83.5%2C62.2-174.7%2C108.5-277.6%2C129.1-8.9%2C1.8-17.9%2C3.1-26.8%2C4.6-29.3-78-31.7-393.8-3.7-495.8%2C71.8%2C9.5%2C138.7%2C33%2C204.6%2C65.3.6-6.2%2C1.5-10.2%2C1.5-14.5%2C0-44.1-.3-88.4.3-132.5.3-11.1-3.7-15.1-14.2-16.9-89-16.8-178.5-27.7-268.9-28.6-18.9-.2-37.8%2C0-56.8.8-68.7%2C2.8-136.8%2C11.7-203.4%2C30.8v161.2c67.2-33.6%2C135.6-58.9%2C210.5-66.2%2C29%2C167.3%2C35.1%2C332.8-2.2%2C498-100.2-5.5-245.6-66.6-341.1-143.3%2C3.4-9.9%2C7.1-20.3%2C10.8-30.8%2C21.6-61.6%2C43.1-123.6%2C54.2-188.6%2C12-71.2%2C5.5-141.1-15.1-209.5-14.5-49-32-97.1-47.5-145.8-1.8-6.2-1.5-16%2C2.2-20.3%2C36.1-41.6%2C72.7-82.6%2C109.4-123%2C2.5-2.8%2C8.3-5.2%2C11.7-4%2C57.6%2C17.6%2C114.9%2C35.7%2C170.7%2C53.6-20%2C22.2-40.4%2C44.7-61.3%2C67.8%2C52.5%2C16.4%2C105.2%2C32.8%2C157.9%2C49.2%2C56.2%2C17.5%2C112.5%2C35%2C168.8%2C52.5.6-1.2%2C1.2-2.1%2C1.8-3.4-56.1-42.8-112.2-85.5-170.6-130-1-.7-1.9-1.5-2.9-2.2%2C1-.8%2C1.9-1.7%2C2.9-2.5%2C16.6-14.5%2C33-28.9%2C50.4-44.6-17-13.2-33.8-26.2-50.4-39.1-45-34.9-89.2-69.2-136-105.4%2C45.6-19.1%2C87.8-37%2C130-54.2C-909.3%2C0-907.2%2C0-905%2C.4c3%2C.5%2C6.2%2C1.7%2C8.8%2C2.7%2C124.8%2C46.5%2C235.7%2C114.9%2C326.6%2C213.2%2C19.7%2C21.3%2C36.7%2C45.3%2C53.9%2C69%2C3.7%2C5.2%2C4.6%2C14.5%2C3.1%2C20.7-14.8%2C60.1-32.7%2C119.2-45.6%2C179.7-19.4%2C90.6-11.1%2C180.6%2C12.9%2C269.3%2C10.2%2C37.9%2C21%2C75.8%2C31.7%2C113.7%2C0%2C0%2C.2%2C0%2C.2%2C0Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%236c7cd8%22%20d%3D%22M-513.4%2C868.7c2.8%2C8.9%2C1.2%2C14.2-6.8%2C20.3-83.5%2C62.2-174.7%2C108.5-277.6%2C129.1-8.9%2C1.8-17.9%2C3.1-26.8%2C4.6-29.3-78-31.7-393.8-3.7-495.8%2C71.8%2C9.5%2C138.7%2C33%2C204.6%2C65.3.6-6.2%2C1.5-10.2%2C1.5-14.5%2C0-44.1-.3-88.4.3-132.5.3-11.1-3.7-15.1-14.2-16.9-89-16.8-178.5-27.7-268.9-28.6v-70.1c56.2%2C17.5%2C112.5%2C35%2C168.8%2C52.5.6-1.2%2C1.2-2.1%2C1.8-3.4-56.1-42.8-112.2-85.5-170.6-130v-4.7c16.6-14.5%2C33-28.9%2C50.4-44.6-17-13.2-33.8-26.2-50.4-39.1V.3c3%2C.5%2C6.2%2C1.7%2C8.8%2C2.7%2C124.8%2C46.5%2C235.7%2C114.9%2C326.6%2C213.2%2C19.7%2C21.3%2C36.7%2C45.3%2C53.9%2C69%2C3.7%2C5.2%2C4.6%2C14.5%2C3.1%2C20.7-14.8%2C60.1-32.7%2C119.2-45.6%2C179.7-19.4%2C90.6-11.1%2C180.6%2C12.9%2C269.3%2C10.2%2C37.9%2C21%2C75.8%2C31.7%2C113.7h.2v.1Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%20%20%3Cg%20id%3D%22Generative_Object__x28_180_x2C__0_x29_%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%236c7cd8%22%20d%3D%22M512.4-.2v160.7c.1%2C0-50.2%2C38.6-50.2%2C38.6l53.2%2C47.5-174.2%2C132.9c3.5%2C4.5%2C6.9.8%2C10.5-.3l159.7-49.4c-.3.7%2C0%2C1.5%2C1%2C2v67.5l-49.9%2C1.6c-73.8%2C4.3-146.3%2C13.5-218.7%2C27.4-5.3%2C1-8.6%2C2.3-11.2%2C5.3-3.7%2C4.1-3.1%2C7.9-3.1%2C13.2l.4%2C127.7%2C1.3%2C17.1c63.6-31.1%2C134.2-56.4%2C205.3-65.1%2C11.2%2C51.5%2C15.2%2C104.1%2C17.6%2C157.1%2C3%2C100.4%2C3%2C210.6-13.7%2C308.2l-7.6%2C30.6c-113-15.4-217.2-67.2-307.6-135.5-6.6-5-6.6-11.1-4.6-18.2l25.5-89.3c34.3-120.1%2C42.1-212.6%2C9.9-335.4l-35.1-132.7c-1.8-6.7-4.1-17%2C0-23.1%2C17.6-26%2C35.4-51.1%2C57.1-73.3l23.6-24.2c27.3-28%2C56.9-52%2C88.7-75.1C358.4%2C65.9%2C433.4%2C27.9%2C512.4-.2Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%232b3eaf%22%20d%3D%22M512.4%2C399.6v-67.5c-1.1-.4-1.4-1.3-1.1-2l158.6-49.6-61.6-68.1%2C172.8-54c5.8-.1%2C9%2C2.6%2C12.4%2C6.5l101.8%2C114.2c7.6%2C8.5%2C11.4%2C17%2C7.6%2C28.6l-39%2C117.7c-27.6%2C83.2-38.5%2C162.9-20.6%2C250.7%2C8.3%2C42.8%2C20.1%2C83.1%2C34.3%2C124.2l27.9%2C80.6c-23.9%2C20-48.9%2C36.8-75.8%2C52.5-78.7%2C45.8-172.3%2C84.3-264.9%2C91.5-7.2-27.8-11.4-54.3-15.5-82.5-20.4-141.4-10.7-276.9%2C12.5-416%2C36.6%2C3.2%2C70.3%2C10.9%2C104.4%2C21.8%2C36.4%2C11.7%2C70.3%2C26.2%2C106.2%2C44.2l.4-160.8c-86-24.1-172.4-31.8-260.3-31.8v-.2h-.1Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%232b3eaf%22%20d%3D%22M512.5%2C160.6V-.2c2.4-.2%2C3.9-.3%2C6.2.6l130.4%2C54.3-136.5%2C105.8h0l-.1.1Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E'); + --icon-bleeding: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201024%201024%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23f85656%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23e20000%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M491.3%2C0s387.8%2C237%2C376.4%2C642.5-392.6%2C381.1-392.6%2C381.1c0%2C0-313-16.2-319.6-340.6%2C0%2C0-12.2-173.6%2C211.2-347.2%2C31-24.3%2C57.1-54.2%2C77-88.1C476.9%2C191.7%2C510.4%2C104.7%2C491.3%2C0h0Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M491.3%2C0s384.5%2C232.6%2C376.4%2C644c-5.5%2C286.4-202.7%2C357.6-313.7%2C373.8-135.6%2C19.9-217.8-68.2-241.4-189.1-17.3-89.6%2C43.5-237.8%2C165.9-283.5%2C189.7-70.8%2C179-394.1%2C12.8-545.2h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-isBlocking: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20358%20358%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23aaa%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23555%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M179%2C.3c-16%2C15.1-96%2C30.3-136%2C45.4v106c0%2C90.9%2C70%2C151.4%2C136%2C206V.3Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M179%2C.3c16%2C15.1%2C96%2C30.3%2C136%2C45.4v106c0%2C90.9-70%2C151.4-136%2C206V.3Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-earth: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20668%20668%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%237f5322%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23c68533%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M667.219%2C479.608c-8.671%2C19.993-71.539%2C159.699-141.152%2C170.538C340.595%2C675.678%2C0%2C570.417%2C0%2C570.417h0l.482-.722c.241-.482.722-1.204%2C1.204-1.927l1.686-3.131c.241-.241.241-.482.482-.722l8.431-14.693L308.559%2C40.257s1.927-2.649%2C3.373-4.577h0c.241-.482.722-.722.964-1.204s.723-.723.964-1.204c.723-.964%2C1.686-1.686%2C2.649-2.649%2C1.204-1.204%2C2.409-2.168%2C3.613-3.131%2C7.226-6.262%2C14.693-13.489%2C18.306-13.489%2C6.262%2C0%2C23.846%2C16.861%2C30.591%2C25.773%2C31.072%2C41.43%2C276.522%2C404.185%2C297.719%2C435.258.964%2C1.204%2C1.204%2C3.131.482%2C4.577v-.003Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M268.574%2C452.148c-179.933.241-208.114%2C61.904-268.574%2C118.269%2C0%2C0%2C.241-.241.482-.722s.722-1.204%2C1.204-1.927c.482-.722%2C1.204-1.927%2C1.686-3.131.241-.241.241-.482.482-.722l2.168-3.613c1.686-3.131%2C3.854-6.744%2C6.504-11.08L308.8%2C40.257s1.927-2.649%2C3.373-4.577h0c.723-.722%2C1.204-1.445%2C1.927-2.168.722-.964%2C1.686-1.686%2C2.649-2.649%2C1.204-1.204%2C2.409-2.168%2C3.613-3.131h0c1.445%2C0%2C26.496%2C3.372%2C70.094%2C114.174%2C59.977%2C153.677%2C71.539%2C309.763-121.882%2C310.244v-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-fire: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23f45f31%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23f4a031%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M205.026%2C0s143.724%2C146.456%2C2.084%2C304.28l-3.959-8.844s-23.36-42.83-56.791-66.213c0%2C0%2C6.529%2C48.201-21.438%2C82.627s-69.037%2C158.981%2C13.266%2C253.278c0%2C0%2C54.429%2C67.51%2C142.567%2C74.247%2C85.499%2C6.529%2C174.469-39.126%2C211.952-84.92%2C0%2C0%2C48.989-54.591%2C55.564-124.717%2C8.798-92.745-12.733-118.304-12.733-118.304-11.414%2C25.652-29.055%2C47.044-48.201%2C64.454-.092%2C0%2C23.059-298.122-282.309-375.887h-.002Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M274.249%2C338.058s46.951%2C66.815-19.007%2C119.647l-.972-3.728s-6.39-18.359-18.012-29.703c0%2C0-.556%2C19.354-13.891%2C31.046s-37.459%2C57.879-11.252%2C100.362c0%2C0%2C16.97%2C30.097%2C51.165%2C38.431%2C33.153%2C8.126%2C71.075-4.005%2C88.786-19.563%2C0%2C0%2C23.151-17.989%2C29.958-45.377%2C8.913-36.001%2C2.686-47.299%2C2.686-47.299-6.164%2C8.949-13.881%2C16.358-22.829%2C21.99l-.322.189s28.476-115.596-86.309-165.996h-.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-frost: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23eaffff%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23ade1e5%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M606.343%2C38.223l-91.595%2C174.334-106.045%2C426.511c0%2C.699-.466%2C1.166-1.166%2C1.166s-1.166-.466-1.166-1.166l-54.304-297.392-68.754-114.202c-.699-1.166-2.331-1.631-3.496-.933-.233.233-.699.466-.933.933l-35.193%2C55.237-46.147%2C144.268c-.466%2C1.166-1.864%2C1.631-3.03%2C1.166-.466-.233-.933-.699-1.166-1.166L109.677%2C147.766%2C38.592%2C75.049c-13.052-13.518-.933-34.261%2C16.314-34.027%2C37.291.233%2C86.234%2C10.022%2C124.458%2C20.976%2C70.386%2C20.044%2C161.049-43.351%2C262.899-30.532%2C99.752%2C12.819%2C164.079%2C6.759%2C164.079%2C6.759v-.002Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M606.343%2C38.223l-124.457%2C151.726c-3.496%2C4.428-5.827%2C9.556-7.225%2C14.916l-58.499%2C243.321c-.699%2C3.03-3.729%2C4.661-6.526%2C3.962-2.098-.466-3.729-2.331-4.195-4.428l-28.9-156.388c-.699-4.195-2.564-8.391-4.894-11.886l-79.709-111.639c-1.631-2.331-5.128-3.03-7.458-1.398l-54.771%2C36.824c-5.127%2C3.496-8.856%2C8.391-10.954%2C14.45l-21.675%2C67.823c-.933%2C2.797-3.962%2C4.661-6.759%2C3.729-1.864-.466-3.263-1.864-3.729-3.729l-44.516-149.162c-2.331-7.691-7.225-13.984-13.984-18.179L33.001%2C62.695c-.233-2.331%2C0-4.661.699-6.759%2C1.398-5.361%2C5.128-10.022%2C10.255-12.352%2C15.149-7.924%2C81.107-20.743%2C159.651-5.827C252.083%2C47.08%2C373.977-11.187%2C440.402%2C1.865c83.671%2C16.547%2C139.141%2C24.938%2C161.049%2C28.201%2C3.496.466%2C5.827%2C3.729%2C5.361%2C7.225-.233.233-.233.699-.466.932h-.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-lightning: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23fced60%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23eac303%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M409.207%2C12.874s-239.311%2C274.023-232.414%2C274.023l148.276%2C5.058c7.586%2C0%2C16.552%2C21.609%2C11.724%2C27.126l-176.552%2C320%2C130.575-336.092-187.816.46L235.874.001h165.518c4.827-.23%2C8.736%2C3.448%2C8.966%2C8.046%2C0%2C1.609-.23%2C3.218-1.149%2C4.827h-.002Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M457.023%2C0l-79.311%2C186.667h158.851l-376.322%2C453.333%2C174.713-336.552h-188.966L278.172%2C0h178.851Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-nature: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20.st0%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%23a0ce3e%3B%0A%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20.st1%20%7B%0A%20%20%20%20%20%20%20%20fill%3A%20%238bb737%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2Fstyle%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Cpath%20class%3D%22st0%22%20d%3D%22M96.993%2C523.156c-61.062-147.604-8.494-298.192%2C87.461-383.587C280.409%2C54.174%2C523.737%2C2.983%2C584.11%2C0c1.836%2C0%2C3.443%2C1.378%2C3.443%2C3.214%2C0%2C1.147-.459%2C2.296-1.607%2C2.984-65.194%2C39.484-118.451%2C162.754-130.846%2C312.195-17.676%2C213.946-273.63%2C218.307-301.176%2C217.848-1.378%2C0-2.754.918-3.214%2C2.296-8.264%2C29.383%2C2.984%2C77.131%2C4.591%2C92.511%2C1.607%2C14.462-39.713%2C9.412-44.534-1.836-2.525-6.657-13.773-105.825-13.773-106.054v-.002Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22st1%22%20d%3D%22M586.175%2C3.214c2.296-.689.229-3.214-1.836-3.214C314.611.229-80.453%2C191.679%2C95.616%2C521.32c.918%2C1.836%2C1.377%2C2.066%2C1.377%2C2.066C75.185%2C187.088%2C507.438%2C27.088%2C586.176%2C3.214h-.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-whirlwind: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20348%20348%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.7%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%201)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M148.55%2C0l-47.3%2C14.2c-29.8%2C13.2-63.2%2C30.3-76.7%2C61.8%2C12-12.3%2C24.5-22.5%2C39.7-30.8C113.75%2C17.8%2C183.05%2C7.4%2C238.95%2C14.1c41.8%2C5%2C123.5%2C27.7%2C104.9%2C85.7-17.4%2C54.5-112.8%2C71.2-161.8%2C73.2s-13.6.3-20%2C0c-1.2%2C0-3.7.8-3.5-1%2C54.8-6.2%2C119.1-20%2C155-65.5%2C3.3-4.2%2C7.4-9.4%2C9-14.5-14.8%2C15.9-33.5%2C28.2-53.3%2C37.2-59.3%2C26.7-140.8%2C34.3-203.2%2C14.8C-20.65%2C117-18.35%2C54.2%2C62.65%2C20.5%2C89.35%2C9.4%2C119.75%2C2.7%2C148.55%2C0ZM63.65%2C84c.9.8%2C13.9-8.4%2C16-9.5%2C53.2-29.4%2C129.3-27%2C185.5-7.5%2C10.4%2C3.6%2C20.8%2C7.9%2C30%2C14%2C11.7-24.8-18.4-39.5-37.7-45.2-47.4-14.1-124.2-7.2-167.1%2C18.5-11.4%2C6.8-23%2C16.6-26.7%2C29.8v-.1ZM161.35%2C66.3c-29.9%2C1.8-62.9%2C9.7-87.1%2C27.9s-7.9%2C4-5.5%2C8.2%2C16.8%2C14.9%2C21.6%2C15.5%2C18.4-9.2%2C22.6-11c38.7-16.7%2C87.8-18.2%2C128.7-9.3s18.3%2C5.1%2C27.3%2C8.2l18.6-13.2c-36.6-20.8-84.3-28.7-126.2-26.2v-.1ZM250.55%2C115c-1.5-2.5-6.2-2.8-9-3.5-33.9-8.5-100.7-8.3-130.7%2C11.3-1%2C.6-1.8-.1-1.3%2C2.2%2C46.8%2C9.6%2C96.1%2C6.1%2C141-10Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M304.65%2C165c-31.2%2C32.8-74.4%2C58.8-119%2C68.5-42.3%2C9.2-90.9%2C4.2-120-31-.9-1.1-2.4-1.6-2-3.5%2C7.8%2C3.7%2C15.6%2C7.1%2C24%2C9.5%2C22.3%2C6.3%2C44.3%2C6.6%2C67.4%2C4.4l39.6-8.9-36.5-1c-39.3-3.7-77.1-17.4-106.5-44%2C18.6%2C7.9%2C37.3%2C14.9%2C57%2C19.5%2C44.9%2C10.4%2C94.8%2C12.4%2C140.2%2C4.2%2C19.3-3.5%2C38.1-9.5%2C55.8-17.7Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M222.65%2C234c-25.3%2C29.9-84.5%2C52-121%2C33.5s-20.3-15.9-20.5-26.5c43.8%2C24.8%2C98%2C12.6%2C141.5-7Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M159.65%2C317l-13.1%2C30.9-29.2.2c-11.9-16.6-21.8-35.1-26.7-55%2C19.3%2C16.5%2C42.6%2C29.3%2C69%2C24v-.1Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M99.65%2C282c25.8%2C9.1%2C53.7%2C6.6%2C79-3-11%2C40.2-57.8%2C26-79%2C3Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-hitChance: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20462%20462%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M286.1%2C232.9c1.2%2C8.2-4.6%2C15.9-12.8%2C17%2C0%2C0%2C0%2C0%2C0%2C0l-147.2%2C20.6-21.3%2C32.5-82.6%2C11.6%2C21.3-32.6-24.5%2C3.4c-.3%2C0-.6.1-.8.2-.7%2C0-1.4.1-2.1.1-8.3%2C0-15.1-6.7-15.2-15%2C0-7.6%2C5.6-14%2C13.1-15%2C.3%2C0%2C.6%2C0%2C.9%2C0l24.5-3.4-29.5-25.5%2C82.6-11.5%2C29.4%2C25.5%2C147.3-20.6c.7%2C0%2C1.4-.1%2C2.1-.1%2C7.5%2C0%2C13.9%2C5.5%2C15%2C12.9h0ZM249.4%2C194.4c2.8-4.2%2C6.5-7.8%2C10.8-10.3%2C4.1-2.3%2C8.7-3.4%2C13.4-3%2C4.9.5%2C9.6%2C2.2%2C13.5%2C5%2C4.8%2C3.4%2C8.8%2C7.7%2C11.9%2C12.6%2C3.8%2C5.9%2C6.6%2C12.4%2C8.4%2C19.1%2C1.9%2C7.2%2C2.8%2C14.6%2C2.6%2C22-.2%2C6.8-1.3%2C13.5-3.5%2C20-1.8%2C5.6-4.7%2C10.8-8.5%2C15.4-3.3%2C3.9-7.6%2C6.9-12.4%2C8.6-4.5%2C1.5-9.3%2C1.6-13.8.3-4.7-1.4-8.9-3.8-12.5-7.1-2.1-1.9-4-4-5.7-6.2l-32.3%2C4.5c2%2C5.5%2C4.4%2C10.8%2C7.1%2C16%2C4.9%2C9.4%2C11.2%2C18%2C18.7%2C25.5%2C6.8%2C6.9%2C14.9%2C12.3%2C23.9%2C15.8%2C8.8%2C3.4%2C18.4%2C4.2%2C27.6%2C2.2%2C10-2.3%2C19.2-7.5%2C26.3-14.9%2C7.9-7.9%2C14.4-18.3%2C19.1-30.5%2C5-13.5%2C7.9-27.6%2C8.3-42%2C.6-15.8-1.2-31.7-5.5-46.9-3.8-14.3-10.1-27.8-18.5-39.9-7.6-10.7-16.4-18.9-25.8-24.4-8.4-5.1-18.1-7.7-28-7.6-9.4.3-18.5%2C3.3-26.3%2C8.7-8.2%2C5.8-15.1%2C13.2-20.2%2C21.9-5.4%2C9.2-9.5%2C19.1-12%2C29.5-1.8%2C7.1-2.9%2C14.2-3.6%2C21.5l31.2-4.4c1.4-4%2C3.2-7.7%2C5.6-11.2ZM447.7%2C159.4c-10.9-35.3-27.3-64.8-46.8-87.4-18.6-21.5-39.5-36.3-61.1-44.2-20.2-7.4-40.6-8.7-60-4.2-18.1%2C4.2-35.2%2C13.5-50.6%2C27.6-14.4%2C13.2-26.1%2C29.6-35.2%2C47.8-8.8%2C18-15.3%2C37-19.3%2C56.6-4.1%2C20-6.1%2C40.3-5.9%2C60.7l22.6-3.2c.4-13.6%2C2.1-27.1%2C5-40.3%2C3.3-15%2C8.7-29.4%2C16-42.9%2C7.4-13.4%2C16.7-25.1%2C28-34.1%2C11.9-9.4%2C24.9-15%2C38.3-16.6%2C14.2-1.8%2C28.8.7%2C42.9%2C7.5%2C14.9%2C7.1%2C29.1%2C18.8%2C41.5%2C34.8%2C12.9%2C16.6%2C23.5%2C37.5%2C30.7%2C61.9%2C7.1%2C24.2%2C10%2C49.5%2C8.7%2C74.6-1.3%2C24-6.4%2C46.4-14.7%2C65.7-8%2C18.6-18.9%2C33.9-31.8%2C44.9-12.3%2C10.5-26.3%2C16.9-41.5%2C18.7-14.1%2C1.5-28.4-.9-41.2-7.1-12.3-5.7-23.8-14.5-34-25.5-10.3-11.3-19-23.9-25.7-37.6-6.1-12.3-11-25.3-14.5-38.6l-22.5%2C3.1c4.5%2C19.9%2C11.2%2C39.3%2C20%2C57.8%2C8.5%2C18%2C19.3%2C34.9%2C32.2%2C50.1%2C13%2C15.2%2C27.8%2C27.8%2C43.9%2C36.8%2C17.2%2C9.6%2C36%2C15.1%2C55.7%2C14.9%2C21.3-.2%2C41.4-7%2C59.5-19.8%2C19.4-13.7%2C36-33.9%2C48.6-59.4%2C13.2-26.8%2C21.7-58.8%2C24-93.6%2C2.4-36.7-2-73.6-12.9-108.8h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stoneSkin: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20472%20472%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M190.1%2C15L8.1%2C121.5l119.6%2C54.3%2C148.3%2C11.7%2C42-24.3%2C17.3%2C11.6-46.2%2C26.8v148.9l53.6-14.6-64.6%2C52-110.9-59.6-2.2-1.5-71.3%2C6.6%2C75.9-32%2C100.8%2C52.1v-147.5l-145.9-11.5h-1.6c0-.1-1.5-.8-1.5-.8L.4%2C138.5v223.8l23.8%2C31.7%2C82%2C21%2C21.9-21.3%2C11.2%2C29.7%2C131.3%2C33.6v-52.2l4.2%2C2.3%2C5.5%2C2.9%2C4.8-3.9%2C4.2-3.3v52.2l182.4-106.3v-96.4l-24.6-11.9%2C24.6-38.8v-105.7l-90.2%2C52.3-1.1%2C34.1-88-58.7%2C85%2C5.4%2C79.5-46.1-184.9-47.1%2C1.6.6-64.4%2C5.8%2C5.3-20.9-24.2-6.2h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-smokeBomb: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20469%20469%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M263.7.2c-20.4%2C0-39.6%2C6.7-52.8%2C18.1-8.8-6.1-19.3-9.3-30-9.3-27.8%2C0-50.6%2C21.5-52.8%2C48.8-18%2C5-30.8%2C21.4-30.8%2C40.6s.2%2C5.1.7%2C7.6c-2.9%2C5.9-4.5%2C12.3-4.5%2C18.9%2C0%2C23.2%2C18.9%2C42.1%2C42.1%2C42.1%2C2.4%2C0%2C4.8-.2%2C7.2-.6%2C1.4%2C2.9%2C3.1%2C5.7%2C5.1%2C8.2-17.4%2C3.3-27.1%2C17.2-23.3%2C36-9.3%2C4.6-16.9%2C6.2-17.2%2C18.3-.3%2C9.9%2C4.9%2C19%2C13.2%2C25.6-8.3%2C6.6-13.2%2C15.7-13.2%2C25.6s10.4%2C21.7%2C17.6%2C28.4c-7.4%2C9.7-7.9%2C25-.3%2C38.2.7%2C1.2%2C1.5%2C2.4%2C2.3%2C3.5l-14.6%2C49.4%2C48.4-30.4c7.1-.4%2C13.2-.9%2C20%2C.1%2C9.9%2C0%2C19.4-4.4%2C26.6-12.2%2C1.6.2%2C3.2.3%2C4.9.3%2C25.4%2C0%2C46.1-20.7%2C46.1-46.1s-.3-5.9-.8-8.8c14.2-4%2C25.6-14.5%2C30.8-28.3%2C8.7-2.7%2C16.6-7.6%2C22.8-14.3%2C27.7-.2%2C51.6-20%2C57.2-46.8%2C14.9-10.4%2C24.1-26.9%2C25-45%2C17.8-6.7%2C29.8-23.6%2C29.8-43.1s-19-44.4-43-46c-3.6-21.8-22.6-38.5-45.5-38.5s-2.1%2C0-3.1.1C324.2%2C17%2C296.6.2%2C263.7.2h0ZM263.7%2C15.5c28.1%2C0%2C52%2C15.2%2C54.4%2C34.5v.7c-9.5-9-22.2-14-35.5-13.9-17.2.1-33.2%2C8.7-42.8%2C23%2C9.5-8.7%2C21.9-13.6%2C34.7-13.7%2C28.5-.2%2C51.6%2C22.7%2C51.6%2C51.1h0c0%2C10.2-3.1%2C20.3-8.8%2C28.8%2C10.8-9.8%2C16.9-23.6%2C16.9-38.1%2C0-11-3.6-21.7-10.2-30.5%2C3.5-.9%2C6.9-1.6%2C10.7-1.7%2C16.9%2C0%2C30.7%2C13.8%2C30.7%2C30.7v8.8c4-.4%2C7.8-.9%2C11.6-1%2C17%2C0%2C30.7%2C13.8%2C30.7%2C30.7s-9.8%2C26.7-23.8%2C29.9l-6.2%2C1.4c.1%2C2.9.3%2C5.8.4%2C8.6%2C0%2C15.2-7.7%2C29.1-20.7%2C37l-3.1%2C1.9-.5%2C3.6c-3.1%2C21.2-21.6%2C37.1-43%2C37.1-2%2C0-4.4-.2-6.5-.3l-2.5%2C3c-5.6%2C6.7-15.6%2C12.1-25.8%2C14-3.6%2C13.8-12.1%2C23.3-28.8%2C27.4l-10.7.7%2C4.2%2C9.9c1.6%2C3.8%2C2.4%2C7.8%2C2.4%2C11.9%2C0%2C17-13.8%2C30.7-30.7%2C30.7-3.4%2C0-7.6-.9-11.3-1.7-5.5%2C7.5-9.4%2C12-20.2%2C13.7-7.8-.1-16.4-1.8-24.9.1l-17.3%2C10.9%2C3.7-12.4%2C2.1-5.7c-2.5-2.7-4.6-4.8-6.4-7.9-5.3-9-4.5-19.8%2C1.7-23.4%2C2.2-1.3%2C3.6-3.5%2C3.9-5.9.5-4.4-2.2-6.8-6.5-10.9-3.9-3.6-14.3-13.2-14.3-18.7%2C0-7.8%2C6.4-14.9%2C16.4-18.3l21.6-7.3-21.6-7.3c-10-3.4-16.4-10.5-16.4-18.3%2C0-3.9%2C13.2-8.2%2C16.7-11.9-3.1-13.3.2-24.4%2C16.4-27.8%2C3.5%2C0%2C7.8%2C1.1%2C11.6%2C2%2C3.3-5.1%2C6.6-9.9%2C10.8-14.6l-8.8-4.2c-7.1-3.4-12.3-9.7-14.4-17.2l-2.2-8.1c-6%2C2.2-10.8%2C4.5-17.2%2C4.6-14.8%2C0-26.8-12-26.8-26.8s1.3-9.6%2C3.8-13.8l1.7-2.8c-.9-3.5-1.7-6.2-1.7-9.9%2C0-13.7%2C10.3-25.2%2C23.9-26.6l7.2-.8c-.1-3.1-.3-6.1-.4-9%2C0-20.7%2C16.9-37.6%2C37.6-37.6s18.4%2C3.5%2C25.4%2C9.8l5.7%2C5.2%2C5.2-5.8c10.1-11.3%2C27.5-18.1%2C46.5-18.1h0ZM176.4%2C73.1c-13.5.1-26.5%2C9.5-32.5%2C23.4-8.1%2C18.7-1.5%2C39.6%2C14.8%2C46.7.6.3%2C1.2.5%2C1.9.7-10.9-8.7-14.1-25.1-7.8-39.6%2C7.5-17.3%2C25.8-26.1%2C40.9-19.5.4.2.7.4%2C1.1.6-7.5%2C3.7-12.4%2C10.2-13.3%2C17.7%2C0%2C.6-.1%2C1.2-.1%2C1.8%2C6-8.2%2C17.8-12.5%2C30-11.1%2C11.9%2C1.4%2C22.1%2C8.1%2C26.1%2C17.1%2C0-.2%2C0-.4.1-.6%2C1.5-13.3-9.8-25.7-25.3-27.7-1.6-.2-3.2-.3-4.8-.3-3%2C0-5.9.5-8.6%2C1.4-2.9-3.6-6.6-6.5-10.8-8.3-3.7-1.6-7.6-2.4-11.7-2.3h0ZM226.4%2C212.4c-18-.4-33.2%2C9.8-37.2%2C25-.6%2C2.3-.9%2C4.6-1%2C6.9%2C0-.1%2C0-.2%2C0-.3%2C5.4-16.7%2C25.5-25.1%2C44.7-18.8%2C0%2C0%2C0%2C0%2C0%2C0%2C19.2%2C6.3%2C30.4%2C24.9%2C25%2C41.5%2C0%2C0%2C0%2C0%2C0%2C0-1.4%2C4.3-3.9%2C8.3-7.3%2C11.5%2C8.4-4.5%2C14.3-11.7%2C16.6-20.2%2C4.9-18.7-8.5-38.4-30.1-44.1%2C0%2C0%2C0%2C0%2C0%2C0-3.5-.9-7.2-1.5-10.8-1.5h0ZM93.4%2C373.7c-26.3%2C0-47.6%2C21.3-47.6%2C47.6s21.3%2C47.6%2C47.6%2C47.6%2C47.6-21.3%2C47.6-47.6-1.5-13.4-4.1-19.3c-1.4-3.2-18.4%2C19.3-33.2%2C9.2-7.1-4.8-1.8-19.9%2C1.5-28.7%2C1.5-3.9%2C2.5-6.5%2C2.1-6.7-4.5-1.4-9.1-2-13.8-2h0ZM78.2%2C390.2c1.1.2-9%2C14%2C1.3%2C36.8%2C2.1%2C4.6-.3%2C10-5%2C12-4.7%2C2-10.2-.1-12.1-4.7-2-4.6%2C0-33.4%2C15.1-43.7.4-.3.6-.4.8-.4h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-warCry: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20467%20467%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M245.4%2C301.9h-23.8l-12.1-40.9-63.8-19.8%2C1%2C39.4%2C41.9%2C47.3%2C16.1-14.3%2C12.2%2C141.8-109.2-122.2%2C19.4-58.2-10.4-125.2%2C23.1-9.8c18.4%2C71.3%2C73.1%2C96.4%2C73.1%2C96.4l20.6-28.9%2C20.6%2C28.9s54.7-25.1%2C73.1-96.4l23.1%2C9.8-10.4%2C125.2%2C19.4%2C58.2-109.2%2C122.2%2C12.2-141.8%2C16.1%2C14.3%2C41.9-47.3%2C1-39.4-63.8%2C19.8-12.1%2C40.9ZM371.2%2C366.7l-74.8%2C76.7%2C56.8-28%2C6.1%2C24%2C51.6-36-39.7-36.7ZM95.8%2C366.7l74.8%2C76.7-56.8-28-6.1%2C24-51.6-36%2C39.7-36.7ZM362.3%2C249l101.2-58.3C483.5%2C2.4%2C409.9-9.9%2C338%2C30.1c0%2C0%2C114.1-27.7%2C66.1%2C109.4l-35.8%2C14.7-6%2C94.8ZM104.7%2C249L3.5%2C190.7C-16.5%2C2.4%2C57.1-9.9%2C129%2C30.1c0%2C0-114.1-27.7-66.1%2C109.4l35.8%2C14.7%2C6%2C94.8ZM233.5%2C97.3l67.5%2C41.8s-3.2%2C35-42.4%2C64.7l-25.1-51.7-25.1%2C51.7c-39.2-29.7-42.4-64.7-42.4-64.7l67.5-41.8Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-intimidatingRoar: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476%20476%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M165.6%2C3.3c53.7%2C45.4%2C5.5%2C70.3-7.8%2C76.3-40.5%2C18.4-87.7-24.6-99.5-67.3-14.3%2C43.2-47.1%2C132.1%2C11.2%2C168.1-35.8%2C39.9-35.7%2C37-65.2-7.9-8.4%2C41.3-2.8%2C112.6%2C15.7%2C164.1%2C2-22.1%2C5-43.5%2C11.2-60.7l1.1-3%2C2.8-1.7c45.9-27.2%2C86.1-36%2C117.3-40.1-3-12.3-4.7-25.5-4.7-39.2s.1-6%2C.2-8.9l-82.1-40.7%2C35.5-14.9-45.3-45.2%2C89.7%2C51-29.2%2C12.2%2C32%2C30.6c2.5-26.4%2C11.2-50.1%2C24.3-68.5%2C15.7-22.1%2C38.4-36.6%2C63.9-36.6s48.2%2C14.5%2C63.9%2C36.6c13.2%2C18.5%2C21.9%2C42.4%2C24.4%2C68.9l40.1-41.3-38.1-10.9%2C84.1-70.1-42.9%2C60.5%2C45.2%2C14.3-88.2%2C49.7c.4%2C6.3.6%2C11.8.4%2C17.5%2C6.2-.9%2C12.5-1.5%2C18.7-1.6%2C5.8%2C0%2C11.5.4%2C16.7%2C1.3%2C14.8%2C4.2%2C40.8%2C45.8%2C45.1%2C57.7-2.9%2C14.3-13%2C25.4-22.4%2C34.8l44.9%2C95.9c5.9%2C12.6%2C2.8%2C28.4.5%2C40.3-2.4%2C12-9.3%2C23.5-21.7%2C27.5-23.7%2C5-40.5-7.7-54.3-23%2C.2%2C15.2%2C0%2C30.1-.4%2C44.9h94.4c27.4-32.1%2C28.2-70.2%2C24.9-111.1-24.7%2C25.5-45.1-14.3-57.4-41.6%2C29.3%2C26.7%2C70.1-42.9%2C59.3-106.7-5.4%2C15.8-42.6%2C27-59-27.7%2C50.4-13%2C54.4-78.4%2C60.5-110-21.2%2C26.9-33.3%2C42.1-65.6%2C24.3%2C38.8-28.3%2C7.1-73.3-26.7-91%2C23%2C33.7-57.3%2C89.8-81.1%2C66.5C287.2%2C25.4%2C217.9-4.1%2C165.6%2C3.3ZM236.6%2C88.9c-18.7%2C0-36%2C10.5-49.2%2C29-5.5%2C7.6-10.1%2C16.6-13.7%2C26.5%2C22.5%2C12.7%2C45.4%2C25.1%2C57.2%2C47.7-1.4%2C5.3-2.4%2C10.8-3.9%2C16l-44.4-10.6c7.1-12.6%2C27.8-11.6%2C39.7%2C3.2-7.6-11.3-19.1-20-38.9-21l-10.4-33.4c-4.7%2C13.7-7.4%2C29.2-7.4%2C45.6%2C0%2C29.2%2C8.5%2C55.5%2C21.8%2C74%2C13.2%2C18.5%2C30.5%2C29%2C49.2%2C29s36-10.5%2C49.2-29c1.4-1.9%2C2.6-3.9%2C3.9-5.9-2.2-17.1-3.9-39.4%2C3.1-52.2%2C3-4.7%2C9.9-6.1%2C14.5-7.6.8-18.8-2.2-39.9-7.9-55.9l-10%2C35c-17.1%2C1.3-27.8%2C8.2-35.2%2C17.4%2C8.1-4.5%2C25.6-6.4%2C36.4-8.8%2C1.1%2C5.7%2C2.8%2C11.4-2.8%2C17.9-13.3-4.4-29.6-1.4-40.9%2C2.8-1.2-5.4-3.3-11.1-4.7-15.7%2C11.4-23.2%2C34.5-36.2%2C56.9-49.6-3.5-9.5-8-18-13.3-25.4-13.2-18.5-30.5-29-49.2-29ZM307.5%2C219.5c-2.2%2C6.6-3%2C19.7-.8%2C33.1%2C2.1%2C13.7%2C6.6%2C27.3%2C10.2%2C34.2%2C6.9%2C2.5%2C13.8%2C5.1%2C20.7%2C7.7l25%2C118c9.6%2C10.8%2C24.3%2C26.9%2C39.2%2C22.4%2C14.2-7.3%2C10.9-33%2C9.2-45.6l-48.6-103.9c7.7-11.8%2C20.9-21.1%2C24.6-31.2-5.2-13.2-17.7-31.3-31-40.9-15.3-.5-35.8%2C1.9-48.5%2C6.2h0ZM197.3%2C223.7c7.8%2C0%2C22.1%2C15%2C39.8%2C13.9%2C15.9-.9%2C29.4-21.3%2C39.5-9.2%2C11%2C13.3-4%2C33.9-11.4%2C40%2C0%2C0-14.3-14.7-27.8-13.6-13.3%2C1-25.1%2C16.4-25.1%2C16.4-15.8-9.5-28.3-28.6-19.4-44.7%2C1.1-2%2C2.6-2.8%2C4.4-2.8h0ZM157.9%2C248.6c-29.9%2C3.7-67.1%2C11.2-110.7%2C36.5-10.1%2C39-10.7%2C79.1-14.4%2C114.8l-23.9%2C41.2c2.8%2C14.4%2C7.5%2C33.4%2C23.5%2C32.1%2C18-2.5%2C35.8-13.4%2C42.1-29-2.4-10.8-6.1-19.3-10.2-28%2C4.3-33.2%2C4.2-66%2C13.3-91.5l2.9-7.8c29.2%2C6.6%2C47.8%2C2.6%2C70.2-13.4l-1.2%2C19c-3.4%2C51.4-12%2C105.7-10.1%2C151.4h195.1c1.5-49.8.3-100.3-10.5-154.2-.7-3.7-1.3-7.6-2-11.8l-17.6-6.6c-3.8-6-6.9-12.9-8.9-18.5-15.4%2C18.3-36%2C30.1-58.9%2C30.1s-48.2-14.5-63.9-36.6c-5.9-8.2-10.9-17.6-14.8-27.7h0ZM130.2%2C336.8c-13%2C4-26.8%2C3.6-38.1%2C1.6-7.3%2C24.1-7.4%2C48.4-9.5%2C74.6%2C5%2C12.5%2C9%2C21.8%2C10.4%2C33.2-4.1%2C10.6-10%2C21-16.5%2C27.7h44.7c-1.8-43.5%2C5.1-91.6%2C9-137.1h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-alorasTouch: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20460%20460%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M133.4.3C82%2C.9%2C53.8%2C56.6%2C54.1%2C87.2c1.5%2C47.3%2C34.2%2C79.4%2C74.8%2C114.8%2C35.4%2C30.8%2C76.1%2C63.3%2C100.9%2C110%2C0%2C0%2C.1-.2.2-.3%2C0%2C0%2C.1.2.2.3%2C24.8-46.7%2C65.6-79.2%2C100.9-110%2C40.6-35.4%2C73.3-67.4%2C74.8-114.8.3-30.7-27.9-86.3-79.2-87-38-.5-82.6%2C25.7-96.6%2C67.7C216%2C25.9%2C171.4-.2%2C133.4.3ZM34.2%2C170c-8.8-.1-17.8%2C11.1-17.9%2C39.9%2C0%2C44.2-4.4%2C56.6%2C16.1%2C106.6%2C15%2C36.6%2C21.7%2C64.8%2C69.6%2C87.5%2C5.7%2C20%2C3.4%2C24.7-.4%2C41.8-3.6%2C16%2C33.4%2C18.9%2C60.5%2C5.5%2C29.1-15.9%2C26.6-59.6%2C21.5-89.2-6-34.5-25.1-41.6-41.5-56.3-17.1-24.5-21.1-68.8-48.9-86.7-5.8-3.7-35.4-7.5%2C5.3%2C93.9-53.6-13.3-43.8-74.8-47.7-120.3-1.2-13.6-8.8-22.5-16.6-22.6h0ZM425.8%2C170c-7.8.1-15.4%2C9.1-16.6%2C22.6-3.9%2C45.5%2C5.9%2C107-47.7%2C120.3%2C40.6-101.5%2C11.1-97.7%2C5.3-93.9-27.8%2C17.9-31.7%2C62.2-48.9%2C86.7-16.5%2C14.7-35.5%2C21.9-41.5%2C56.3-5.2%2C29.6-7.6%2C73.3%2C21.5%2C89.2%2C27.1%2C13.5%2C64.1%2C10.5%2C60.5-5.5-3.9-17.1-6.1-21.8-.4-41.8%2C47.9-22.7%2C54.7-50.9%2C69.6-87.5%2C20.4-49.9%2C16.2-62.4%2C16.1-106.6%2C0-28.8-9.1-40-17.9-39.9h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-armorPenetration: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20480%20480%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M203.7%2C2.2l-17.1%2C78.3c16.9-6%2C35.1-9.3%2C54-9.4L203.7%2C2.2ZM433%2C75.1l-133.3%2C57.1c-3.8%2C39.7%2C34.4%2C73.8%2C69.1%2C72.9l64.2-130h0ZM242.1%2C89.7c-32.5%2C0-62.6%2C10.4-87%2C28.2l25.4%2C4.4h5.2l2.4%2C5.6c23.2%2C53-17.3%2C112.8-68.4%2C118.4l-5%2C.6-3.2-3.9-17-20.4c-.5%2C5.1-.8%2C10.3-.8%2C15.5%2C0%2C82%2C66.3%2C148.3%2C148.3%2C148.3s8.5-.2%2C12.6-.5l-33.8-26.5-4-3.1.4-5c3.7-43.3%2C44.8-80.4%2C90.1-80.7%2C10.5%2C0%2C21.1%2C1.9%2C31.6%2C6.1l4.7%2C1.9%2C1%2C5%2C10.1%2C50.8c22.1-25.9%2C35.4-59.5%2C35.4-96.3s-1-19.5-2.8-28.8l-4.5%2C9-2.2%2C4.5-5%2C.6c-50.9%2C6.4-104.3-42.3-94-99.3l1.9-5%2C3.6-2%2C24-10.3c-20.7-11-44.3-17.2-69.3-17.2h0ZM29.8%2C115.3l92.7%2C111.5c34-7.1%2C63.1-49.2%2C50.2-86.9L29.8%2C115.3h0ZM75.1%2C237.4L.3%2C280.2l85.4%2C16.2c-6.8-18.2-10.6-37.9-10.6-58.4s0-.4%2C0-.6h0ZM408.6%2C249.9c-1.4%2C20.2-6.5%2C39.9-15%2C58.2l86.1-7.9-71.1-50.3h0ZM307.5%2C289.4c-33.8.8-65.3%2C28.3-70.7%2C58.5l120.6%2C94.8-29.9-150.3c-6.7-2.1-13.4-3.2-20.1-3h0ZM162.3%2C384.7l8.6%2C93.2%2C52.2-73.9c-21.3-2.4-42-8.9-60.8-19.2h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-the-arena: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20470%20470%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M131.4%2C56.8c-49.3%2C15.9-93.3%2C45.8-114.4%2C86%2C13.5-.9%2C10.6%2C14.5%2C10.6%2C29.9h-13.5c.3%2C20%2C4.5%2C22.5%2C4.5%2C22.5%2C8.8%2C0%2C8.8%2C16%2C8.8%2C32H10.6L0%2C389.2c0%2C2.8%2C3.5%2C5.3%2C9.9%2C7.5.2-25.6%2C1.5-47.5%2C8.7-47.5s8.7%2C24.5%2C8.8%2C52c6.8%2C1.3%2C14.7%2C2.5%2C23.5%2C3.6.2-27.4%2C1.5-51.6%2C11.7-51.6s11.6%2C25.7%2C11.7%2C54.1c9.2.8%2C19%2C1.6%2C29.4%2C2.2.1-28.5%2C1.4-54.3%2C13.7-54.3s13.6%2C26.7%2C13.7%2C55.8c8.3.4%2C16.8.7%2C25.5%2C1%2C.1-28.6%2C1.5-54.8%2C15.6-54.8s17.3%2C8%2C17.4%2C36.9c27.6%2C20.2%2C24%2C14.4%2C27.7%2C19%2C.1-29.1%2C1.5-55.9%2C17.6-55.9s17.5%2C26.8%2C17.6%2C55.9c9.9%2C0%2C19.7-.2%2C29.4-.4.1-28.9%2C1.4-55.6%2C15.6-55.6s15.5%2C26.1%2C15.6%2C54.8c6.9-.2%2C13.7-.5%2C20.6-.8l-34.5-77.3-30.5-2.6-24.5-113-35.3%2C3-13-52.7-15.9-2.3-48.7-109.5ZM117.7%2C102.8c13.7%2C0%2C13.7%2C16%2C13.7%2C32l-27.4%2C8c0-16%2C0-40%2C13.7-40ZM62.9%2C118.8c11.8%2C0%2C11.8%2C16%2C11.8%2C32l-23.5%2C4c0-16%2C0-36%2C11.8-36ZM172.3%2C179.2c15.7%2C0%2C15.7%2C16%2C15.7%2C32l-31.3%2C2c0-16%2C0-34%2C15.7-34h0ZM117.5%2C183.2c13.7%2C0%2C13.7%2C16%2C13.7%2C32l-27.4%2C2c0-16%2C0-34%2C13.7-34ZM62.7%2C189.2c11.8%2C0%2C11.8%2C16%2C11.8%2C32l-23.5%2C4c0-16%2C0-36%2C11.8-36ZM262%2C216.4l20%2C92.2c0-23.8.1-47.3%2C15.7-47.3s15.7%2C24%2C15.7%2C48c-1.4%2C5.7-1.5%2C6.2-2.2%2C7.7l28.7%2C64.2c1.4-15.2%2C4.7-25.9%2C12.7-25.9%2C12.3%2C0%2C13.6%2C25.8%2C13.7%2C54.3%2C9.6-.6%2C18.8-1.3%2C27.5-2.1.1-28.4%2C1.2-54.2%2C11.7-54.2s11.6%2C24.4%2C11.7%2C51.8c10.5-1.3%2C19.8-2.7%2C27.5-4.2.1-27.4%2C1.1-51.6%2C8.8-51.6s8.5%2C21.5%2C8.7%2C46.8c5.1-2.1%2C7.9-4.3%2C7.9-6.8l-9-138.1c-10.9-10-26.1-16.9-44.1-21.7l-19.9%2C14-30.3-2.8-20.7-21.1c-27.1-1.7-55.9-2.2-84-3.1h0ZM172.3%2C261.2c15.7%2C0%2C15.7%2C24%2C15.7%2C48h-31.3c0-24%2C0-48%2C15.7-48ZM235%2C261.2c17.6%2C0%2C17.6%2C24%2C17.6%2C48h-35.2c0-24%2C0-48%2C17.6-48ZM117.5%2C263.2c13.7%2C0%2C13.7%2C24%2C13.7%2C48h-27.4c0-24%2C0-48%2C13.7-48ZM352.5%2C263.2c13.7%2C0%2C13.7%2C24%2C13.7%2C48h-27.4c0-24%2C0-48%2C13.7-48ZM62.7%2C265.2c11.8%2C0%2C11.8%2C22%2C11.8%2C46l-23.5%2C2c0-24%2C0-48%2C11.8-48ZM405.4%2C265.2c11.8%2C0%2C11.8%2C24%2C11.8%2C48l-23.5-2c0-24%2C0-46%2C11.8-46ZM22.6%2C267.2c8.8%2C0%2C8.8%2C22%2C8.8%2C46l-17.6%2C2c0-24%2C0-48%2C8.8-48h0ZM449.4%2C267.2c8.8%2C0%2C8.8%2C24%2C8.8%2C48l-17.6-2c0-24%2C0-46%2C8.8-46h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-powerShot: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20477%20477%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M68.4.2l-3.1%2C49.7-30.6-28.6-11.7%2C11.7%2C30%2C32.2L.2%2C68.4c41.8%2C51.5%2C65.3%2C68.4%2C119.2%2C67.8l22.3%2C23.9c3.2-3.3%2C6.3-6.5%2C9.6-9.7h0c3.5-3.5%2C7.1-7%2C10.6-10.4l-23.4-21.8C144.6%2C63.2%2C116.1%2C38.8%2C68.4.2h0ZM432.7%2C2.3c-1%2C0-2%2C0-3%2C0-2.3%2C0-4.7.2-7.2.4-19.9%2C1.8-44.9%2C9.5-72.7%2C22.8-55.5%2C26.5-122.2%2C74.9-185.7%2C138.4-63.5%2C63.5-111.9%2C130.2-138.6%2C185.9-13.3%2C27.8-21.1%2C52.9-22.9%2C72.8-1.8%2C19.9%2C2.2%2C34%2C11%2C42.8%2C8.8%2C8.8%2C22.9%2C12.8%2C42.8%2C11%2C19.9-1.8%2C45-9.6%2C72.8-22.9%2C47.2-22.6%2C102.5-61%2C156.9-110.9l-14.2-15.2c-2.1%2C1.9-4.2%2C3.9-6.2%2C5.8-8.9%2C6.3-17.5%2C11.4-25.2%2C15.1-8.8%2C4.2-16.6%2C6.6-22.2%2C7.1-5.6.5-8.1-.6-9.3-1.9s-2.4-3.8-1.9-9.3c.5-5.5%2C2.8-13.4%2C7.1-22.2%2C6.8-14.2%2C18.4-31.2%2C33.5-48.1h.1c2.2-2.4%2C4.4-4.9%2C6.6-7.3.3-.4.7-.7%2C1-1.1%2C1.2-1.3%2C2.5-2.6%2C3.8-3.8%2C20.8-20.8%2C42.6-36.6%2C60.3-45%2C8.8-4.2%2C16.6-6.5%2C22.1-7%2C.7%2C0%2C1.3-.1%2C1.9-.1.6%2C0%2C1.2%2C0%2C1.7%2C0%2C3.1.2%2C4.8%2C1%2C5.7%2C2%2C1.3%2C1.3%2C2.4%2C3.8%2C1.9%2C9.3-.5%2C5.5-2.8%2C13.3-7%2C22.1-3.9%2C8.1-9.3%2C17-16%2C26.3-.3.3-.6.6-.9%2C1l15.1%2C14.2c49.2-54%2C87-108.5%2C109.3-155.2%2C13.3-27.8%2C21-52.8%2C22.8-72.7%2C1.8-19.9-2.2-34-11-42.8-7.2-7.2-18-11.2-32.6-11.4h0ZM420.4%2C68.3c7.3-.2%2C13%2C1.6%2C16.9%2C5.5%2C18.1%2C18.1-10%2C77.3-65.6%2C147.1.4-8.3-1.5-16.6-7.4-22.5-4.7-4.7-11-6.9-17.6-7.4-2.2-.1-4.4-.1-6.6%2C0-8.9.8-18.4%2C3.9-28.5%2C8.8-20.3%2C9.7-43.4%2C26.6-65.4%2C48.6h0c-22%2C22-38.9%2C45.1-48.7%2C65.5-4.9%2C10.2-8%2C19.7-8.8%2C28.6-.8%2C8.9.9%2C17.9%2C7.3%2C24.2%2C5.7%2C5.7%2C13.7%2C7.7%2C21.8%2C7.4-68.3%2C53.8-125.8%2C80.6-143.6%2C62.8-24.7-24.7%2C36.6-126.2%2C136.8-226.4%2C84.6-84.6%2C170-141.4%2C209.5-142.3h0ZM236.9%2C210c-8.5%2C8.2-16.9%2C16.7-25%2C25.3l10.5%2C11.2c8.4-8.9%2C17.3-17.3%2C26.5-25.3l-11.9-11.2h0ZM289.5%2C259.1c-10.3%2C8.7-19.8%2C18-28.7%2C28.6l25%2C26.8h0c0%2C0%2C14.3%2C15.3%2C14.3%2C15.3h0c0%2C0%2C38%2C40.7%2C38%2C40.7l-73.9%2C23.7%2C211.1%2C81.6-81.6-211.1-22.6%2C70.6-39.7-37h0c0%2C0-15.2-14.3-15.2-14.3%2C0%2C0%2C0%2C0-.1.1l-26.7-24.9h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-brawlers: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476%20476%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M237.9.5c-13.4%2C0-26.1%2C7.7-35.9%2C21.8-9.9%2C14.1-16.3%2C34.3-16.3%2C56.8s6.5%2C42.7%2C16.3%2C56.7c9.9%2C14.1%2C22.5%2C21.8%2C35.9%2C21.8s26-7.7%2C35.9-21.8c9.9-14.1%2C16.4-34.2%2C16.4-56.7s-6.5-42.7-16.4-56.8C263.9%2C8.2%2C251.3.5%2C237.9.5h0ZM87.6%2C43.5c-20.3.6-24%2C13.9-31.8%2C29C32.6%2C117.9.3%2C237.3.3%2C237.3l160.5-5.4%2C29.1%2C137.6-22.8%2C106h149.1l-22.3-106%2C24.2-137.5%2C157.5%2C5.3s-32.3-119.4-55.6-164.8c-7.8-15.1-11.5-28.5-31.8-29-17.9%2C0-32.4%2C15.6-32.4%2C34.7s14.5%2C34.7%2C32.4%2C34.7%2C7.3-.9%2C10.6-2.1l7.9%2C74.4-116.9-40.1c-.3.4-.6.9-.8%2C1.3-12.4%2C17.7-30.6%2C29.7-51.2%2C29.7s-38.8-12-51.2-29.7c-.3-.4-.5-.8-.8-1.2l-116.8%2C40%2C7.9-74.4c3.3%2C1.2%2C6.9%2C2.1%2C10.6%2C2.1%2C17.9%2C0%2C32.4-15.6%2C32.4-34.7s-14.5-34.7-32.4-34.7h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-provocation: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20471%20471%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M85.1%2C37.9v11.8c.9%2C109.9%2C50.1%2C220%2C147.5%2C314.1l6.5%2C6.3%2C6.5-6.3c96.8-93.9%2C147-204%2C147.8-314.1v-11.7c0%2C0-11.4%2C2.5-11.4%2C2.5-80.3%2C17.7-205.3%2C17.9-285.5%2C0l-11.5-2.6h0ZM119%2C70.4l11.4%2C2.6c61%2C13.6%2C156.7%2C13.5%2C217.7%2C0l11.5-2.5v11.7c-.8%2C84.9-39.6%2C169.9-114%2C242.1l-6.5%2C6.3-6.5-6.3c-74.9-72.4-113-157.3-113.6-242.1v-11.8c0%2C0%2C0%2C0%2C0%2C0ZM340.5%2C93.4c-60.4%2C11.2-141.8%2C11.4-202.2%2C0%2C3.6%2C73.1%2C36.8%2C146.2%2C100.9%2C210.8%2C63.8-64.5%2C97.6-137.8%2C101.3-210.9h0ZM.2%2C229.9l103.4%2C166.3%2C17.9-51.3%2C96.2%2C88.2-103.4-166.3-17.9%2C51.3L.2%2C229.9h0ZM470.8%2C229.9l-96.2%2C88.2-17.9-51.3-103.4%2C166.3%2C96.2-88.2%2C17.9%2C51.3%2C103.4-166.3h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-buff: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20403.4%20469.6%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M4.7%2C400.9l185.5-185.2c6.2-6.2%2C16.2-6.3%2C22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0l185.5%2C185.2c6.2%2C6.2%2C6.2%2C16.5%2C0%2C22.8l-41.5%2C41.2c-6.2%2C6.2-16.2%2C6.3-22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0l-132.8-132.8-132.8%2C132.8c-6.2%2C6.2-16.2%2C6.3-22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0l-41.5-41.2c-6.2-6.2-6.2-16.5%2C0-22.8%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M5.2%2C189.9L190.7%2C4.7c6.2-6.2%2C16.2-6.3%2C22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0l185.5%2C185.2c6.2%2C6.2%2C6.2%2C16.5%2C0%2C22.8l-41.5%2C41.2c-6.2%2C6.2-16.2%2C6.3-22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0L201.9%2C121.2%2C69.2%2C253.9c-6.2%2C6.2-16.2%2C6.3-22.4%2C0%2C0%2C0%2C0%2C0%2C0%2C0L5.2%2C212.7c-6.2-6.2-6.2-16.5%2C0-22.8%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-daggerThrow: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20473.3%20471.3%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0v17.4l133.3%2C133.3c-3.9%2C6.4-5.9%2C13.4-6.3%2C20.1L0%2C43.8v35.8l191.4%2C191.4c-3.3%2C5.7-6.3%2C11.5-9.1%2C17.4L0%2C106v39l171.3%2C171.3c-2.2%2C6.7-4.1%2C13.6-5.8%2C20.6L0%2C171.4v33.6l158.3%2C157.6%2C2.1-2.1h0c0%2C.1%2C13.9-2.7%2C13.9-2.7%2C26.1-5.4%2C50.1-15%2C71.9-27.4%2C66.7%2C66%2C119.5%2C103%2C210.4%2C135.1l16.8%2C5.9-4.6-17.2c-24.8-92.5-69.2-136.4-139.3-206.4%2C13.4-22.5%2C23.5-47.4%2C29-74.9l2.8-13.7%2C1.8-1.8L205.9%2C0h-35l164.6%2C164.6c-7%2C1.7-13.8%2C3.7-20.5%2C6L144.5%2C0h-39.5l182.1%2C182.1c-5.8%2C2.8-11.5%2C5.9-17.1%2C9.2L78.6%2C0h-37.2l129.9%2C129.9c-1.4%2C0-2.7%2C0-4.1%2C0-5.9.3-11.9%2C1.8-17.5%2C4.8L15%2C0S0%2C0%2C0%2C0ZM168.7%2C148.3c5.2-.1%2C10.3%2C1.6%2C15%2C4.3%2C4.7%2C2.8%2C8.5%2C6.7%2C10.4%2C10.4%2C1.9%2C3.7%2C2.1%2C6.6.9%2C9.4l-3.2%2C7.6%2C7.1%2C4.2c17.7%2C10.4%2C31.4%2C22.2%2C44.6%2C37.8l5.9%2C6.9%2C7.1-5.7c22.8-18.3%2C49.7-31.7%2C80.1-39.7-6%2C22.1-14.9%2C42.3-26.6%2C60.7l-4.1%2C6.3%2C5.3%2C5.3c68.3%2C68.3%2C109.3%2C106.9%2C134.3%2C185.3-80-30.5-127.4-65.3-191.1-129l-5.2-5.2-6.3%2C3.8c-17.6%2C10.8-37%2C19.2-57.8%2C24.9%2C7.8-29.2%2C20.3-55.7%2C37.4-77.8l5.5-7.1-6.8-5.8c-16.4-13.8-31.4-27.8-41.4-45.2l-3.3-5.8-6.6%2C1.3c-8.2%2C1.7-17.1-3.5-21.5-12-4.4-8.5-4.8-18.6%2C5.6-28.5%2C4.7-4.5%2C9.8-6.5%2C15-6.6h0ZM267.8%2C247l-16.6%2C17.8c41.4%2C43.6%2C112.4%2C108.9%2C157.8%2C140.7-32-45.9-97.4-117-141.2-158.5h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-weave: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20473.4%20473.1%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M473.4%2C19.9V.1c-89.2-.1-178.5-.1-267.7-.1l138%2C9.7c-6%2C15.4-11.8%2C31.4-15.1%2C47.9-2.8%2C13.7-3.6%2C27.9-.9%2C41.9L188%2C28.6c-1.7-9.8-4.3-19.9-4-28.6h-18.8c-.2%2C6.1.4%2C12%2C1.4%2C17.7L131.8%2C0h-58.1c-6.8%2C11.5-11.7%2C24.3-13.8%2C38.7L13.6%2C0H0v13.1l52.5%2C43.8C33.9%2C65.1%2C15.2%2C78.3%2C0%2C95.5v46.8l64.8%2C83.9c-22.5%2C12.6-46%2C25.8-64.8%2C46.3v51.3l32.2%2C77.7c-11-.2-21.8.9-32.2%2C3.9v19.6c12.2-4.5%2C25.8-5.7%2C40.2-4.5l21.8%2C52.6h20.3l-23.8-57.2c33.2-26.5%2C75.1-43.6%2C118.9-44.1l70.2%2C90.8c-25.2%2C1.4-53.2%2C3.2-76.7%2C10.5h109.5c36.5-59.5%2C75.1-101.7%2C136.1-111.3%2C18.6%2C11.7%2C39.2%2C31.5%2C56.9%2C46.3v-24.3l-49.6-41.4c-3.5-68.9%2C17.1-117.9%2C41.6-151.9l8%2C4v-20.9l-9.5-4.8c-7.9-20.4-13.1-46.8-12.5-73.1.5-27.6%2C7.2-54.9%2C22-75.8ZM180.5%2C45.8l145.3%2C73.8c-29.9%2C27.3-43.5%2C62.8-46.5%2C102.3l-119.1-99.5c-.7-27.3%2C9-56.6%2C20.3-76.6ZM94.6%2C2.1l69.3%2C35.2c-11.5%2C20.3-20.8%2C43.4-22.3%2C69.6l-64.3-53.7c.3-20.5%2C6.6-36.5%2C17.3-51.1ZM5.4%2C118.8c17.7-20.3%2C40.3-40.1%2C63.3-48.4l64.3%2C53.7c-24.2%2C21.4-46.4%2C48.6-59.2%2C83.1L5.4%2C118.8ZM51.1%2C398.1L7.3%2C292.8c20.1-23.3%2C46.9-39.2%2C69.1-51.7l87.3%2C112.9c-41.6%2C3.3-80.6%2C19.8-112.6%2C44.1ZM87.5%2C224.9c13.6-35.7%2C35.3-67.1%2C59.9-88.7l125.8%2C104.9c-39.4%2C22.5-74.7%2C53.8-94.1%2C102.3l-91.6-118.5ZM267.8%2C458.2l-75.3-97.4c20.5-48%2C58.3-86.2%2C96-107l110.8%2C92.5c-58.2%2C14.3-97.3%2C57.5-131.5%2C111.9ZM404.8%2C326.6l-107.6-89.8c5.3-44.7%2C19.8-85.6%2C46.5-108.1l105%2C53.3c-23.7%2C33.9-43.7%2C81.4-43.9%2C144.6ZM432.7%2C95.3c-.5%2C21.5%2C2.4%2C42.6%2C7.6%2C61.5l-89.5-45.5c-7.3-15.7-7.4-32.2-3.9-50%2C3.3-16.2%2C9.7-33.2%2C16.3-50.2l89.5%2C6.3c-13.7%2C23.3-19.5%2C50.9-20%2C77.9Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-recharge: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20471.5%20466%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M238.5%2C0c-3.7%2C0-7.4.1-11.1.27l.8%2C17.98c3.4-.16%2C6.8-.25%2C10.3-.25%2C118.8%2C0%2C215%2C96.2%2C215%2C215s-96.2%2C215-215%2C215c-89.6%2C0-166.35-54.7-198.65-132.6l27.63-8.3-48.43-34.3L0%2C327.3l22.55-6.7c34.63%2C85.2%2C118.35%2C145.4%2C215.95%2C145.4%2C128.6%2C0%2C233-104.4%2C233-233S367.1%2C0%2C238.5%2C0Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M207.7%2C2.04c-13.3%2C1.75-26.1%2C4.6-38.6%2C8.48l5.6%2C17.09c11.4-3.54%2C23.3-6.15%2C35.4-7.75l-2.4-17.82h0Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M150.7%2C17.16c-12.4%2C5.05-24.2%2C11.12-35.4%2C18.12l9.5%2C15.21c10.3-6.44%2C21.2-12.03%2C32.6-16.67l-6.7-16.66Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M98.9%2C46.5c-10.498%2C7.869-20.316%2C16.606-29.35%2C26.12l13.05%2C12.28c8.3-8.77%2C17.4-16.81%2C27-24.06l-4.8-6.57s-5.9-7.77-5.9-7.77Z%22%2F%3E%0A%20%20%3Cpolygon%20points%3D%22168.4%2055.08%20164%2072.52%20381%20128%20385.4%20110.6%20168.4%2055.08%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M56.57%2C87.5c-8.19%2C10.2-15.54%2C21.2-21.94%2C32.7l15.65%2C8.8c5.91-10.7%2C12.69-20.8%2C20.26-30.3l-13.97-11.2Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M184.2%2C96.3c-3.9%2C26%2C2.8%2C55.2%2C14.2%2C79.2%2C6.4%2C13.4%2C14.2%2C25.2%2C21.9%2C33.8%2C4.2%2C4.7%2C8.4%2C8.3%2C12.2%2C10.9l-5.4%2C21.2c-4.6.4-10%2C1.6-16%2C3.7-10.9%2C3.8-23.4%2C10.4-35.4%2C19.1-21.6%2C15.6-41.4%2C37.9-50.4%2C62.6l167.5%2C42.9c3.9-26-2.8-55.2-14.2-79.2-6.4-13.4-14.2-25.2-21.9-33.8-4.2-4.7-8.4-8.3-12.2-10.9l5.4-21.2c4.5-.5%2C10-1.6%2C16-3.7%2C10.9-3.8%2C23.4-10.4%2C35.4-19.1%2C21.6-15.6%2C41.4-37.9%2C50.4-62.6l-167.5-42.9h0Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M25.74%2C137.9c-5.33%2C12-9.7%2C24.4-13%2C37.3l17.48%2C4.2c3.03-11.8%2C7.04-23.2%2C11.95-34.2l-16.43-7.3Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M8.7%2C194.5c-2.09%2C12.5-3.2%2C25.4-3.2%2C38.5v.9l18-.2v-.7c0-12.1%2C1.02-24%2C2.95-35.6l-17.75-2.9Z%22%2F%3E%0A%20%20%3Cpolygon%20points%3D%2296%20338%2091.6%20355.4%20308.6%20410.9%20313%20393.5%2096%20338%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-skewer: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20471.579%20433.759%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M145.157.009c-1.535.012-3.06.03-4.595.063-14.17.307-28.304%2C1.539-42.313%2C3.687h-.03C57.749%2C9.967%2C30.043%2C29.072%2C14.812%2C53.759-.418%2C78.446-3.213%2C108.023%2C3.282%2C135.039c6.492%2C27.02%2C22.268%2C51.823%2C45.405%2C67.126%2C23.137%2C15.304%2C53.82%2C20.5%2C87.156%2C8.564%2C88.876-31.822%2C154.224-18.526%2C202%2C22.125%2C47.297%2C40.24%2C77.402%2C109.05%2C90.25%2C190.53%2C9.29%2C10.237-.1.206%2C9.657%2C10.375%2C9.74-8.25-.16-.032%2C9.593-8.406%2C49.368-122.298%2C18.986-236.885-52.062-315.69C333.647%2C41.304%2C241.777-.739%2C145.157.01h0ZM274.875%2C69.539l90.687%2C36.345c4.922%2C4.69%2C9.668%2C9.56%2C14.25%2C14.563-4.09-2.25-8.194-3.45-11.938-3.563-10.212-.307-17.585%2C7.21-13.593%2C21.875%2C8.252%2C30.456%2C55.747%2C34.927%2C45.187%2C5.5%2C9.34%2C12.627%2C17.642%2C26.007%2C24.75%2C40.03-6.273-8.833-12.323-12.982-17.342-13.093-13.9-.306-19.88%2C30.236-.875%2C77.188%2C20.765%2C51.37%2C43.424%2C59.815%2C45.906%2C31.438%2C3.183%2C34.31-.184%2C70.722-11.408%2C108.437-15.63-70.58-45.05-130.96-90.53-169.656-14.414-12.265-30.428-22.22-48-29.532l-40.907-22.313%2C77.53%2C2.938-111.25-56%2C102.22%2C5.03-54.687-49.187Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stomp: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20479.431%20431.976%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M200.128%2C0c-6.348.01-13.056.447-20.006%2C1.32-34.6%2C4.347-75.144%2C19.348-107.408%2C47.303l33.47%2C190.197.33%2C10.1c42.262%2C15.79%2C100.808%2C24.565%2C152.873%2C24.272%2C27.192-.154%2C52.657-2.762%2C72.982-7.8%2C20.325-5.04%2C35.188-12.803%2C41.803-20.917l.433.353c-14.317-48.847-60.635-88.597-135.474-56.27-12.09%2C5.612-24.333%2C12.902-36.332%2C21.685%2C11.24-16.29%2C23.786-29.055%2C36.76-38.453l.013-.12-27.066-14.183-35.343%2C25-10.793-15.256%2C27.546-19.484-27.5-14.41%2C8.67-16.554%2C35.964%2C18.842%2C34.57-24.457%2C1.62-16.186-30.2-17.918-35.16%2C22.433-10.05-15.757%2C27.208-17.36-27.97-16.595%2C9.538-16.072%2C36.08%2C21.408%2C37.088-23.664C255.227%2C10.847%2C232.294-.053%2C200.128%2C0h0ZM251.21%2C55.262l-16.522%2C10.54%2C14.602%2C8.665%2C1.92-19.205ZM243.157%2C135.802l-13.517%2C9.563%2C11.936%2C6.254%2C1.58-15.816h.001ZM378.727%2C265.712c-10.84%2C8.135-25.243%2C13.7-41.86%2C17.82-22.375%2C5.546-49.07%2C8.188-77.373%2C8.347-21.232.12-43.344-1.15-65.117-3.76l12.463%2C22.137c80.16%2C9.438%2C141.51-1.205%2C172.035-21.796.718-7.44.658-15.098-.15-22.75l.002.002ZM107.174%2C269.024l.996%2C30.464%2C58.595%2C8.456%2C9.58-22.312c-24.54-3.827-48.202-9.383-69.17-16.607h-.001ZM74.044%2C290.584c-2.51.75-4.906%2C1.515-7.175%2C2.3H19.352l24.928%2C11.085L0%2C329.599l45.677-4.822c2.33%2C1.773%2C5.212%2C3.498%2C8.62%2C5.166l-29.19%2C44.532%2C64.785-32.977c4.21.968%2C8.64%2C1.892%2C13.27%2C2.773l-10.733%2C66.783%2C61.413-59.744c5.551.539%2C11.108%2C1.017%2C16.67%2C1.435l11.673%2C77.528%2C50.93-75.073c2.03.013%2C4.05.034%2C6.096.034%2C2.436%2C0%2C4.85-.022%2C7.265-.04l56.216%2C76.782%2C6.903-79.364c5.663-.437%2C11.218-.92%2C16.625-1.457l60.782%2C59.9-10.762-66.976c4.528-.872%2C8.86-1.787%2C12.98-2.743l65.102%2C33.14-29.437-44.913c3.135-1.58%2C5.808-3.21%2C7.984-4.88l46.562%2C4.915-44.253-25.613%2C24.966-11.1h-48.592c-2.223-.77-4.564-1.52-7.016-2.253%2C5.408%2C3.254%2C8.34%2C6.724%2C8.34%2C10.326%2C0%2C18.587-77.737%2C33.652-173.627%2C33.652s-173.627-15.065-173.627-33.652c0-3.62%2C2.96-7.105%2C8.418-10.373h.004Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-endGame: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20450.584%20480.223%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M224.141.008c-23.24.42-47.45%2C10.39-67.124%2C31.218%2C54.09-11.145%2C69.053%2C9.38%2C78.844%2C43.22%2C16.83%2C58.176-66.19%2C70.523-60.156-10.53-25.37%2C15.966-34.08%2C52.878%2C0%2C85.28%2C22.675%2C21.555%2C13.393%2C52.563-13.406%2C52.563-44.735.186-107.775-75.315-59.594-139.594-35.413%2C13.593-59.442%2C25.662-67.72%2C59.593-7.1-29.47%2C6.47-55.563%2C31.532-68.344-101.978%2C7.38-74.16%2C112.918-.594%2C134.31%2C65.69%2C19.1%2C4.9%2C108.815-49.062%2C29.782-5.833%2C112.267%2C64.145%2C131.99%2C136.094%2C181.063%2C31.776%2C21.673%2C46.344%2C34.713%2C46.344%2C55.25%2C0%2C35.486%2C52.656%2C35.953%2C52.656-3.156%2C0-21.18%2C18.167-34.655%2C53.406-56.783%2C57.705-36.23%2C102.22-91.155%2C102.22-130.218%2C0-69.113-42.904-90.754-107.158-118.658%2C53.15%2C59.41-40.205%2C83.995-57.718%2C42.282-15.19-36.18%2C6.475-59.857%2C33.656-61.406%2C69.004-3.936%2C92.73-81.274%2C43.03-116.844%2C11%2C20.999%2C5.597%2C43.889-12.84%2C60.129C298.083%2C25.223%2C263.711.319%2C226.394.008c-.75-.01-1.5-.011-2.25%2C0h-.003ZM417.736%2C48.32c-69.183%2C65.477%2C18.182%2C64.61-2%2C159.625%2C84.92-109.75-14.143-112.042%2C2-159.625ZM277.206%2C225.383c1.255-.01%2C2.5.026%2C3.75.093%2C3.396.185%2C6.76.636%2C10.06%2C1.376%2C26.422%2C5.92%2C48.41%2C29.86%2C49.5%2C64.656%2C1.15%2C36.58-25.886%2C65.358-52.06%2C89.157-13.09%2C11.898-26.29%2C22.706-36.47%2C32.374s-16.868%2C18.497-18.25%2C23.656l-9.03%2C33.688-9-33.688c-1.71-6.376-8.278-15.138-18.158-24.688s-22.696-19.988-35.5-31.5c-25.607-23.023-52.243-51-53.437-88.406-1.135-35.56%2C21.576-59.654%2C48.594-65.187%2C23.2-4.753%2C49.572%2C3.38%2C67.47%2C24.624%2C14.32-17.327%2C33.69-26.03%2C52.53-26.156h.001ZM257.142%2C291.07c-11.997.282-24.43%2C6.9-32.5%2C20.875-19.384-33.576-68.84-24.852-67.56%2C15.28%2C1.333%2C41.796%2C61.125%2C66.135%2C67.56%2C90.158%2C5.894-21.984%2C68.665-50.103%2C67.408-90.157-.736-23.43-17.37-36.567-34.907-36.155h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-riposte: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20463.712%20463.128%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M231.856%2C0l-6.252%2C41.475c-40.904%2C1.6-81.38%2C16.64-114.233%2C45.137L29.701%2C25.982l60.593%2C82.1c-28.1%2C33.614-42.45%2C74.828-43.054%2C116.206L0%2C231.272l47.573%2C7.17c2.384%2C38.934%2C16.966%2C77.26%2C43.765%2C108.758l-61.635%2C83.51%2C83.33-61.864c32.178%2C27.257%2C71.444%2C41.798%2C111.19%2C43.647l7.63%2C50.635%2C7.473-50.55c.853-.03%2C1.707-.052%2C2.56-.093-.843-.038-1.683-.09-2.524-.14l16.193-109.53c6.912-2.247%2C13.462-5.484%2C19.445-9.61l44.186%2C24.788-24.934-43.953c4.012-5.768%2C7.197-12.069%2C9.463-18.72l159.997-24.05-45.147-6.654c-.54-42.053-15.258-83.957-44.194-117.907l59.556-80.22h-.002l-80.392%2C59.333c-33.289-28.502-74.271-43.302-115.556-44.422L231.857%2C0h-.001ZM249.461%2C74.522c43.267%2C0%2C86.536%2C16.507%2C119.548%2C49.52%2C28.136%2C28.136%2C44.273%2C63.723%2C48.428%2C100.41l-113.322-16.705c-2.23-6.922-5.452-13.485-9.565-19.483l24.636-43.424-43.223%2C24.522c-6.295-4.49-13.244-7.984-20.603-10.358l-12.47-84.343c2.19-.084%2C4.38-.138%2C6.57-.138h0ZM220.241%2C77.062l-12.412%2C82.34c-6.777%2C2.308-13.19%2C5.571-19.046%2C9.69l-42.748-24.254%2C24.107%2C42.975c-4.229%2C6.068-7.541%2C12.726-9.83%2C19.76l-78.146%2C11.553c5.06-34.793%2C20.974-68.312%2C47.746-95.084%2C25.55-25.55%2C57.246-41.206%2C90.33-46.98h0ZM80.394%2C243.388l80.318%2C12.105c2.338%2C6.798%2C5.637%2C13.227%2C9.796%2C19.09l-24.826%2C43.76%2C43.963-24.942c5.566%2C3.795%2C11.616%2C6.826%2C17.988%2C9.012l16.325%2C108.306c-34.42-5.222-67.54-21.073-94.045-47.58-33.063-33.062-49.568-76.415-49.517-119.75h-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-deflect: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20472.844%20459.2%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M.38%2C0l-.38%2C27.84%2C267.127%2C154.75-58.703%2C19.916%2C57.602%2C19.36-142.886%2C142.223-19.214-19.213-51.47%2C114.324%2C123.125-43.482-17.492-18.95%2C151.868-151.87%2C12.433%2C43.078%2C22.976-68.5%2C56.675-16.565-57.475-15.492-22.934-79.828-14.145%2C48.266L38.837.447.383%2C0h-.003ZM351.634%2C62.483c-4.53.02-9.035.12-13.51.302-3.275.134-6.528.32-9.76.547l31.25%2C108.786%2C104.05%2C28.045c6.204-39.085%2C8.902-80.275%2C9.18-120.075-35.454-10.725-76.726-17.288-116.674-17.595-1.512-.012-3.025-.015-4.537-.01h.001ZM314.764%2C64.583c-31.99%2C3.653-61.013%2C12.153-83.014%2C25.87l64.493%2C37.31%2C18.52-63.18h.001ZM462.944%2C204.58l-102.966%2C30.093-38.93%2C116.054-20.268-70.225-39.07%2C39.067c18.814%2C35.364%2C46.1%2C62.287%2C86.175%2C77.604%2C47.473-17.834%2C78.566-62.795%2C98.014-121.6%2C7.323-22.14%2C12.905-46.11%2C17.042-70.993h.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-emberStrike: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill%3D%22%23000%22%20d%3D%22M407.47%2020.85c10.26%2016.748%2017.462%2036.09%2019.856%2056.65-32.396-44.636-58-40.276-96.36-25.697%2065.992%209.776%20101.33%2067.377%2096.36%20140.75%2048.848-61.72%2034.92-160.814-19.857-171.703zm-276.167%202.896c-.987-.002-1.985.006-2.994.024h-.003c-34.522.598-107.756%2026.213-104.54%20101.037%2021.08-55.636%2065.886-58.685%20104.54-32.123%2046.407%2031.894%2022.075%2098.348-16.936%20100.45%2011.637-17.33%2017.04-40.65%202.974-55.29-24.895-25.91-54.777%204.487-55.533%2029.594-1.403%2046.62%2045.44%2068.116%2075.336%2060.738%2030.192-7.45%2050.092%2012.416%2036.795%2051.976-15.056%2044.795-121.114%2075.948-133.155-8.173%201.7%2088.73%2043.248%20129.87%20104.54%2098.114%2041.467-21.487%2078.87%2018.96%2074.17%2054.896-32.792-37.747-82.098%2017.986-38.544%2040.883%2078.98%2041.522%20199.4%2040.194%20265.73-23.945%2064.735-62.6%2060.833-175.215%2012.263-259.89-5.614%2026.608-28.43%2052.367-74.17%2067.163%2059.262-77.482%202.572-206.85-129.652-174.036%2084.2%204.683%2073.567%20108.248%205.257%20105.123-62.264-2.848-.79-156.296-126.074-156.54zM277.508%20230.22c-56.683%2051.454%2015.914%20153.65%2088.95%20141.837-33.543-9.43-64.745-51.995-54.833-100.05%2031.558%2066.125%20129.923%2066.127%20137.49-16.85%2029.98%2068.665%2013.327%20147.842-36.478%20182.18-58.45%2040.295-156.124%2024.466-181.955-58.83%2019.527%2019.775%2058.78%2032.23%2082.654%2028.722-92.908-26.93-106.546-145.142-35.828-177.01zM24.68%20355.77c-16.486%20116.72%2099.137%20117.28%20130.425%2029.306-48.323%2024.538-100.24%2029.99-130.425-29.305z%22%2F%3E%3C%2Fsvg%3E'); + --icon-sunder: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20414.937%20467.905%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0v9.344c0%2C102.68%2C10.49%2C205.087%2C41.125%2C288.155%2C30.637%2C83.068%2C82.364%2C147.415%2C163.75%2C169.78l2.22.626%2C2.22-.5c89.269-19.03%2C141.643-83.64%2C170.372-167.56%2C28.728-83.92%2C35.25-187.777%2C35.25-290.5V0H0ZM18.814%2C18.688h377.34c-.413%2C98.8-7.497%2C197.342-34.125%2C275.125-27.21%2C79.487-73.39%2C136.637-154.375%2C154.78-73.28-21.03-119.914-78.696-149-157.562C30.179%2C213.819%2C19.448%2C116.901%2C18.811%2C18.687h.003ZM37.624%2C37.438c.807%2C84.13%2C12.486%2C172.823%2C39.314%2C244.812%2C7.825%2C20.998%2C16.874%2C40.495%2C27.25%2C58.063l45.844-38.438-40.75-75.063-5.47-10.062%2C10.97-3.344s38.865-11.786%2C60.406-18.25l20.437-7.25L100.782%2C37.438s-63.158%2C0-63.158%2C0ZM197.874%2C37.438l45.782%2C91.5%2C132.407-43.157c.69-16.205%2C1.053-32.366%2C1.155-48.344h-179.344ZM375.031%2C105.781l-122.906%2C40.064%2C24.908%2C49.78%2C25.875%2C48.72%2C53.28-1.845c10.245-42.834%2C16.03-89.664%2C18.844-136.72h0ZM265.002%2C212.845l-30.75%2C10.374%2C67.25%2C145.187c17.813-23.2%2C31.737-51.6%2C42.624-83.686%2C2.578-7.595%2C4.966-15.39%2C7.19-23.344l-53.626%2C1.844-5.844.22-2.75-5.158-24.094-45.437h0ZM165.782%2C217.531c-13.133%2C3.972-27.346%2C8.262-34.625%2C10.47l38.937%2C71.654%2C3.625%2C6.72-5.844%2C4.906-53.56%2C44.906c24.67%2C35.91%2C55.887%2C61.828%2C94.655%2C73.125%2C30.34-6.91%2C55.36-21.496%2C76.03-42.062l-119.216-169.72h-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-aimedShot: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20471.624%20471.626%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M245.157.002v57.75c91.033%2C4.56%2C164.143%2C77.686%2C168.717%2C168.718h57.75C466.989%2C103.35%2C368.279%2C4.62%2C245.156%2C0v.002ZM226.467.032C103.607%2C4.964%2C4.654%2C103.558%2C0%2C226.471h58.377c4.56-90.824%2C77.346-163.827%2C168.09-168.687V.032ZM236.157%2C107.252c-32.23%2C0-61.768%2C11.79-84.408%2C31.312l22.47%2C22.47c12.541-10.451%2C27.53-17.548%2C43.562-20.626l18.78%2C70.53%2C18.75-70.374c15.581%2C3.119%2C30.149%2C10.044%2C42.407%2C20.156l22.345-22.344c-22.465-19.41-51.782-31.125-83.906-31.125h0ZM333.281%2C151.595l-22.344%2C22.345c10.19%2C12.371%2C17.139%2C27.085%2C20.22%2C42.813l-70.095%2C18.687%2C70.125%2C18.656c-3.095%2C15.954-10.12%2C30.885-20.438%2C43.44l22.344%2C22.342c19.513-22.637%2C31.312-52.154%2C31.313-84.375%2C0-32.124-11.716-61.44-31.126-83.906v-.002ZM138.531%2C151.752c-19.478%2C22.446-31.28%2C51.697-31.28%2C83.75s11.885%2C61.6%2C31.467%2C84.22l22.532-22.532c-10.116-12.426-17.016-27.151-20.093-42.875l70.936-18.875-70.906-18.906c3.073-15.502%2C9.909-30.01%2C19.906-42.25l-22.562-22.532h0ZM.031%2C245.159c4.95%2C122.665%2C103.774%2C221.487%2C226.436%2C226.435v-58.34c-90.544-4.852-163.21-77.547-168.06-168.094H.03h0ZM413.843%2C245.159c-4.862%2C90.755-77.85%2C163.575-168.686%2C168.125v58.342c122.924-4.638%2C221.507-103.596%2C226.436-226.468h-57.75ZM236.563%2C259.909l-18.97%2C71.28c-16.208-3.188-30.995-10.455-43.22-20.687l-22.436%2C22.437c22.618%2C19.582%2C52.072%2C31.47%2C84.22%2C31.47s61.304-11.803%2C83.75-31.283l-22.345-22.343c-11.955%2C9.914-26.296%2C16.98-42.03%2C20.217l-18.97-71.093v.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-frostStrike: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476.75%20478.532%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M1.376.001v44.03l74.157%2C33.28-4.657%2C29.22%2C44.968%2C46.72-26.28%2C64.81%2C168.78%2C55.5v.564l-41.467%2C12.28%2C32.687%2C74.75-40.28-37.374-32.72-4.094-54.875-37.97%2C39.125%2C61.908%2C43.78-.563%2C52.564%2C47.876%2C33.312-7%2C186.28%2C94.594-42.623-87-29.188-127.906-38.563-37.375-9.343-48.47-34.44-32.72%2C12.25%2C74.19%2C56.064%2C63.06-11.094%2C39.126-14.156-41.156-35.5-15.25-26.063%2C18.625%2C54.095%2C32.53-84.094-21.592%2C18.126-38.563-62.812-47.656-23.406-144.47-48.125-15.186%2C9.937%2C65.406%2C28.03%2C3.937-44.968%2C35.5-21.03-110.124-48.47-11.094L73.909%2C0H1.376ZM97.032.001l5.624%2C13.155%2C68.97%2C18.97L138.876%2C0h-41.845.001ZM172.532.001l32.53%2C37.093-.813-37.094h-31.717ZM240.187%2C2.625l-15%2C38.5%2C6.72%2C33.562%2C23.25-33.562s-14.97-38.5-14.97-38.5ZM347.875%2C4.655l-36.532%2C7.846%2C14.314%2C36.81%2C22.22-44.655h-.002ZM344%2C61.187l-7.47%2C36.188%2C30.909-6.094-23.438-30.094h-.001ZM1.375%2C67.437v41.406l62.938-14.124L1.375%2C67.439v-.002ZM252.718%2C77.187l.125%2C33.813%2C56.94%2C54.593-23.22-83.22-33.844-5.187h-.001ZM50.688%2C115.625l-37.97%2C12.625%2C74.625%2C26.686-36.655-39.312h0ZM248.188%2C134.969l9.53%2C68.062%2C56.406%2C40.656-5.156-53.437-60.78-55.282h0ZM3.188%2C142.719l65.875%2C71.842%2C12.344-40.686L3.187%2C142.719h.001ZM11.688%2C196.937L0%2C236.657l41.374-14.126-29.687-25.594h0ZM50.063%2C233.061l-17.094%2C28.25%2C32.063%2C13.94%2C69.686-25.19-84.656-17h0ZM182.657%2C265.906l-52.438%2C1.25%2C51.125%2C36.344%2C24.032-2.47-22.718-35.125h0ZM27.001%2C279.501l-19.626%2C28.374%2C37.22%2C1.812-17.594-30.187h0ZM79.469%2C305.031l20.313%2C30.875%2C17.56-26.156-37.874-4.72h.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stormStrike: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20474.18%20474.86%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0v39.72l130.88%2C73.84%2C94.9-45.12L130.28%2C0H0ZM196.98.1l95.3%2C57.34c-86.5%2C41.22-177.9%2C84.62-255.47%2C121.52l161.57%2C86.1%2C59.6-39.2-39.4-34.9c82.3-40.6%2C168.3-83.5%2C241.8-119.93L366.78.1h-169.8ZM341.18%2C151.16l-76.5%2C37.9%2C44.9%2C25.3c-54.2%2C35.6-111.8%2C73.6-160.6%2C105.7l325.2%2C154.8-187.4-147.2c57.6-32.3%2C117.5-65.9%2C168.8-94.6l-114.4-81.9ZM354.38%2C311.26l-33.9%2C18.9%2C139.3%2C74.3c-35.1-31.1-70.3-62.2-105.4-93.2h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-wildGrowth: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20475.673%20460.531%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M73.056%2C0c-11.966.114-21.575%2C10.038-27.69%2C34.406-1.684-.12-3.372-.162-5.06-.125-.69.015-1.36.048-2.032.093-55.335%2C3.656-56.578%2C101.698%2C35.622%2C245.313C1.958%2C103.977%2C38.286%2C53.122%2C118.178%2C122.687c-38.505%2C17.613-21.605%2C45.215-5.344%2C73.5-1.287-30.686%2C19.758-38.518%2C24.313-55.563%2C23.737%2C24.213%2C50.402%2C57.545%2C78.656%2C99.907%2C7.393%2C11.091%2C15.04%2C22.011%2C22.936%2C32.75-14.56%2C10.542-7.932%2C33.297-35.656%2C45.217%2C31.126.735%2C54.204-3.397%2C53.313-22.187%2C80.447%2C100.804%2C148.373%2C127.744%2C184.875%2C115-1.53%2C14.002%2C8.962%2C28.752-6.313%2C49.22%2C33.763-18.444%2C52.77-37.19%2C20.375-57.25%2C42.036-35.254%2C14.252-124.714-40.78-181.44%2C52.787-50.407-8.977-89.516-72.22-104.874%2C27.52%2C21.707%2C21.675%2C48.652%2C32.22%2C73-13.708-8.013-28.228-13.7-43.126-16.28-4.14-.718-8.307-1.222-12.5-1.44-71.263-5.38-67.123%2C47.11-.875%2C69.97-31.727-11.35-33.71-67.642%2C16.405-52.03l-.03-.19c86.477%2C40.41%2C130.355%2C169.808%2C84.81%2C177.876-23.083%2C4.09-55.358-11.07-94.06-49.375%2C19.28-4.406%2C31.163-23.904%2C53.78-40.75-15.274-.834-29.638-4.237-41.406-3.937-14.15.36-24.508%2C6.105-28.19%2C28.094-19.554-21.58-40.526-48.67-62.624-81.813C176.982%2C115.462%2C115.534%2C59.446%2C71.43%2C41.125c14.436-5.612%2C29.11-15.96%2C54.406-5.874C106.05%2C14.508%2C87.769-.139%2C73.056.001h0ZM85.806%2C299.875c29.458%2C75.44%2C9.59%2C124.826-60.157%2C113.75%2C111.215%2C39.413%2C130.842-22.563%2C60.157-113.75Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stoneShatter: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20475.394%20475.452%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M137.566%2C0l21.832%2C149.004-83.165-78.248%2C40.946%2C125.732-74.765-6.927%2C39.33%2C68.112h71.87l-11.512-38.73%2C28.125%2C15.234%2C1.17-49.223%2C44.537%2C51.568%2C14.064-78.52%2C17.58%2C60.94%2C57.425-39.846-17.58%2C58.597%2C55.082-22.266-30.912%2C42.248h80.834l37.17-63.13-51.26%2C6.845%2C20.565-85.008-70.873%2C48.905%2C48.37-111.842-95.25%2C51.473-12.266-100.908-51.576%2C104.803-32.53-87.51-18.517%2C18.18L137.567%2C0h0ZM194.796%2C259.61l-48.064%2C34.892%2C20.48%2C27.527-127.039%2C16.723%2C8.42%2C66.527-.506%2C2.99L0%2C428.395v47.057h34.42l47.1-46.206-18.678-74.63%2C46.343-6.1%2C3.358%2C54.933%2C1.685.75%2C39.685%2C32.815-18.117%2C38.437h54.185l5.808-59.415-65.352-26.19-2.673-43.777%2C73.43-9.666-28.182-37.886%2C53.593-38.91h-31.81v.003ZM254.92%2C259.61l49.722%2C58.437-74.63%2C35.61-4.355.222%2C52.588%2C62.935-30.766%2C58.638h72.033l-2.315-73.403-53.628-43.697%2C58.706-28.014%2C73.418%2C17.262-45.13%2C72.213%2C41.003%2C55.112.19.527h69.838l-78.51-55.122%2C14.45-35.62%2C77.86%2C30.75v-34.606l-68.937-15.215%2C18.912-30.26-101.807-23.934-44.103-51.836h-24.54.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-cut: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20468.662%20457.16%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M247.78%2C420.097C553.76%2C472.173%2C295.343%2C4.562%2C0%2C1.235%2C424.473-31.951%2C673.767%2C616.3%2C247.781%2C420.095v.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-doublePersona: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20313.32%20473.23%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M264.14%2C68.04C234.76%2C26.44%2C195.39%2C1.26%2C152.31%2C0v473.23c43.08-1.26%2C82.45-26.44%2C111.83-68.05%2C30.15-42.69%2C49.18-102.41%2C49.18-168.57s-19.02-125.88-49.18-168.57ZM172.94%2C274.31c14.89-50.39%2C46.9-67.83%2C90.46-67.75%2C10.05.02%2C20.72.98%2C31.93%2C2.67.86%2C98.74-54.77%2C57.68-122.39%2C65.08Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M31.94%2C206.564c-10.05.02-20.717.973-31.93%2C2.67-.857%2C98.74%2C54.765%2C57.68%2C122.387%2C65.075-14.887-50.39-46.9-67.83-90.457-67.745Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-ripAndTear: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20478.19%20476.161%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M85.167%2C0c23.14%2C15.444%2C46.098%2C31.27%2C68.55%2C47.572C108.662%2C26.678%2C59.207%2C11.655%2C4.347%2C3.327c46.697%2C26.72%2C91.596%2C55.58%2C135.705%2C85.524-37.203-18.033-77.48-32.22-121.602-41.37%2C58.218%2C34.322%2C109.368%2C72.465%2C154.71%2C114.206-57.34%2C47.213-107.065%2C104.703-147.57%2C174.166%2C27.11-24.29%2C54.91-47.545%2C82.868-70.68C61.742%2C321.033%2C24.85%2C386.683%2C0%2C463.808c20.36-24.62%2C40.988-48.203%2C61.905-70.817%2C44.7-67.485%2C89.567-147.11%2C148.856-170.418-29.61%2C30.708-63.36%2C75.164-98.25%2C118.145%2C40.99-40.437%2C83.09-77.46%2C126.415-111.512%2C61.598%2C70.49%2C110.757%2C149.38%2C152.145%2C235.873-6.738-44.794-16.796-87.384-30.03-127.666l46.444%2C65.53s-26.037-72.69-43.66-101.987c40.76%2C55.91%2C78.208%2C114.428%2C112.328%2C175.205-18.674-89.454-50.512-169.772-98.893-238.224%2C35.144%2C34.93%2C68.816%2C71.31%2C100.93%2C109.045-33.342-76.482-74.81-143.489-126.176-198.309%2C40.224-25.887%2C81.48-49.73%2C123.863-71.783-31.096%2C5.387-61.824%2C12.712-92.006%2C21.934%2C21.836-16.173%2C44.41-32.124%2C67.024-47.523-37.987%2C11.91-74.633%2C25.775-109.067%2C41.433%2C42.668-27.673%2C86.32-53.668%2C131.004-78.602h-.003c-67.47%2C18.055-130.83%2C42.19-188.998%2C73.548C227.537%2C45.89%2C161.821%2C15.893%2C85.168%2C0h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-pounce: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476.174%20448.532%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M272.75.002c29.89%2C36.34%2C55.086%2C74.792%2C74.156%2C115.062-49.052-38.586-105.036-68.945-168.78-89.344%2C40.696%2C29.09%2C78.052%2C61.91%2C110.624%2C97.188-37.52-20.55-74.29-31.632-107.438-34.938%2C33.73%2C14.255%2C77.803%2C44.654%2C111.063%2C83.03.615.987%2C1.208%2C1.987%2C1.78%2C3%2C.03.024.066.042.095.064l-.03.03c-.02-.03-.046-.06-.064-.093-19.063-14.253-54.482-30.81-95.312-40.78-50.3-3.666-101.766.18-154.438%2C11.624%2C60.61%2C5.896%2C118.714%2C18.332%2C172.844%2C37.97-79.658%2C6.653-155.155%2C45.72-217.25%2C121.47%2C37.545-21.421%2C83.49-39.941%2C125.375-48.721%2C40.242-11.185%2C72.465-12.254%2C95.563-6.5.04-.004.085.004.125%2C0l-.032.03c-.03-.007-.06-.022-.093-.03-28.123%2C2.88-74.114%2C16.98-115.53%2C40.688-44.49%2C40.303-83.695%2C98.33-97.22%2C158.78h129.657c22.906-37.08%2C51.314-68.357%2C82.78-93.5-6.392%2C18.97-9.292%2C37.678-9.218%2C55.438%2C12.05-31.583%2C44.076-73.017%2C86.72-96.344%2C11.652%2C22.34%2C32.257%2C39.923%2C58.437%2C46.938%2C49.563%2C13.28%2C100.75-16.278%2C114.03-65.844%2C4.41-16.39%2C4.227-33.677-.53-49.97%2C18.47-69.046-6.238-141.86-56.563-200.842%2C9.922%2C38.16%2C12.75%2C77.235%2C5.844%2C114.47C386.524%2C94.154%2C337.377%2C41.557%2C272.75%2C0v.002ZM211.406%2C410.47l-.03.094.03.03v-.124ZM181.312%2C87.97c-.03-.012-.064-.02-.093-.03l-.032.03c.04.004.084-.004.125%2C0ZM366.062%2C198.095c25.482%2C28.396%2C40.14%2C73.42%2C39.438%2C101.44%2C15.463-40.44%2C16.46-62.094%2C4.97-96.595%2C13.306%2C5.783%2C24.22%2C15.16%2C31.936%2C26.625%2C3.704%2C26.134-8.748%2C63.216-22.375%2C79.313%2C14.565-9.242%2C26.246-21.02%2C35-35.375-.187%2C5.702-1.026%2C11.364-2.5%2C16.875-10.666%2C39.81-51.348%2C63.29-91.155%2C52.625-35.814-9.597-58.406-43.468-54.813-79.157%2C35.783%2C4.916%2C67.725%2C25.49%2C83.375%2C44.876-9.22-30.88-31.59-60.696-69.968-80.72%2C10.98-15.49%2C27.472-26.19%2C46.092-29.905v-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-unstoppable: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476.906%20474.344%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M3.032.001C1.031%2C4.242-.004%2C8.874%2C0%2C13.564%2C0%2C30.85%2C13.93%2C45.108%2C31.093%2C45.657c2.274%2C7.447%2C4.881%2C14.787%2C7.814%2C22-7.123%2C5.912-11.688%2C14.818-11.688%2C24.72%2C0%2C17.628%2C14.465%2C32.124%2C32.094%2C32.124%2C3.66%2C0%2C7.18-.633%2C10.47-1.78%2C5.182%2C6.985%2C10.742%2C13.682%2C16.655%2C20.06-2.03%2C4.2-3.156%2C8.9-3.156%2C13.845%2C0%2C11.376%2C6.042%2C21.443%2C15.06%2C27.156%2C2.909-5.49%2C6.059-10.848%2C9.44-16.06-3.53-2.4-5.814-6.42-5.814-11.095%2C0-7.53%2C5.908-13.438%2C13.438-13.438%2C3.22%2C0%2C6.152%2C1.08%2C8.437%2C2.907%2C4.008-4.724%2C8.221-9.27%2C12.626-13.625-5.65-4.954-13.022-7.97-21.062-7.97-5.922%2C0-11.466%2C1.66-16.25%2C4.5-5.018-5.494-9.74-11.28-14.22-17.313%2C4.218-5.554%2C6.501-12.337%2C6.5-19.312%2C0-17.63-14.495-32.125-32.125-32.125-1.05%2C0-2.1.056-3.125.156-2.628-6.457-4.973-13.026-7.03-19.687%2C9.03-5.712%2C15.093-15.772%2C15.093-27.157%2C0-4.835-1.086-9.434-3.032-13.563H3.032ZM32.125.126c7.53%2C0%2C13.437%2C5.907%2C13.437%2C13.438s-5.908%2C13.437-13.438%2C13.437-13.437-5.907-13.437-13.438S24.594.126%2C32.125.126ZM59.312%2C78.939c7.53%2C0%2C13.438%2C5.907%2C13.438%2C13.437s-5.908%2C13.438-13.438%2C13.438-13.406-5.908-13.406-13.438%2C5.876-13.438%2C13.406-13.438h0ZM284.75%2C90.063c-106.228%2C0-192.125%2C85.93-192.125%2C192.157s85.897%2C192.124%2C192.125%2C192.124%2C192.156-85.898%2C192.156-192.125-85.93-192.158-192.156-192.158v.002ZM381.687%2C144.783c7.52%2C3.186%2C14.892%2C7.89%2C21.625%2C14.624%2C18.858%2C18.858%2C30.55%2C48.69%2C34.53%2C82.53%2C6.007%2C8.252%2C10.547%2C17.502%2C13.25%2C27.595%2C2.466%2C9.2%2C3.035%2C18.644%2C2.345%2C27.908-3.86-7.832-8.59-15.445-14.125-22.72-.77%2C30.396-7.25%2C62.106-19.813%2C90.813%2C3.03-16.998%2C4.635-34.97%2C4.938-54.03.312-19.598-.964-38.772-3.594-57.063-21.342-19.84-49.29-35.61-81.53-44.25-15.274-4.092-30.26-6.445-45.063-6.968%2C44.76-11.995%2C89.006-4.885%2C119.532%2C15.75-7.485-29.017-18.55-54.523-32.095-74.19h0ZM116.999%2C314.969c49.026%2C67.317%2C129.026%2C112.73%2C212.532%2C134.342-8.873%2C2.55-19.25%2C3.037-30.064%2C3.5-75.993%2C3.258-168.286-67.14-182.47-137.843h.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-poisonousSting: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20471.579%20433.759%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M145.157.009c-1.535.012-3.06.03-4.595.063-14.17.307-28.304%2C1.539-42.313%2C3.687h-.03C57.749%2C9.967%2C30.043%2C29.072%2C14.812%2C53.759-.418%2C78.446-3.213%2C108.023%2C3.282%2C135.039c6.492%2C27.02%2C22.268%2C51.823%2C45.405%2C67.126%2C23.137%2C15.304%2C53.82%2C20.5%2C87.156%2C8.564%2C88.876-31.822%2C154.224-18.526%2C202%2C22.125%2C47.297%2C40.24%2C77.402%2C109.05%2C90.25%2C190.53%2C9.29%2C10.237-.1.206%2C9.657%2C10.375%2C9.74-8.25-.16-.032%2C9.593-8.406%2C49.368-122.298%2C18.986-236.885-52.062-315.69C333.647%2C41.304%2C241.777-.739%2C145.157.01h0ZM274.875%2C69.539l90.687%2C36.345c4.922%2C4.69%2C9.668%2C9.56%2C14.25%2C14.563-4.09-2.25-8.194-3.45-11.938-3.563-10.212-.307-17.585%2C7.21-13.593%2C21.875%2C8.252%2C30.456%2C55.747%2C34.927%2C45.187%2C5.5%2C9.34%2C12.627%2C17.642%2C26.007%2C24.75%2C40.03-6.273-8.833-12.323-12.982-17.342-13.093-13.9-.306-19.88%2C30.236-.875%2C77.188%2C20.765%2C51.37%2C43.424%2C59.815%2C45.906%2C31.438%2C3.183%2C34.31-.184%2C70.722-11.408%2C108.437-15.63-70.58-45.05-130.96-90.53-169.656-14.414-12.265-30.428-22.22-48-29.532l-40.907-22.313%2C77.53%2C2.938-111.25-56%2C102.22%2C5.03-54.687-49.187Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-venom: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20477.675%20470.29%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M251.334%2C0c-17.095%2C0-30.953%2C13.86-30.953%2C30.954s13.857%2C30.953%2C30.952%2C30.953%2C30.954-13.857%2C30.954-30.953S268.429.001%2C251.333.001h.001ZM248.564%2C9.33c-1.963.883-3.61%2C2.304-5.22%2C3.915-7.128%2C7.128-7.344%2C18.743-.217%2C25.87%2C7.128%2C7.13%2C18.96%2C7.13%2C26.088%2C0%2C1.707-1.705%2C2.808-3.775%2C3.698-5.87-.526%2C4.734-2.46%2C9.416-6.087%2C13.043-8.487%2C8.487-22.166%2C8.268-30.653-.217h-.002c-8.484-8.483-8.703-22.166-.216-30.65%2C3.48-3.48%2C8.08-5.463%2C12.61-6.09h0ZM159.474%2C11.624c-23.916%2C0-43.302%2C19.384-43.302%2C43.3s19.386%2C43.3%2C43.3%2C43.3c3.23%2C0%2C6.375-.365%2C9.403-1.035%2C1.283%2C15.915%2C14.596%2C28.434%2C30.842%2C28.434%2C17.096%2C0%2C30.953-13.858%2C30.953-30.953%2C0-16.374-12.717-29.77-28.812-30.87.597-2.866.916-5.834.916-8.877%2C0-23.915-19.386-43.3-43.3-43.3h0ZM152.998%2C27.504c-2.674%2C1.203-4.917%2C3.14-7.11%2C5.333-9.717%2C9.716-10.012%2C25.55-.298%2C35.266%2C9.715%2C9.716%2C25.845%2C9.716%2C35.56%2C0%2C2.328-2.327%2C3.827-5.15%2C5.04-8.002-.718%2C6.454-3.354%2C12.837-8.3%2C17.782-11.565%2C11.568-30.216%2C11.27-41.782-.297h-.002c-11.566-11.566-11.863-30.22-.295-41.785%2C4.742-4.743%2C11.014-7.443%2C17.186-8.297h.001ZM307.842%2C64.906c-32.255%2C0-58.402%2C26.147-58.402%2C58.403s26.147%2C58.402%2C58.402%2C58.402%2C58.403-26.147%2C58.403-58.402-26.147-58.403-58.403-58.403ZM196.272%2C76.646c-1.85.83-3.4%2C2.17-4.918%2C3.688-6.72%2C6.72-6.926%2C17.668-.207%2C24.387%2C6.718%2C6.718%2C17.873%2C6.718%2C24.594%2C0%2C1.608-1.61%2C2.642-3.56%2C3.48-5.533-.494%2C4.46-2.317%2C8.873-5.735%2C12.293-8%2C8-20.896%2C7.794-28.895-.205s-8.206-20.895-.207-28.894c3.28-3.28%2C7.618-5.15%2C11.887-5.738v.002ZM301.162%2C79.363c-3.913%2C1.76-7.193%2C4.592-10.404%2C7.803-14.21%2C14.21-14.644%2C37.37-.433%2C51.582%2C14.21%2C14.21%2C37.803%2C14.21%2C52.013%2C0%2C3.402-3.404%2C5.596-7.53%2C7.37-11.704-1.05%2C9.438-4.905%2C18.773-12.137%2C26.006-16.92%2C16.92-44.2%2C16.485-61.118-.434-16.92-16.92-17.353-44.198-.434-61.117%2C6.937-6.936%2C16.11-10.887%2C25.14-12.136h.003ZM205.038%2C147.433c-23.87%2C0-43.22%2C19.348-43.22%2C43.217s19.35%2C43.22%2C43.22%2C43.22%2C43.216-19.35%2C43.216-43.22-19.347-43.215-43.216-43.215v-.002ZM201.518%2C159.236c-2.824%2C1.27-5.192%2C3.316-7.512%2C5.633-10.262%2C10.262-10.572%2C26.98-.31%2C37.242s27.294%2C10.262%2C37.554%2C0c2.456-2.457%2C4.04-5.436%2C5.32-8.45-.756%2C6.815-3.54%2C13.555-8.763%2C18.778-12.215%2C12.215-31.912%2C11.903-44.127-.312h-.002c-12.215-12.215-12.53-31.914-.312-44.13%2C5.008-5.007%2C11.632-7.86%2C18.152-8.76h0ZM283.84%2C227.342c-14.153%2C0-26.078%2C9.5-29.767%2C22.47-5.051-.104-10.102-.16-15.154-.166-64.15%2C0-122.217%2C7.86-165.02%2C20.92-21.403%2C6.53-39.006%2C14.3-51.93%2C23.623-14.435%2C12.847-25.627%2C24.45-20.85%2C42.916%2C5.49%2C36.45%2C32.217%2C68.37%2C70.718%2C91.483%2C43.34%2C26.017%2C102.216%2C41.702%2C167.08%2C41.702s123.74-15.685%2C167.08-41.703c38.48-23.103%2C65.2-55%2C70.71-91.427.707-4.507%2C1.486-9.716.51-14-2.14-11.28-10.294-21-21.344-28.973-12.925-9.324-30.528-17.092-51.93-23.623-25.175-7.682-55.657-13.545-89.524-17.087-2.313-14.808-15.12-26.137-30.578-26.137v.002ZM282.58%2C238.939c-1.85.832-3.4%2C2.17-4.92%2C3.688-6.718%2C6.72-6.923%2C17.668-.204%2C24.387s17.87%2C6.718%2C24.59%2C0c1.61-1.61%2C2.647-3.56%2C3.486-5.534-.496%2C4.464-2.32%2C8.876-5.74%2C12.296-7.997%2C8-20.894%2C7.794-28.893-.205-8-7.997-8.204-20.894-.205-28.893%2C3.28-3.28%2C7.618-5.148%2C11.887-5.737v-.002ZM238.918%2C268.344c5.286%2C0%2C10.512.074%2C15.707.183%2C4.226%2C12.065%2C15.707%2C20.72%2C29.215%2C20.72%2C12.17%2C0%2C22.69-7.023%2C27.748-17.235%2C33.278%2C3.444%2C62.996%2C9.144%2C86.897%2C16.437%2C20.132%2C6.144%2C36.143%2C13.47%2C46.447%2C20.903%2C9.27%2C6.687%2C13.307%2C12.79%2C14.027%2C17.976-.105%2C1.925-.285%2C3.844-.54%2C5.755-1.483%2C4.648-5.58%2C9.927-13.487%2C15.63-2.407%2C1.737-5.137%2C3.468-8.146%2C5.18-60.55-67.602-319.786-71.505-397.23-.867-2.423-1.428-4.647-2.867-6.65-4.312-7.927-5.72-12.026-11.013-13.5-15.67-.248-1.889-.425-3.786-.53-5.688.708-5.192%2C4.744-11.306%2C14.03-18.005%2C10.305-7.434%2C26.315-14.76%2C46.448-20.903%2C40.265-12.287%2C96.956-20.105%2C159.564-20.105h0ZM35.728%2C372.327c10.775%2C5.7%2C23.588%2C10.725%2C38.17%2C15.174%2C42.803%2C13.063%2C100.87%2C20.92%2C165.02%2C20.92s122.22-7.857%2C165.024-20.92c14.576-4.447%2C27.384-9.47%2C38.158-15.167-10.695%2C14.855-26.175%2C28.496-45.725%2C40.232-39.745%2C23.86-95.63%2C39.04-157.46%2C39.04s-117.714-15.18-157.46-39.04c-19.552-11.737-35.033-25.38-45.728-40.238h.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-gore: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20480.155%20476.096%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M161.75%2C0l66.718%2C179.03L3.78%2C3.125l178.344%2C216.406L0%2C141.345l175.186%2C146.56-148.906-11.185%2C183.594%2C85.72-88.875%2C38.936%2C154.155%2C18.094-21.063%2C56.22%2C96.22-34.814%2C32.968%2C35.22%2C28.22-56.22%2C56.06-17.438-28.279-39.313%2C40.875-85-55.344%2C10.563-7.686-146.063-44.406%2C77.5-74.313-181.188%2C1.125%2C140.313L161.751%2C0h0ZM257.624%2C237.03c16.315-.184%2C40.993%2C12.932%2C63%2C34.94%2C29.342%2C29.34%2C42.85%2C63.397%2C30.156%2C76.092-12.695%2C12.696-46.783-.782-76.125-30.125-29.342-29.342-42.85-63.43-30.156-76.125%2C3.173-3.173%2C7.685-4.72%2C13.124-4.78v-.002ZM354.344%2C274.375c37.93%2C3.08%2C67.592%2C34.657%2C67.592%2C73.406%2C0%2C40.8-32.887%2C73.656-73.687%2C73.656-40.057%2C0-72.43-31.67-73.595-71.437%2C8.263%2C23.457%2C30.67%2C40.375%2C56.875%2C40.375%2C33.176%2C0%2C60.25-27.106%2C60.25-60.28%2C0-25.107-15.517-46.69-37.438-55.72h.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-haymaker: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20461%20461%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M126.8%2C71.1l-11.2%2C2.3L94%2C3.9l6.6%2C72.7-10.8%2C2.3L67%2C10l8.4%2C93.1%2C27.2-5.7%2C1%2C4.9c-2.6%2C5.6-5.3%2C14-5.1%2C24.5%2C2.8%2C2.8%2C7.1%2C6.8%2C12.1%2C11.3l63.1%2C322.5%2C17.1-16.4-3.6%2C16.4h37.5s47.9-169.2%2C47.9-169.2l38.3%2C169.3h38.4s-34.2-215.7-34.2-215.7l1.6-16.8%2C77.3-55.9-68.7-75.7-35.2%2C6.1c5.6-8.5%2C9.3-22.3%2C10-36.4%2C7.8.1%2C32.9%2C2.7%2C40.7%2C3-1.6-14.5-20.9-23-39.7-27.1%2C2.8-29.8-4.9-35.3-30.2-36.4-25.3-1.2-32.4%2C7.2-34.2%2C27.9-18.5-.6-43.7%2C6-48.7%2C16.3%2C11.2%2C4.4%2C36.1%2C7.8%2C46.1%2C10.1%2C1.7%2C16.8%2C8.2%2C35.3%2C16.4%2C49.6l-23.4%2C4.1-51.5%2C43.1-52.2-47.8-3.1-15.4%2C28.3-5.9L120.6.3s6.2%2C70.8%2C6.2%2C70.8ZM94%2C3.9h0%2C0s0%2C0%2C0%2C0ZM348.3%2C170l-31.5%2C23.7.3-64.1%2C31.2%2C40.3ZM229.2%2C150.9l4.5%2C95.4-42.8%2C197.5-57.4-285.6c21.9%2C19.1%2C44.9%2C38.5%2C44.9%2C38.5l50.9-45.9h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-charge: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20452%20452%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.4.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%20226)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M320%2C10.2c-44.6.3-96%2C14.5-134%2C36.7-36%2C34.3-32.5%2C92.9-74.7%2C138.8%2C4.4-.3%2C8.8-.6%2C13-1.1h-.3c17.8-2.6%2C32%2C10.4%2C34.7%2C25.1%2C1.4%2C7.3%2C0%2C15.5-5.1%2C22.1-4.5%2C5.9-11.6%2C10.1-20.5%2C11.9%2C14.6%2C31.9%2C32%2C62.2%2C57.1%2C89.1%2C10.7.7%2C23.6-.3%2C31-10.8l-8.5-51.1%2C1.6-2.8c14.1-25%2C15.3-32.2%2C15.7-49.6l.3-10.3c9.3%2C1.5%2C16.5%2C2.7%2C25.9%2C4.1-10.7-13.5-16.2-26.7-17.9-39.4-2.1-18.3%2C6.4-42%2C15.6-62.9l16.3%2C7.6c-7.9%2C17.2-14.8%2C31.9-14.1%2C53%2C2%2C15.2%2C11.2%2C32.5%2C37.4%2C53.4%2C6.7%2C4.3%2C13.2%2C11.7%2C18.1%2C19.3l-4.1%2C5.2c-18.5%2C23.5-33.8%2C45.4-40.3%2C70%2C11.6%2C30.5%2C38.9%2C76.1%2C71.1%2C98%2C12.6%2C2.8%2C38.1-9.6%2C49.1-16.3-7.2-14.4-16.5-27.7-27.7-40l-24.1%2C11.5-1.6-12.3c-1.3-10.1-8.5-17.7-18.4-26.6l-8.6-7.8%2C9.7-6.4c23.4-15.4%2C41.9-24.1%2C51.4-41.2l2.4-3.8%2C7.2-4.4c20.5-12.7%2C40.9-42.4%2C34.2-77l17.7-3.2c5.1%2C28.3-.2%2C52.2-21.3%2C79.2%2C6.8-1.3%2C12.9-2.9%2C18.2-4.8%2C11.8-4.2%2C19.6-9.5%2C24.9-17.1V64.2c-32.2-19-86.5-46.6-131.6-54.1h0ZM20.3%2C143.2c20%2C15.8%2C42.5%2C30.5%2C71.6%2C41.3%2C2.9-6.1%2C5.8-12.2%2C8.8-18.3-27.4-6.1-54.4-14.8-80.3-23h0ZM.4%2C198.2c34.6%2C16.5%2C74.8%2C30.1%2C127.4%2C28.1%2C6.7-.9%2C9.9-3.2%2C11.6-5.5%2C1.7-2.3%2C2.2-5%2C1.7-8-1.1-6.1-6.1-11.7-14.4-10.5h-.2s-.2%2C0-.2%2C0c-40.8%2C4.5-85.1-.4-126-4.3h0ZM165.8%2C274.8c-7.8-9.6-12.2-18.6-12.1-23%2C.1-3.8%2C5.9-9.9%2C9.9-9.9%2C10.4.4%2C4.5%2C24.8%2C2.2%2C32.8ZM177.6%2C306.6c6.2-.4%2C12.2.5%2C18.3%2C3.5%2C3.6%2C4%2C1.6%2C16.1%2C1.6%2C16.1l-19.9-19.6h0ZM222.3%2C345c-2.7%2C1.5-6.3%2C3-9.7%2C4l4.3%2C31.2-10.4-29.9c-3.2.5-6.5.7-9.8.8l5.4%2C31.5s-18.6-13.5-28.4-10.9c-11.2%2C3-22.1%2C27-22.1%2C27%2C0%2C0-8.9-20.4-16.7-17.9-6.2%2C2.1-19%2C44-4.1%2C54.4%2C15.7%2C10.9%2C52-23.9%2C52-23.9%2C0%2C0%2C20.4%2C33.9%2C35.5%2C30.2%2C8.1-2%2C9.5-23.2%2C9.5-23.2%2C0%2C0%2C36.1%2C18.7%2C51.6%2C10.5%2C11.1-5.8%2C14.7-34.4%2C14.7-34.4l-23.2%2C9.1s-5.2-29.9-17.2-33.7c-7.2-2.3-20%2C10.5-20%2C10.5l-11.6-35.5h0ZM376.8%2C352c10.3%2C11.9%2C19.1%2C24.8%2C26.1%2C38.6%2C3.7-2.2%2C7.4-4.3%2C11.1-6.3-7.2-13.5-15.6-26.1-27.2-37.1l-10%2C4.8Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-execute: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20465.223%20475.532%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M290.813.002c-16.917.16-35.992%2C8.394-51.344%2C23.813-25.855%2C25.966-31.416%2C62.47-12.438%2C81.53%2C18.978%2C19.06%2C55.332%2C13.468%2C81.188-12.5%2C25.856-25.967%2C31.416-62.469%2C12.436-81.529C312.945%2C3.571%2C302.387-.106%2C290.813.002ZM0%2C14.94c41.975%2C60.496%2C108.395%2C103.37%2C178.063%2C130.53.768.296%2C1.542.584%2C2.312.876%2C74.676%2C28.292%2C158.988%2C40.7%2C228.22%2C31.875.072-.013.144-.018.217-.03%2C73.4-13.258%2C89.237-60.577-38.562-134.25C533.642%2C191.914%2C128.063%2C169.085%2C0%2C14.941h0ZM194.155%2C171.284c-3.861%2C2.091-7.503%2C4.562-10.874%2C7.375-12.204%2C10.163-20.78%2C24.71-26.75%2C42.187-10.988%2C32.16-12.56%2C73.362-13.375%2C109.563h40.064l.625%2C8.656%2C10.218%2C136.467h86.687l9.03-136.406.595-8.717h38.53c1.694-40.387-.062-81.073-12.25-111.594-3.295-8.256-7.23-15.796-12-22.5-36.92-4.4-74.495-12.92-110.5-25.032h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-boom: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20484.61%20481.972%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M150.528%2C0l86.455%2C98.443c2.138-1.109%2C4.295-2.18%2C6.47-3.215%2C14.37-6.805%2C27.684-11.083%2C39.76-12.103.75-.064%2C1.498-.113%2C2.243-.15L224.343%2C0h-73.815ZM0%2C52.75v27.722l.21-.25%2C128.432%2C107.3c3.31-3.817%2C6.687-7.576%2C10.127-11.276L0%2C52.752v-.002ZM287.897%2C101.585c-.982.017-2.017.07-3.11.163-8.734.738-20.327%2C4.21-33.337%2C10.37-.564.268-1.146.567-1.715.844l30.996%2C35.295c1.406-.72%2C2.808-1.43%2C4.193-2.1%2C13.245-6.395%2C25.504-10.477%2C36.683-11.554.592-.057%2C1.183-.1%2C1.774-.14l-21.385-29.032-.344.344c-2.62-2.62-6.88-4.304-13.754-4.19h0ZM0%2C104.402v148.353l69.13%2C47.274c.036-.995.088-1.993.172-2.996%2C1.02-12.077%2C5.298-25.392%2C12.104-39.762%2C8.213-17.34%2C20.215-36.21%2C35.324-55.348L0%2C104.403h0ZM326.181%2C153.027c-.875.025-1.802.083-2.784.178-7.853.756-18.432%2C4.027-30.346%2C9.78-23.826%2C11.508-53.028%2C32.712-80.87%2C60.554-27.843%2C27.84-49.048%2C57.044-60.555%2C80.87-5.754%2C11.914-9.025%2C22.494-9.782%2C30.346-.755%2C7.853.795%2C12.184%2C3.197%2C14.586%2C2.402%2C2.402%2C6.735%2C3.952%2C14.588%2C3.196%2C7.852-.757%2C18.432-4.028%2C30.345-9.782%2C7.81-3.77%2C16.202-8.6%2C24.928-14.347-17.195%2C39.23-28.067%2C89.333-34.394%2C153.564%2C37.517-129.093%2C80.838-109.43%2C114.544-6.287-18.62-109.564%2C99.38-61.623%2C185.008%2C5.397-66.417-101.782-124.625-177.518%2C4.55-188.135-124.058-5.07-140.995-44.53-21.876-102.653-58.372%2C6.19-105.555%2C15.9-143.54%2C32.65%2C4.806-7.536%2C8.915-14.8%2C12.206-21.613%2C5.754-11.914%2C9.023-22.494%2C9.78-30.346.756-7.852-.794-12.183-3.196-14.585-1.8-1.8-4.688-3.122-9.332-3.352-.823-.039-1.647-.046-2.47-.02h0ZM152.739%2C188.677c-3.353%2C3.61-6.6%2C7.226-9.734%2C10.842l37.066%2C30.97c2.872-3.275%2C5.795-6.504%2C8.768-9.687l-36.1-32.125h0ZM295.009%2C189.794c3.84.122%2C6.953%2C1.23%2C9.142%2C3.42%2C6.837%2C6.836%2C3.118%2C22.676-8.182%2C41.52-29.24%2C17.088-52.02%2C39.92-69.58%2C70.706-20.12%2C12.694-37.26%2C17.173-44.45%2C9.984-11.437-11.437%2C6.648-48.066%2C40.396-81.814%2C26.365-26.366%2C54.49-43.17%2C70.986-43.81.577-.02%2C1.14-.024%2C1.69-.007h-.002ZM131.109%2C213.932c-14.242%2C18.11-25.428%2C35.748-32.81%2C51.338-6.163%2C13.01-9.634%2C24.602-10.373%2C33.336-.738%2C8.734%2C1.033%2C13.87%2C4.026%2C16.86l-.1.1%2C31.152%2C21.304c.034-1.296.112-2.6.238-3.91%2C1.076-11.177%2C5.158-23.437%2C11.555-36.68%2C7.777-16.104%2C19.084-33.65%2C33.275-51.465l-36.965-30.882h.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-slingshot: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20457.321%20475.274%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M121.2%2C0c-2.838.003-5.676.125-8.5.365-22.6%2C1.92-44.724%2C11.21-61.347%2C26.587-16.32%2C15.096-27.204%2C36.473-26.69%2C61.45%2C3.875-.13%2C9.014-.284%2C14.847-.397%2C1.073-.02%2C2.088-.027%2C3.146-.043-.402-19.627%2C7.798-35.656%2C20.92-47.795%2C13.38-12.377%2C32-20.283%2C50.647-21.867%2C18.517-1.573%2C36.767%2C2.965%2C50.646%2C14.524%2C5.123-2.898%2C10.762-4.77%2C16.602-5.51%2C1.061-.132%2C2.125-.231%2C3.192-.297-2.443-2.757-5.079-5.335-7.89-7.715C160.931%2C5.937%2C141.059-.008%2C121.198.002l.002-.002ZM189.277%2C44.282c-2.986.057-5.93.6-8.842%2C1.477-1.103.255-2.188.579-3.25.972.026.04.05.082.075.12-3.47%2C1.38-6.817%2C3.335-9.692%2C6.35-3.5%2C3.673-6.077%2C9.9-4.693%2C15.998l.094.413.045.144c11.863-10.083%2C27.67-14.763%2C42.444-14.64.3.002.596.024.895.03l-.068-.868-.592-1.374c-2.704-6.274-8.677-8.048-13.11-8.49-1.099-.11-2.204-.154-3.308-.133h.002ZM241.32%2C65.52c-6.248.09-12.4.574-18.474%2C1.378l-.582.54%2C4.716%2C17.102c4.68-.57%2C9.39-.928%2C14.133-1.015%2C1.6-.03%2C3.207-.03%2C4.817%2C0%2C36.413.658%2C76.09%2C16.07%2C122.072%2C59.433l15.937-9.623c-49.936-48.12-95.313-67.04-137.684-67.806-1.652-.03-3.297-.035-4.936-.01h.001ZM189.03%2C76.115c-6.7%2C2.283-12.923%2C5.844-17.354%2C10.447l2.01%2C10.578c4.8-7.386%2C9.9-14.41%2C15.345-21.025h0ZM207.627%2C82.068c-4.65%2C5.218-9.075%2C10.81-13.297%2C16.738%2C5.564-1.297%2C11.307-1.985%2C17.088-2.13-.102-.656-.203-1.312-.3-1.958l-3.49-12.65h0ZM153.86%2C89.22c-10.62%2C5.178-21.06%2C10.89-31.368%2C16.828l14.736%2C8.645-.23-.047c.64.353%2C1.372.707%2C1.754%2C1.027.528.443.905.83%2C1.213%2C1.19%2C5.797-3.22%2C11.592-6.312%2C17.392-9.227l-3.497-18.416ZM44.352%2C105.976c-1.61.018-2.815-.007-4.496.025-8.207.16-14.15.39-16.605.478-2.228%2C1.913-6.242%2C5.488-11.158%2C11.178C5.463%2C125.327-.075%2C135.255%2C0%2C140.981c.095%2C7.15%2C3.73%2C19.28%2C9.736%2C30.228%2C6.007%2C10.948%2C14.408%2C20.872%2C21.87%2C25.426.002%2C0%2C2.58.932%2C6.513%2C1.07%2C3.934.138%2C9.176-.22%2C15.04-1.04%2C11.728-1.64%2C25.992-5.075%2C39.117-9.215%2C8.666-2.735%2C16.262-5.755%2C22.9-8.71-17.423-3.064-34.79-11.906-48.413-23.3-9.947-8.318-17.986-18.11-21.704-29.304-2.151-6.515-2.397-13.51-.707-20.16h0ZM214.482%2C114.572c-13.804-.118-26.667%2C3.534-35.956%2C11.37.29%2C1.234.584%2C2.44.873%2C3.696%2C7.614%2C33.128%2C13.767%2C73.212%2C9.864%2C97.246-5.603%2C34.496-31.537%2C84.64-56.23%2C125.106-14.89%2C24.398-29.136%2C45.285-38.177%2C58.144%2C10.07-.018%2C20.817%2C2.73%2C31.086%2C7.26%2C11.084%2C4.89%2C21.573%2C11.887%2C29.23%2C20.914%2C1.474%2C1.737%2C2.831%2C3.57%2C4.06%2C5.488%2C1.36-3.347%2C2.576-6.353%2C4.36-10.703%2C5.542-13.528%2C13.064-31.452%2C21.98-50.63%2C17.835-38.352%2C41.727-81.852%2C64.653-103.98%2C25.013-24.14%2C74.933-49.443%2C118.108-67.835%2C6.201-2.638%2C12.426-5.216%2C18.676-7.735-4.533-14.565-13.66-26.322-24.893-37.757-.622.35-1.232.7-1.86%2C1.052-35.47%2C19.846-79.24%2C38.213-106.96%2C35.963-3.385-.274-8.838-3.985-12.028-8.44-11.913-16.64-21.224-49.812-26.786-79.158h0ZM108.14%2C118.5c-.125.142-.195.26-.324.406-3.408%2C3.85-7.99%2C8.477-12.875%2C13.076-4.585%2C4.317-9.376%2C8.534-13.716%2C11.965%2C14.612%2C11.06%2C34.845%2C18.494%2C49.54%2C17.9.08-3.49-.12-7.653-.57-11.81-.688-6.327-1.887-12.74-3.016-17.247-.32-1.28-.697-2.544-1.13-3.79l-17.908-10.5h0ZM430.496%2C123.7c-2.163.02-4.4.502-6.305%2C1.614l-.428.252-.4.297s-2.87%2C2.124-7.9%2C5.642c14.61%2C14.434%2C22.734%2C32.15%2C28.22%2C50.262l4.314-1.457-.045.012c3.98-1.237%2C7.185-4.906%2C8.28-7.91%2C1.197-3.282%2C1.194-6.115.98-8.954-.425-5.676-2.144-11.535-4.497-17.277-2.354-5.742-5.26-11.186-9.092-15.605-1.915-2.21-4.043-4.27-7.263-5.73-1.61-.73-3.7-1.168-5.86-1.146h-.004ZM393.148%2C148.802l-13.875%2C8.377c5.383%2C5.814%2C10.47%2C12.035%2C14.83%2C18.9%2C1.41-8.554%2C1.554-17.292-.955-27.278h0ZM412.553%2C156.257c1.144%2C12.08-.52%2C22.994-2.93%2C33.05l15.717-5.33c-3.235-10.06-7.23-19.383-12.787-27.72h0ZM94.61%2C428.134c-.444%2C0-.878.012-1.3.03-6.752.316-9.117%2C1.857-10.17%2C4.693l-2.212%2C5.965c.14%2C4.046%2C1.104%2C8.02%2C2.834%2C11.68%2C3.7%2C7.818%2C10.09%2C14.155%2C17.732%2C18.603s16.732%2C7.043%2C26.115%2C5.9c7.178-.874%2C14.383-4.265%2C20.183-10.12.164-4.882-1.947-9.743-6.35-14.935-5.278-6.223-13.748-12.11-22.765-16.087-8.454-3.73-17.418-5.75-24.07-5.73h.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dragonBreath: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20481.231%20480.65%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0v61.32c76.696%2C54.194%2C157.847%2C147.575%2C64.827%2C125.566%2C57.116%2C55.067%2C104.12%2C26.786%2C174.037%2C135.492%2C30.42%2C47.297%2C7.473%2C80.54-29.785%2C90.524-47.88%2C12.828-114.353-30.45-57.82-54.314-59.296-1.45-66.954%2C47.977-38.727%2C80.237-27.93-9.635-46.01-34.308-43.034-60.605-36.043%2C48.278-5.362%2C93.284%2C54.313%2C102.43h357.42V136.08c-15.752-70.31-94.876-87.764-103.372-3.504%2C14.61-36.423%2C50.96-20.625%2C84.1%2C18.688-11.28-7.498-24.24-11.49-36.21-11.097-19.73.65-37.36%2C12.086-41.466%2C36.794%2C55.902-46.113%2C84.628%2C34.717%2C61.74%2C76.876-24.744%2C45.582-94.89-20.467-95.03-75.71-27.974%2C31.235-7.813%2C108.298%2C52.37%2C122.548-114.055-12.382-75.947-130.752-123.035-155.832C309.056%2C272.476%2C106.401%2C49.263%2C50.81.003H0v-.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-hatch: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476.006%20476.007%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M238.525%2C0c-61.262-.17-122.585%2C23.086-169.264%2C69.766C-10.614%2C149.642-21.094%2C271.85%2C36.224%2C363.797c-21.126-58.596-5.07-136.433%2C43.875-204.518-26.864%2C54.274-23.788%2C119.52%2C8.705%2C171.64-16.072-44.577-3.09-104.19%2C35.502-155.568-22.22%2C40.8-20.71%2C91%2C4.105%2C130.804-13.956-38.71%2C1.842-92.823%2C43.24-134.222%2C43.876-43.875%2C102.245-59.39%2C141.206-40.764-39.916-27.966-92.123-30.865-134.612-8.724%2C54.177-39.073%2C116.827-50.336%2C161.063-29.194-52.326-36.654-120.2-41.6-176.747-14.863%2C71.832-49.555%2C153.662-63.29%2C211.87-35.47C333.777%2C14.438%2C286.168.135%2C238.524%2C0h.001ZM374.433%2C42.919l.008.006v-.002s-.006-.003-.008-.004ZM339.308%2C93.251s.004.004.007.006v-.002s-.006-.003-.008-.004h.001ZM433.08%2C101.566c27.828%2C58.21%2C14.094%2C140.048-35.47%2C211.887%2C26.74-56.548%2C21.8-124.425-14.858-176.754%2C21.144%2C44.238%2C9.878%2C106.895-29.2%2C161.075%2C22.145-42.488%2C19.248-94.7-8.714-134.618%2C18.62%2C38.96%2C3.107%2C97.327-40.768%2C141.2-41.4%2C41.4-95.513%2C57.196-134.224%2C43.238%2C39.81%2C24.817%2C90.023%2C26.326%2C130.826%2C4.096-51.383%2C38.602-111.004%2C51.59-155.588%2C35.513%2C52.118%2C32.49%2C117.364%2C35.57%2C171.637%2C8.71-68.085%2C48.943-145.92%2C64.997-204.512%2C43.87%2C91.947%2C57.318%2C214.157%2C46.838%2C294.03-33.037%2C82.987-82.986%2C91.948-212.252%2C26.842-305.18h-.001ZM344.839%2C163.155l-.004-.007h-.002l.006.007ZM382.753%2C136.698l-.004-.007h-.002l.006.007Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-shrug: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20472%20461%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M236%2C0c-11.642%2C0-22.985%2C7.432-32.006%2C21.607-9.02%2C14.176-14.994%2C34.64-14.994%2C57.393s5.973%2C43.217%2C14.994%2C57.393c9.02%2C14.175%2C20.364%2C21.607%2C32.006%2C21.607s22.985-7.432%2C32.006-21.607c9.02-14.176%2C14.994-34.64%2C14.994-57.393s-5.973-43.217-14.994-57.393C258.986%2C7.432%2C247.642%2C0%2C236%2C0ZM156%2C131c-32%2C0-48%2C144-48%2C144%2C0-16-16-64-32-96C60%2C179-.002%2C195%2C0%2C205v22l60-16s32%2C128%2C48%2C128%2C48-112%2C48-112l16%2C234h128l16-234s32%2C112%2C48%2C112%2C48-128%2C48-128l60%2C16v-22c.027-10-60-26-76-26-16%2C32-32%2C80-32%2C96%2C0%2C0-16-144-48-144%2C0%2C0-10.902.02-25.727%2C1.74-2.092%2C4.725-4.453%2C9.187-7.082%2C13.317-11.246%2C17.673-27.904%2C29.943-47.191%2C29.943s-35.944-12.27-47.19-29.943c-2.63-4.13-4.99-8.592-7.083-13.317-14.825-1.72-25.727-1.74-25.727-1.74Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-potion: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20377.55%20460%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M323.65%2C0l-14.5%2C20.4%2C49.5%2C35.1%2C14.5-20.3L323.65%2C0ZM266.25%2C12.3l-14.1%2C20.7%2C111.3%2C76.2%2C14.1-20.7L266.25%2C12.3h0ZM258.95%2C65.7l-69.9%2C82.8c-10.3-2.1-20.9-3.2-31.8-3.2C70.45%2C145.3%2C0%2C215.8%2C0%2C302.6c0%2C86.4%2C70.45%2C157.4%2C157.25%2C157.4s157.3-71%2C157.3-157.4c0-37.8-13.4-72.5-35.6-99.6l51.4-86.9-71.4-50.4ZM266.35%2C104.7l29.5%2C19.5-46.5%2C78c26.1%2C23.9%2C42.5%2C58.2%2C42.5%2C96.4%2C0%2C72-58.5%2C130.4-130.6%2C130.4S30.7%2C370.6%2C30.7%2C298.6s58.55-130.6%2C130.55-130.6c22.6%2C0%2C43.9%2C5.8%2C62.5%2C15.9l42.6-79.2ZM234.85%2C285.2c-47.3-.7-126.2%2C58.3-178.3%2C13.5.1%2C57.7%2C47%2C104.3%2C104.7%2C104.3%2C56.1%2C0%2C102-44%2C104.6-99.5-7-13.2-17.8-18.1-31-18.3ZM223.35%2C308.5c5.1-.1%2C9.7%2C1.5%2C12.7%2C5%2C6.9%2C7.9%2C3.2%2C22.4-8.3%2C32.4-11.4%2C10-26.3%2C11.7-33.2%2C3.8-6.9-7.9-3.2-22.4%2C8.2-32.4%2C6.5-5.6%2C14-8.6%2C20.6-8.8h0ZM166.85%2C357.6c1.2%2C0%2C2.4.1%2C3.7.3%2C9.9%2C1.5%2C17.2%2C8.2%2C16.2%2C15.1-1%2C7-9.8%2C11-19.8%2C10-9.9-2-17.2-8-16.2-15.3.9-6%2C7.7-10.1%2C16.1-10.1Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-armory: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20422.55%20447.641%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M280.685%2C0l-102.848%2C205.699h13.711l13.364-13.363%2C6.363-6.364%2C19.727%2C19.727h70.273L376.222%2C25.826c-8.11-4.986-23.97-11.715-41.314-16.445-19.05-5.196-39.628-8.654-54.223-9.381ZM141.48.021c-14.576.771-34.953%2C4.21-53.838%2C9.36-17.344%2C4.73-33.204%2C11.46-41.314%2C16.445l74.947%2C179.873h36.44l38.722-77.445L141.48.021ZM170.73%2C22.584l36.25%2C84.584%2C41.984-83.971c-26.948%2C5.752-51.079%2C5.561-78.234-.613h0ZM43.691%2C66.298L0%2C131.838l65.88%2C39.529%2C15.24-15.24-37.429-89.829ZM378.859%2C66.298l-37.43%2C89.829%2C15.24%2C15.24%2C65.881-39.53-43.691-65.539ZM211.275%2C211.425l-20.42%2C20.42%2C20.42%2C30.63%2C20.42-30.63-20.42-20.42ZM108.275%2C223.7v30h75.518l-16.098-24.147%2C5.853-5.853h-65.273ZM249.002%2C223.7l5.853%2C5.853-16.098%2C24.147h75.518v-30h-65.273ZM119.877%2C271.7l-26.045%2C165.24c114.22%2C14.268%2C120.666%2C14.268%2C234.886%2C0l-26.045-165.24h-75.916l-15.482%2C23.222-15.482-23.223h-75.916Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-experience: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20463.092%20463.093%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M232.31%2C0C104.628%2C0%2C0%2C104.628%2C0%2C232.313s104.627%2C230.78%2C232.31%2C230.78%2C230.782-103.095%2C230.782-230.78S359.996%2C0%2C232.312%2C0h-.002ZM231.25%2C82l117.374%2C117.97-23.938%2C25.093-65.406-37.938v172.47c79.295-13.13%2C139.78-81.987%2C139.78-165%2C0-39.265-13.54-75.368-36.186-103.907%2C37.702%2C35.365%2C61.22%2C85.81%2C61.22%2C141.625.336%2C105.581-84.983%2C191.444-190.564%2C191.78-.406.001-.813.001-1.219%2C0-106.398%2C0-193.31-85.385-193.31-191.78%2C0-55.123%2C23.342-105.018%2C60.624-140.313-22.028%2C28.33-35.156%2C63.928-35.156%2C102.594%2C0%2C82.46%2C59.645%2C150.973%2C138.156%2C164.75v-168.72l-62.5%2C35.626-25.094-26.28%2C116.219-117.97Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-immobilize: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20472%20437.239%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0v209.947l9.924%2C30.64c34.506-22.263%2C65.675-34.64%2C101.433-30.433L74.293%2C0H0ZM397.707%2C0l-37.064%2C210.154c35.758-4.206%2C66.927%2C8.17%2C101.433%2C30.434l9.924-30.64V0h-74.293ZM173.145%2C227.31c5.361%2C5.193%2C6.517%2C15.154%2C7.12%2C21.655l21.26%2C11.031c1.888%2C5.184-3.41%2C15.26-8.29%2C15.977l-12.995-6.743c-.973%2C6.645-1.787%2C12.547-4.783%2C17.797l9.486%2C4.924c6.546%2C3.397%2C14.294%2C2.037%2C19.485-1.197%2C3.128-1.949%2C5.71-4.43%2C7.863-7.223%2C7.377%2C1.392%2C15.502%2C1.969%2C23.709%2C1.969s16.332-.577%2C23.709-1.969c2.154%2C2.793%2C4.735%2C5.274%2C7.863%2C7.223%2C5.191%2C3.234%2C12.939%2C4.594%2C19.485%2C1.197l9.486-4.924c-2.996-5.25-3.81-11.152-4.783-17.797l-12.994%2C6.743c-4.88-.717-10.179-10.793-8.291-15.977l21.26-11.031c.603-6.5%2C1.759-16.462%2C7.12-21.654-2.663.092-5.482.912-8.27%2C1.97l-28.401%2C14.739c-6.546%2C3.397-9.895%2C10.514-10.239%2C16.62-.11%2C1.967.01%2C3.89.287%2C5.774-5.01.685-10.643%2C1.086-16.232%2C1.086s-11.222-.4-16.232-1.086c.276-1.883.397-3.807.287-5.773-.344-6.107-3.693-13.225-10.239-16.621l-28.402-14.739c-2.787-1.058-5.606-1.878-8.27-1.97h0ZM98.713%2C227.89c-37.724.526-74.546%2C20.941-96.358%2C44.897l7.249%2C19.81c31.68-38.692%2C77.26-50.786%2C120.38-39.818-.417-7.09-.23-13.694.319-20.293-10.395-3.33-21.028-4.742-31.59-4.595h0ZM373.287%2C227.89c-10.562-.146-21.195%2C1.266-31.59%2C4.596.55%2C6.6.736%2C13.204.319%2C20.293%2C43.12-10.968%2C88.7%2C1.126%2C120.38%2C39.819l7.249-19.81c-21.812-23.957-58.634-44.372-96.358-44.897h0ZM148.096%2C228.182c-.81%2C10.885-.266%2C29.41%2C2.834%2C43.607l9.734%2C3.965c2.586-11.223%2C2.906-32.67.065-42.97-3.732-2.342-7.926-3.739-12.633-4.602h0ZM323.904%2C228.182c-4.707.863-8.9%2C2.26-12.633%2C4.601-2.84%2C10.3-2.522%2C31.748.065%2C42.97l9.734-3.964c3.1-14.196%2C3.645-32.722%2C2.834-43.607h0ZM99.684%2C266.642c-27.276.344-53.959%2C12.954-71.176%2C31.323%2C1.704%2C5.264%2C3.41%2C10.527%2C5.113%2C15.79-6.285%2C37.74-8.29%2C77.163-2.838%2C108.579%2C1.055%2C8.222%2C4.829%2C15.139%2C11.516%2C14.898%2C10.581-.38%2C20.631-8.059%2C30.33-8.7%2C8.435-.45%2C14.473%2C2.946%2C21.142%2C5.087%2C6.67%2C2.141%2C13.051%2C3.436%2C18.21%2C2.36%2C10.989-4.862%2C15.247-20.824%2C25.505-24.791%2C10.459-5.374%2C23.473%2C2.55%2C33.567-.66%2C6.792-2.094%2C10.493-5.844%2C10.933-11.54-4.083-24.287-14.821-46.989-28.312-68.86%2C8.6-.557%2C18.822%2C5.084%2C27.074%2C11.04%2C4.113%2C7.971%2C7.819%2C16.16%2C10.924%2C24.613%2C5.29-5.878%2C14.188-14.14%2C10.51-21.804-5.364-10.173-10.077-19.009-16.282-28.32-2.506-3.763-41.568-31.013-61.416-31.075l-2.714-15.396c-6.42-1.613-12.942-2.43-19.446-2.538-.88-.014-1.76-.016-2.64-.006h0ZM372.316%2C266.642c-.88-.01-1.76-.008-2.64.007-6.504.108-13.026.925-19.446%2C2.537l-2.714%2C15.396c-19.848.062-58.91%2C27.313-61.416%2C31.074-6.205%2C9.312-10.918%2C18.148-16.282%2C28.32-3.678%2C7.666%2C5.22%2C15.927%2C10.51%2C21.805%2C3.105-8.454%2C6.81-16.642%2C10.924-24.613%2C8.252-5.956%2C18.474-11.597%2C27.074-11.039-13.49%2C21.87-24.229%2C44.572-28.312%2C68.86.44%2C5.695%2C4.14%2C9.445%2C10.933%2C11.538%2C10.094%2C3.21%2C23.108-4.713%2C33.567.66%2C10.258%2C3.968%2C14.516%2C19.93%2C25.506%2C24.792%2C5.158%2C1.076%2C11.539-.219%2C18.209-2.36%2C6.67-2.14%2C12.707-5.537%2C21.142-5.088%2C9.699.642%2C19.75%2C8.321%2C30.33%2C8.702%2C6.687.24%2C10.46-6.676%2C11.516-14.899%2C5.452-31.415%2C3.447-70.839-2.838-108.578%2C1.703-5.264%2C3.41-10.527%2C5.113-15.791-17.217-18.369-43.9-30.979-71.176-31.322h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dot: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20472.677%20474.686%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M301.557.006c-.496-.01-.984-.007-1.463.008-1.358.09-2.045.27-3.057.4l-96.077%2C150.685c1.53%2C6.565%2C3.088%2C13.04%2C4.778%2C19.226l-18.027%2C4.926c-9.073-33.212-15.026-70.992-26.538-94.735-5.757-11.872-12.47-19.702-20.625-23.246-6.714-2.92-15.483-3.28-27.63.6%2C17.258%2C50.103%2C24.184%2C102.383%2C33.495%2C143.826%2C4.933%2C21.958%2C10.617%2C40.805%2C18.21%2C54.317%2C7.59%2C13.51%2C16.324%2C21.482%2C29.108%2C24.625l-4.463%2C18.148c-18.367-4.515-31.723-17.217-40.94-33.62-4.192-7.46-7.682-15.74-10.726-24.673-30.794%2C33.74-75.13%2C70.583-137.602%2C98.473v135.72h140.437c22.443-42.52%2C44.626-79.104%2C66.23-105.74%2C22.48-27.712%2C44.393-46.065%2C68.247-46.47l-.19.006%2C2.985-.112-28.434-81.853%2C21.164-7.057-33.67-79.035%2C68.99%2C92.844-27.9%2C7.52%2C31.3%2C66.41%2C149.417-5.558c4.266-5.493%2C7.614-14.578%2C8.1-23.91.467-8.97-1.767-17.213-5.073-22.166l-119.5%2C3.42c.137-8.21-.404-16.456-1.55-24.627l130.184-45.302c2.502-6.403%2C2.67-15.49-.002-24.108-2.58-8.326-7.588-15.26-12.38-18.79l-130.13%2C43.943c-3.459-8.192-7.529-16.113-12.177-23.694l108.244-77.542c.024-6.105-2.634-14.563-7.788-21.476-5.365-7.196-12.655-12.406-19.1-14.172l-109.396%2C79.31c-6.44-5.683-13.267-10.506-20.36-14.316l71.172-111.678c-2.26-4.454-6.892-9.397-13.256-13.218C318.174%2C2.877%2C308.989.138%2C301.557.005h0ZM292.582%2C336.236c-3.66%2C51.045-31.82%2C66.58-31.82%2C95.014%2C0%2C14.116%2C15.503%2C26.684%2C31.82%2C26.684%2C15.958%2C0%2C32.457-12.494%2C32.457-27.357%2C0-29.613-27.877-43.213-32.458-94.34h.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-debuff: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20403.2%20469.575%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M398.55%2C68.688l-185.5%2C185.2c-6.2%2C6.2-16.2%2C6.3-22.4%2C0h0L5.15%2C68.688c-6.2-6.2-6.2-16.5%2C0-22.8L46.65%2C4.688c6.2-6.2%2C16.2-6.3%2C22.4%2C0h0l132.8%2C132.8L334.65%2C4.688c6.2-6.2%2C16.2-6.3%2C22.4%2C0h0l41.5%2C41.2c6.2%2C6.2%2C6.2%2C16.5%2C0%2C22.8%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M398.05%2C279.688l-185.5%2C185.2c-6.2%2C6.2-16.2%2C6.3-22.4%2C0h0L4.65%2C279.688c-6.2-6.2-6.2-16.5%2C0-22.8l41.5-41.2c6.2-6.2%2C16.2-6.3%2C22.4%2C0h0l132.8%2C132.7%2C132.7-132.7c6.2-6.2%2C16.2-6.3%2C22.4%2C0h0l41.6%2C41.2c6.2%2C6.2%2C6.2%2C16.5%2C0%2C22.8%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-uninterruptable: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20480.375%20480.342%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M240.188%2C0C107.651%2C0%2C0%2C107.65%2C0%2C240.186s107.65%2C240.156%2C240.188%2C240.156c132.536%2C0%2C240.187-107.62%2C240.187-240.156S372.725%2C0%2C240.187%2C0h.001ZM240.188%2C18.686c122.436%2C0%2C221.5%2C99.064%2C221.5%2C221.5%2C0%2C17.96-2.133%2C35.412-6.157%2C52.125l-44.906-8.686-20.53-71.594-1.376-4.844-4.844-1.5-58.063-17.937-66.906-128.626-4.75-9.156-8.655%2C5.624-91.094%2C59.25-2.936%2C1.907-.97%2C3.374-47.936%2C167.377-70.22%2C29.436c-8.82-23.91-13.656-49.753-13.656-76.75C18.689%2C117.75%2C117.753%2C18.686%2C240.189%2C18.686h0ZM241%2C80.811l-52.53%2C104.595%2C16.218%2C134.438%2C90.125-61.938v62.97l-23.563%2C6.25%2C20.845%2C128.434c-16.646%2C3.988-34.03%2C6.095-51.908%2C6.095-88.813%2C0-165.33-52.117-200.656-127.47l74.406-31.217%2C4.126-1.72%2C1.25-4.312%2C48.187-168.28%2C73.5-47.845h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-crystal: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20335.253%20469.345%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M166.5.002l-53.875%2C59.562v90.063l-34.75-60.188-35.563-17.594-9.344%2C43.53%2C48.376%2C83.783-19.97-5.345-28.75%2C10.5%2C19.658%2C23.5%2C30.28%2C8.125-59.155%2C15.844L0%2C279.752l34.25%2C12.498%2C66.875-17.937-27.875%2C48.28%2C5.562%2C62.72%2C33.813-15.72v33.126l46.812%2C66.626%2C46.78-66.625v-72.81l21.626%2C68.092%2C35.875%2C27.344%2C13.564-43.03-32.688-102.97%2C42.875%2C11.5%2C26.876-13.78-17.78-20.22-64.595-17.312-.092-.25%2C82.25-22.03%2C21.125-24.064-31.97-16.406-73.656%2C19.75%2C39-67.594-3.562-55.25-58.844%2C18.97v-33.097L166.504%2C0l-.004.002ZM160.78%2C109.564l22.438%2C115.03%2C39.876%2C12.032-39.875%2C12.032-22.436%2C115.03-22.375-114.53-41.595-12.533%2C41.594-12.53%2C22.374-114.532h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-stunned: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22996%22%20height%3D%221024%22%20viewBox%3D%220%200%20996%201024%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23ab31c9%22%20d%3D%22M496.26%20601.438c0%200-54.441-34.072-28.516-128.139%2015.184-55.552%2081.846-112.584%20170.728-88.142%20115.918%2032.22%20158.137%20191.097%2049.996%20335.531%200%200-134.064%20178.135-360.344%2077.031%200%200-147.026-67.032-170.728-234.057-28.146-199.245%20109.251-337.383%20109.251-337.383s145.545-179.617%20391.453-125.546c252.574%2055.922%20341.086%20277.017%20337.753%20411.452-2.963%20126.658-37.034%20294.053-224.428%20426.265-199.615%20140.731-442.931%2084.068-560.7%200-88.512-62.958-207.022-181.839-210.725-391.453-3.703-206.281%20111.103-381.454%20249.241-471.077%2087.771-57.033%20228.872-84.438%20334.050-73.698%2015.925%202.222%2014.073%2022.221-0.37%2021.85-9.629-1.111-177.765-1.481-326.273%20118.51-120.362%2097.4-174.061%20262.944-164.062%20379.602%208.888%20106.289%2046.663%20255.907%20238.131%20339.235s455.152-42.96%20482.558-280.35c26.294-224.428-159.988-278.498-240.353-267.758-96.66%2012.592-185.912%2071.106-185.912%20198.875%204.814%2062.588%2051.848%20112.214%20109.251%2089.253z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%236d219e%22%20d%3D%22M496.26%20601.438c0%200-54.070-41.849-24.813-98.511%2038.145-73.328%20117.769-43.701%20138.138-6.666%2029.257%2052.959%2012.962%20155.174-75.92%20184.431%200%200-81.105%2028.516-158.137-21.85%200%200-74.069-49.626-76.661-146.656-1.111-37.775%205.555-75.18%2019.258-109.992%2024.443-60.366%2071.476-108.511%20131.102-134.435%2056.292-24.813%20144.434-48.145%20240.353-15.184%20155.174%2053.7%20191.468%20182.209%20197.763%20259.611%205.925%2072.217-18.888%20245.908-162.581%20345.901-169.988%20118.51-363.307%2099.622-481.447%2015.554-88.142-62.958-183.32-141.842-187.024-351.456-3.703-206.281%2098.511-344.79%20241.464-429.599%2089.993-53.329%20203.689-87.031%20289.238-80.365%2011.11%200.741%207.777%2012.221-3.703%2012.221-9.629-1.111-177.765-1.481-326.273%20118.51-120.732%2097.4-174.432%20262.944-164.803%20379.602%208.888%20106.289%2046.663%20255.907%20238.131%20339.235s455.152-42.96%20482.558-280.35c26.294-224.428-159.618-277.017-240.353-267.758-91.475%2010.37-177.024%2065.551-185.172%20180.357-1.481%2015.925%200.37%2031.85%204.444%2047.034%2015.184%2047.404%2055.922%2079.624%20104.437%2060.366z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-meat: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20485.028%20344.268%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M421.961.007c-4.05-.11-8.044%2C1.117-11.656%2C4-1.542%2C1.23-3.1%2C2.884-4.47%2C4.75-22.9%2C31.22-48.278%2C57.33-75.186%2C81-8.76%2C14.692%2C10.695%2C44.406%2C25.594%2C44.406%2C34.144-12.928%2C69.617-22.516%2C106.75-26.314%2C42.628-4.358%2C17.688-68.134-26.25-45.47C467.043%2C39.713%2C443.837.589%2C421.961.005v.002ZM292.275%2C10.1c-6.167-.108-12.215%2C1.172-17.595%2C4.28-1.556.901-3.03%2C1.937-4.406%2C3.095-.038-.056-.09-.13-.126-.186-79.912%2C66.402-116.334%2C73.468-158.22%2C86.844-6.886%2C2.2-12.27%2C7.18-16.5%2C15.5s-6.892%2C19.843-7.343%2C33.125c-.9%2C26.563%2C6.935%2C59.927%2C23.72%2C89.03%2C16.72%2C28.99%2C43.37%2C53.946%2C67.656%2C67.126%2C12.143%2C6.59%2C23.682%2C10.167%2C32.375%2C10.436%2C8.694.27%2C13.915-1.95%2C17.782-7.375%2C30.986-43.45%2C89.343-69.052%2C156.157-92.25-.005-.006.003-.023%2C0-.03%2C2.031-.661%2C3.989-1.53%2C5.842-2.594%2C8.2-4.738%2C13.535-12.897%2C16.282-22.125%2C2.747-9.227%2C3.22-19.75%2C2.03-31.25-.953-9.233-3.033-19.127-6.155-29.374-5.916%2C1.366-11.628%2C3.157-17.908%2C5.47%2C2.835%2C9.25%2C4.69%2C17.978%2C5.5%2C25.81%2C1.007%2C9.74.403%2C18.06-1.375%2C24.033-1.777%2C5.972-4.412%2C9.338-7.718%2C11.25-3.308%2C1.91-7.543%2C2.505-13.595%2C1.06-6.052-1.443-13.55-5.07-21.47-10.81-15.838-11.482-33.334-31.223-47.624-56-14.29-24.78-22.61-49.838-24.624-69.314-1.006-9.738-.403-18.027%2C1.375-24%2C1.78-5.973%2C4.414-9.37%2C7.72-11.28%2C1.653-.957%2C3.52-1.58%2C5.75-1.782.557-.05%2C1.147-.067%2C1.75-.063%2C1.81.014%2C3.824.272%2C6.094.814%2C6.05%2C1.444%2C13.518%2C5.04%2C21.437%2C10.78%2C8.218%2C5.957%2C16.884%2C14.166%2C25.314%2C24.126%2C5.07-4.055%2C9.34-8.25%2C13.406-13.188-8.97-10.46-18.366-19.26-27.75-26.062-9.354-6.78-18.733-11.61-28.094-13.844-2.311-.555-4.661-.931-7.03-1.125-.884-.068-1.77-.11-2.657-.124v-.003ZM300.242%2C44.288c-.438.024-.86.063-1.28.125-17.327%2C2.54-14.97%2C36.035%2C5.03%2C74.56%2C20%2C38.528%2C50.52%2C67.576%2C67.844%2C65.032%2C5.995-.88%2C9.263-5.687%2C10.658-12.875-1.67%2C2.187-3.847%2C3.484-6.72%2C3.907-15.316%2C2.248-42.316-23.093-60-57.156-17.682-34.064-19.254-63.91-3.937-66.157%2C3.638-.53%2C7.69.417%2C12.345%2C2.782-8.68-6.8-17.353-10.583-23.938-10.218h-.002ZM83.805%2C227.068c-16.555%2C1.844-35.304%2C3.26-57.063%2C4.376-49.128%2C2.523-25.555%2C71.576%2C30.094%2C52.22-49.365%2C29.9%2C3.86%2C86.927%2C26.97%2C46.75%2C10.362-18.016%2C21.88-33.79%2C34.375-47.814-8.42-9.644-16.078-20.224-22.563-31.47-4.469-7.748-8.415-15.786-11.812-24.06v-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-confused: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20411.458%20474.101%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M208.804%2C0C96.894-.001%2C18.231%2C38.287%2C4.136%2C80.671h.002c-25.93%2C77.97%2C72.846%2C117.983%2C216.416%2C92.307%2C78.262-14%2C182.29%2C16.69%2C123.08%2C80.35%2C151.465-68.768%2C22.753-120.352-128.742-102.648-88.326%2C10.322-160.02%2C11.012-170.92-37.805-7.92-35.467%2C76.538-71.817%2C167.17-77.25%2C89.626-5.373%2C183.32%2C37.95%2C170.533%2C64.828-17.172%2C36.097-126.9%2C7.75-120.308-25.113%2C2.21-11.017%2C19.864-15.988%2C42.05-14.6-30.58-10.615-72.8-11.888-79.427%2C12.846-4.788%2C17.872%2C27.71%2C42.46%2C72.418%2C53.73%2C54.674%2C13.782%2C115.05%2C5.32%2C115.05-46.136C411.458%2C36.28%2C319.161%2C0%2C208.803%2C0h0Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M338.286%2C273.799l-56.64%2C13.39%2C38.91-38.91c-18.73-20.82-45.76-37.6-77.88-46.21-12.96-3.48-26.29-5.44-39.71-5.84-1.75-.05-3.49-.07-5.24-.07-53.92.17-99.46%2C27.14-110.98%2C70.15-7.39%2C27.56%2C1.15%2C56.59%2C19.86%2C81.18%2C2.06%2C2.71-.42%2C8.23-3.51%2C11.09-51.88%2C48.18-12.11%2C89.94%2C25.12%2C51.4-16.99%2C47.31%2C24.36%2C66.46%2C46.72%2C24.53-2.46%2C47.79%2C41.42%2C54.25%2C51.97%2C8.76%2C12.31%2C50.24%2C66.51%2C34.65%2C47.31-33.29-1.43-5.05.67-9.28%2C4.67-10.51%2C33.49-10.34%2C58.97-33.09%2C67.16-63.66%2C5.56-20.75%2C2.32-42.26-7.76-62.01ZM149.296%2C344.759c-22.66-6.07-36.1-29.36-30.03-52.01%2C5.12-19.12%2C22.5-31.68%2C41.42-31.49%2C3.5.03%2C7.06.51%2C10.6%2C1.45%2C22.65%2C6.07%2C36.1%2C29.36%2C30.03%2C52.02-6.07%2C22.66-29.36%2C36.1-52.02%2C30.03ZM190.626%2C400.289c-31.33-8.9-.89-41.16%2C16.97-56.83%2C8.91%2C23.33%2C15.9%2C66.21-16.97%2C56.83ZM289.046%2C357.799c-4.41%2C16.44-21.31%2C26.2-37.76%2C21.8-16.44-4.41-26.2-21.31-21.79-37.75%2C3.72-13.88%2C16.33-22.99%2C30.06-22.86%2C2.54.03%2C5.12.37%2C7.69%2C1.06%2C16.45%2C4.4%2C26.2%2C21.31%2C21.8%2C37.75Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-all-elements: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20470.197%20470.199%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M235.099%2C0c-57.656%2C0-110.49%2C20.826-151.41%2C55.34l-.02.018c-14.922%2C11.324-27.811%2C25.103-38.114%2C40.748C16.93%2C135.054%2C0%2C183.116%2C0%2C235.1c0%2C60.03%2C22.573%2C114.835%2C59.67%2C156.406l-.428.428c2.47%2C2.472%2C4.99%2C4.866%2C7.545%2C7.2%2C42.715%2C43.82%2C102.358%2C71.065%2C168.31%2C71.065%2C129.73%2C0%2C235.1-105.367%2C235.1-235.098S364.827.001%2C235.097.001h.002ZM253.656%2C19.485c110.923%2C9.397%2C197.856%2C102.235%2C197.856%2C215.615%2C0%2C93.92-59.656%2C173.746-143.185%2C203.725%2C21.783-10.06%2C42.125-23.996%2C59.99-41.86%2C83.66-83.66%2C81.477-221.553-4.095-308.117-27.37-34.46-66.12-59.47-110.566-69.363ZM182.714%2C40.729c50.418%2C0%2C94.77%2C25.548%2C120.845%2C64.426-23.568-22.81-55.268-36.417-87.088-37.588-1.74-.064-3.482-.09-5.222-.08-26.108.163-51.995%2C8.817-73.223%2C27.744-37.01%2C33-47.4%2C93.67-11.256%2C132.697%2C24.97%2C26.964%2C70.172%2C34.654%2C98.377%2C6.775%2C9.363-9.253%2C15.098-21.745%2C16.107-34.748%2C1.01-13.002-3.07-26.867-13.68-36.925l-.002-.002c-6.717-6.365-15.495-10.193-24.725-10.723-9.23-.53-19.322%2C2.714-26.187%2C10.797-4.143%2C4.851-6.451%2C11.003-6.52%2C17.382-.087%2C6.48%2C2.615%2C13.847%2C8.807%2C18.47l.01.008.008.006c3.53%2C2.623%2C7.546%2C3.958%2C12.13%2C3.813%2C4.585-.147%2C10.325-2.614%2C13.293-7.69v-.003c1.62-2.77%2C2.21-5.36%2C1.828-8.705-.383-3.344-2.986-8.217-7.56-9.988-2.477-.96-3.87-1.053-6.464-.467-.617.14-1.33.36-2.078.7.265-.494.487-1.06.797-1.427%2C2.8-3.297%2C6.35-4.495%2C10.865-4.236%2C4.515.26%2C9.583%2C2.45%2C12.94%2C5.63%2C6.232%2C5.91%2C8.547%2C13.58%2C7.9%2C21.913-.647%2C8.334-4.617%2C16.978-10.607%2C22.9-19.7%2C19.47-52.966%2C13.852-71.52-6.183-28.257-30.51-19.83-79.463%2C9.98-106.043%2C43.082-38.41%2C110.765-25.763%2C147.365%2C17.128%2C16.63%2C19.486%2C26.923%2C44.188%2C29.785%2C69.752l.168-.02c-5.076%2C75.787-67.978%2C135.512-145.07%2C135.512-80.42%2C0-145.414-64.99-145.414-145.412%2C0-29.5%2C8.753-56.917%2C23.796-79.818%2C9.88-13.331%2C21.254-25.487%2C33.9-36.23%2C24.37-18.436%2C54.745-29.366%2C87.718-29.366h-.003ZM406.454%2C203.637c13.955%2C63.703-3.07%2C131.83-51.354%2C180.113-74.77%2C74.77-197.125%2C74.596-276.945.438-33.938-35.717-55.775-83.033-59.03-135.432%2C17.826%2C89.673%2C96.938%2C157.267%2C191.847%2C157.267%2C108.034%2C0%2C195.612-87.576%2C195.612-195.61%2C0-2.27-.053-4.526-.13-6.776h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-taunt: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20479.47%20474.81%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M386.03%2C199.16l93.44-32.72v-66.56l-93.44%2C99.28ZM0%2C53.72v84.09l99.28%2C46.72L0%2C53.72ZM423.4%2C0l-74.15%2C158.28%2C130.22-99.31V0h-56.07ZM317.12%2C0l-16.34%2C130.22L391.31%2C0h-74.19ZM223.68%2C0l22.78%2C118.56L282.09%2C0h-58.41ZM188.65%2C0h-65.43l68.34%2C124.41L188.65%2C0ZM89.34%2C0H0v14.59l140.75%2C132.57L89.34%2C0Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M360.9%2C216.5c-1.85-9.47-6.03-19.94-12.37-29.78-10.96-17.01-25.24-27.29-36.16-27.37-3.64-.03-6.9%2C1.07-9.56%2C3.43-2.42%2C2.16-4.12%2C5.17-5.12%2C8.82%2C1.25%2C1.57%2C2.48%2C3.17%2C3.65%2C4.84%2C11.65%2C16.57%2C19.58%2C37.63%2C22.47%2C61%2C8.61%2C7.78%2C17.56%2C11.76%2C24.72%2C10.78l54.59%2C35.94-104.59%2C57.81c-4.07%2C5.26-8.57%2C10.02-13.44%2C14.16-5.57-4.35-11.03-7.95-16.44-10.82%2C6.33-4.49%2C12.21-10.48%2C17.41-17.87%2C12.3-17.5%2C20.28-42.42%2C20.28-70.13%2C0-7.05-.51-13.91-1.49-20.52-.65-4.44-1.51-8.76-2.56-12.95-3.52-14.09-9.16-26.6-16.23-36.65-12.3-17.5-28.3-27.32-45.44-27.32s-33.13%2C9.82-45.43%2C27.32c-6.8%2C9.67-12.29%2C21.62-15.82%2C35.06-1.69%2C6.42-2.94%2C13.18-3.68%2C20.2-.51%2C4.84-.78%2C9.8-.78%2C14.86%2C0%2C27.71%2C7.98%2C52.63%2C20.28%2C70.13%2C4.54%2C6.45%2C9.58%2C11.86%2C15%2C16.12-5.51%2C2.62-11.07%2C6.02-16.69%2C10.22-3.81-3.52-7.32-7.35-10.5-11.44l-105.25-58.19%2C54.44-35.84c7.49.51%2C16.76-4.09%2C25.5-12.59%2C3.06-22.69%2C10.85-43.12%2C22.22-59.28.78-1.13%2C1.6-2.23%2C2.43-3.32-.93-4.32-2.75-7.89-5.5-10.34-2.65-2.37-5.92-3.47-9.56-3.44v.01c-10.92.08-25.16%2C10.36-36.13%2C27.37-6.48%2C10.05-10.7%2C20.77-12.5%2C30.41-49.04%2C22.67-113.9%2C63.9-113.9%2C63.9l148.43%2C126%2C15%2C67.78h144.28l11.32-64.65.09.09%2C152.25-129.22s-66.03-41.99-115.22-64.53ZM257.47%2C230.42l10.13-10.13c5.97%2C1.13%2C11.93%2C2.6%2C17.82%2C4.39v18.34l-.39%2C1.14c-9.07-3.11-18.41-5.32-27.91-6.63.23-2.36.34-4.74.35-7.11ZM195.13%2C243v-18.71c6.77-2.27%2C13.76-3.96%2C20.89-5.08l11.32%2C11.31c.01%2C2.1.08%2C4.14.25%2C6.14-11.27.94-22.11%2C3.38-32.06%2C7.34l-.4-1ZM240.09%2C333.25c-20.26%2C0-36.69-16.43-36.69-36.68s16.43-36.66%2C36.69-36.66%2C36.72%2C16.4%2C36.72%2C36.65-16.45%2C36.69-36.72%2C36.69Z%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M179.37%2C222.25c-1.69%2C6.42-2.94%2C13.18-3.68%2C20.2l3.68-20.2Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dynamite: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20477.279%20429.883%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M261.372%2C2.633c-2.8%2C2.78-4.1%2C9.46-.7%2C20.04%2C3.4%2C10.59%2C11.3%2C23.59%2C22.8%2C35.39%2C11.5%2C11.7%2C24.3%2C19.9%2C34.9%2C23.5%2C10.5%2C3.7%2C17.2%2C2.4%2C20-.3%2C2.8-2.8%2C4.2-9.5.8-20.1-3.4-10.6-11.3-23.6-22.8-35.32-11.6-11.76-24.4-19.94-34.9-23.57-6.2-1.5-15-4.44-20.1.36h0ZM350.472.793c-4%2C0-6.9%2C1.05-8.5%2C2.62-2.8%2C2.78-4.1%2C9.45-.7%2C20.04%2C3.4%2C10.58%2C11.3%2C23.61%2C22.8%2C35.31%2C11.5%2C11.8%2C24.3%2C20%2C34.9%2C23.6%2C10.5%2C3.6%2C17.2%2C2.4%2C20-.4%2C2.8-2.7%2C4.2-9.4.8-20-3.4-10.6-11.3-23.6-22.8-35.35-11.6-11.76-24.4-19.94-34.9-23.56-4.6-1.59-8.5-2.25-11.6-2.26h0ZM241.772%2C21.833l-31.2%2C30.63c5.8%2C17.4%2C13.4%2C32.7%2C24.2%2C44.8%2C12.8%2C14.5%2C29.9%2C24.9%2C55.1%2C29.7l1.5.3%2C27.4-26.8c-2.1-.5-4.2-1.1-6.3-1.9-14-4.8-28.7-14.4-41.9-27.9-13.2-13.5-22.5-28.4-27.1-42.48-.7-2.18-1.2-4.44-1.7-6.35ZM183.472%2C78.963l-120.8%2C118.3c5.7%2C16.5%2C13.2%2C31.1%2C23.5%2C42.7%2C12.8%2C14.5%2C29.9%2C24.9%2C55.1%2C29.7l4%2C.7%2C118-115.6c-37-11.4-63-38.6-79.8-75.8h0ZM363.472%2C92.763c-4%2C0-6.9%2C1-8.5%2C2.6-2.8%2C2.8-4.1%2C9.5-.7%2C20%2C3.4%2C10.6%2C11.3%2C23.6%2C22.8%2C35.4s24.3%2C19.9%2C34.9%2C23.6c10.5%2C3.6%2C17.2%2C2.4%2C20-.4.7-.7%2C1.3-1.6%2C1.8-2.8%2C13.2%2C11.3%2C24.3%2C26.2%2C25.3%2C35.8%2C1.3%2C11.7-3.5%2C21.7-12.8%2C32.4-9.4%2C10.7-23.2%2C21.2-37.4%2C32-14.1%2C10.7-28.5%2C21.6-39.3%2C34.4-10.7%2C12.9-17.9%2C28.7-14.7%2C46.4%2C2.9%2C15.6%2C11.3%2C31.8%2C25.1%2C42.9%2C13.7%2C11.2%2C33.4%2C16.8%2C55.1%2C9.7l8.6-2.8-5.6-17.1-8.6%2C2.8c-16.3%2C5.3-28.4%2C1.5-38.2-6.5-9.8-8-16.6-20.9-18.6-32.2-2.1-11.6%2C1.9-21.1%2C10.7-31.6%2C8.9-10.5%2C22.4-21%2C36.4-31.7%2C14.1-10.7%2C28.8-21.7%2C40-34.5%2C11.2-12.7%2C19.2-28.3%2C17.2-46.1-2.2-20.4-18.9-37.8-35.6-51-4-3.2-8.1-6.1-12.1-8.6-4.2-8.6-10.7-18.1-19.3-26.9-11.6-11.8-24.4-19.9-34.9-23.6-4.6-1.5-8.5-2.2-11.6-2.2h0ZM335.372%2C114.563l-27.3%2C26.8.2%2C1.5c4.2%2C25.3%2C14.3%2C42.7%2C28.5%2C55.8%2C11.9%2C11%2C27.1%2C19%2C44.3%2C25.1l31.3-30.6c-2.1-.5-4.2-1.1-6.3-1.8-14-4.8-28.7-14.5-41.9-28s-22.5-28.4-27.1-42.4c-.7-2.2-1.2-4.3-1.7-6.4h0ZM279.972%2C168.863l-118.1%2C115.6.7%2C4c4.1%2C25.3%2C14.2%2C42.6%2C28.5%2C55.7%2C11.4%2C10.6%2C25.7%2C18.4%2C42.2%2C24.4l120-117.5c-36.8-17.8-63.1-44.6-73.3-82.2h0ZM37.052%2C222.363c-11.64%2C9-23.69%2C22.4-34.25%2C33.5-2.84%2C2.8-4.19%2C9.5-.79%2C20.1%2C3.41%2C10.6%2C11.32%2C23.6%2C22.83%2C35.3%2C11.52%2C11.8%2C24.36%2C20%2C34.87%2C23.6%2C10.51%2C3.6%2C17.21%2C2.4%2C20.04-.4%2C12.72-12.3%2C25.72-25.1%2C36.62-35.8-36.88-11.6-62.65-38.9-79.32-76.3ZM132.172%2C313.563c-12.2%2C11.4-20.2%2C19.3-35.8%2C35.1-2.8%2C2.8-4.2%2C9.4-.8%2C20%2C3.4%2C10.6%2C11.3%2C23.6%2C22.8%2C35.4%2C11.6%2C11.7%2C24.4%2C19.9%2C34.9%2C23.5%2C10.5%2C3.7%2C17.2%2C2.5%2C20.1-.3%2C11.3-10.6%2C21.6-21.2%2C32.4-31.8-36.8-17.8-63.2-44.5-73.6-81.9h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-berserk: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20455.391%20440%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M419.691%2C0c-29.4%2C44.05-63.2%2C65.7-126.3%2C64.8-14.915-20.504-39.465-32.757-65.7-32.79-26.271.002-50.865%2C12.258-65.8%2C32.79-63%2C.9-96.85-20.77-126.2-64.8-30.29%2C45.43%2C21.04%2C110.9%2C112.2%2C112.4.617%2C10.15%2C3.371%2C20.079%2C8.1%2C29.2C16.531%2C161.1-11.489%2C352.1%2C3.691%2C428h80c0-48%2C16-112%2C64-144l-16%2C144c0%2C16%2C64%2C16%2C64%2C0%2C0-32%2C16-64%2C32-64s32%2C32%2C32%2C64c0%2C16%2C64%2C16%2C64%2C0l-16-144c48%2C32%2C64%2C96%2C64%2C144h80c15.2-75.9-12.8-267-152.4-286.4%2C4.764-9.114%2C7.552-19.043%2C8.2-29.2%2C91.1-1.5%2C142.5-66.96%2C112.2-112.4ZM163.691%2C87.8c13.5%2C15.7%2C27.2%2C31.3%2C48%2C40.2%2C0%2C0-22.9%2C15.7-32%2C8.7-10.1-7.9-16-48.9-16-48.9ZM291.691%2C87.8s-5.9%2C41-16%2C48.9c-9.1%2C7-32-8.7-32-8.7%2C20.8-8.9%2C34.5-24.5%2C48-40.2h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-crushingBlow: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20465.479%20474.16%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M53.682%2C0l36.696%2C67.596L.002%2C14.182v.058l102.127%2C106.376L0%2C74.346v.3l53.856%2C60.932L0%2C131.506v.014l196.608%2C95.675-68.502%2C34.29%2C76.547%2C18.104-42.896%2C55.227%2C72.892-11.634c5.323-8.462%2C9.98-16.897%2C13.958-25.48-18.586-11.336-30.994-31.8-30.994-55.165%2C0-35.66%2C28.91-64.57%2C64.572-64.57%2C22.323%2C0%2C41.986%2C11.335%2C53.58%2C28.556l36.55%2C2.15%2C35.013-37.644-59.405%2C9.334%2C23.363-78.582-63.15%2C59.25-21.5-112.395-21.354%2C110.425-48.256-53.547%2C6.737%2C61.11L54.2.001h-.52.002ZM284.788%2C222.244c-2.274%2C61.787-26.61%2C106.513-68.617%2C156.828l75.126%2C82.96%2C41.545-116.155c-6.507%2C2.467-13.803%2C3.007-20.984%2C1.083-18.23-4.885-29.204-23.86-24.32-42.086.206-.77.444-1.522.7-2.265l1.452-22.514%2C77.674-3.506h.004l65.41%2C41.467-11.62%2C24.1c-5.448%2C17.396-23.93%2C27.675-41.698%2C22.915-6.818-1.827-12.62-5.626-16.957-10.618l-22.757%2C119.707%2C104.506-33.964c-13.598-67.112-8.595-114.53%2C21.227-169.622l-83.105-42.59-97.586-5.74h0ZM320.268%2C298.094c-6.786.15-12.81%2C4.683-14.668%2C11.62-2.265%2C8.455%2C2.62%2C16.913%2C11.098%2C19.185%2C8.48%2C2.272%2C16.937-2.61%2C19.203-11.067%2C2.265-8.456-2.62-16.913-11.098-19.185-1.036-.278-2.097-.453-3.168-.523-.46-.03-.915-.04-1.368-.03h.001ZM387.872%2C316.204c-6.786.15-12.81%2C4.682-14.67%2C11.618-2.266%2C8.456%2C2.618%2C16.914%2C11.098%2C19.186%2C8.48%2C2.272%2C16.937-2.61%2C19.203-11.066%2C2.267-8.456-2.617-16.914-11.097-19.186-1.035-.278-2.096-.454-3.166-.523-.458-.03-.915-.04-1.367-.03h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-sound-off: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20443.564%20352%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cg%20transform%3D%22translate(0%2065.922)%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M237.73%2C7.236C219.24%2C1.976%2C197.72-.124%2C176.43.006c-35.46.21-70.26%2C6.61-89.25%2C14.86-14.08%2C43.14-16.33%2C127.92-6.73%2C180.52-8.46-4.27-18.34-6.55-28.45-6.56-28.72%2C0-52%2C17.91-52%2C40s23.28%2C40%2C52%2C40%2C52-17.91%2C52-40c-6.16-49.18-13.74-115.12-8.22-165.43%2C37.75-7.73%2C77.49-17.43%2C114.68-10.72-4.15%2C38.29-3.03%2C82.42%2C3.38%2C117.55-8.45-4.26-18.33-6.54-28.44-6.55-28.72%2C0-52%2C17.91-52%2C40s23.28%2C40%2C52%2C40%2C52-17.91%2C52-40c-4.62-72.49-18.78-132.77.33-196.44ZM212.91%2C34.526c-37.91-5.63-78.58%2C1.39-114.33%2C9.66.92-5%2C2.02-9.96%2C3.27-14.88%2C19.73-7.72%2C50.15-13.48%2C80.04-13.67%2C11.7-.07%2C23.32.71%2C34.18%2C2.56-1.19%2C5.2-2.24%2C10.67-3.16%2C16.33Z%22%2F%3E%0A%20%20%20%20%3Cpolygon%20points%3D%22298.512%2033.351%20273.053%2058.81%20324.326%20110.08%20273.054%20161.351%20298.512%20186.809%20349.783%20135.537%20401.054%20186.809%20426.512%20161.351%20375.24%20110.08%20426.512%2058.809%20401.054%2033.351%20349.783%2084.623%20298.512%2033.351%20298.512%2033.351%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'); + --icon-sound-on: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20443.564%20352%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M299.564%2C0c128%2C64%2C128%2C288%2C0%2C352%2C192-64%2C192-288%2C0-352ZM251.564%2C16c64%2C50.843%2C64%2C270.217%2C0%2C321.06%2C128-50.843%2C128-270.217%2C0-321.06ZM176.434%2C65.922c-35.468.215-70.268%2C6.618-89.253%2C14.863-14.084%2C43.136-16.33%2C127.919-6.736%2C180.518-8.452-4.265-18.337-6.543-28.445-6.555-28.719%2C0-52%2C17.909-52%2C40s23.281%2C40%2C52%2C40%2C52-17.909%2C52-40c-6.166-49.187-13.74-115.12-8.225-165.437%2C37.756-7.722%2C77.49-17.422%2C114.688-10.715-4.152%2C38.294-3.029%2C82.424%2C3.379%2C117.552-8.452-4.265-18.337-6.543-28.446-6.554-28.719%2C0-52%2C17.908-52%2C40s23.281%2C40%2C52%2C40%2C52-17.909%2C52-40c-4.618-72.485-18.78-132.767.33-196.436-18.491-5.267-40.012-7.365-61.293-7.236h.001%2C0ZM181.89%2C81.557c11.697-.073%2C23.313.706%2C34.174%2C2.558-1.185%2C5.199-2.232%2C10.67-3.156%2C16.336-37.913-5.64-78.578%2C1.385-114.332%2C9.656.926-4.997%2C2.019-9.961%2C3.277-14.884%2C19.722-7.718%2C50.145-13.48%2C80.037-13.666h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-mend: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20426.75%20472.719%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M195.35.319c-8.6%2C1.31-16.5%2C5.4-20.7%2C9.7l26.1%2C158.7-17.6%2C5.6L110.15%2C26.319c-5.9-.8-14.3.61-22.2%2C4.81-8.1%2C4.3-14.4%2C11-17.2%2C17.39l69.1%2C142.9-15.2%2C10.5L30.1%2C101.719c-5.8%2C1.2-13.1%2C5.5-19.1%2C12.1-6.2%2C7-10.2%2C15.8-11%2C22.8l96.05%2C103.6c69.9-31.4%2C140.4-54.2%2C210.9-76.1l10.4-47.2c-8.5.6-16.6-.6-24.1-3.2-7.2-2.5-13.9-6.2-20.2-10.8l-11.7%2C53-18.3-.5L218.85%2C4.029C210.65.009%2C203.65-.471%2C195.35.319h0ZM289.75%2C11.449l-16.1%2C68.34c8.4%2C8.03%2C16.9%2C13.93%2C25.5%2C16.93s17.5%2C3.3%2C27.8%2C0l16.9-69.73v-.11c-3.7-14.58-42.4-21.77-54.1-15.43h0ZM395.55%2C176.419c-5.7.1-12.1%2C1.4-19.1%2C3.9-19%2C6.6-41.6%2C21.3-64.6%2C35.5l-.5-.4c-59.7%2C34.3-118.1%2C69.2-169.8%2C110.4v2.1c21.6%2C2.9%2C51.6%2C11.2%2C80.3%2C20.6%2C23%2C7.6%2C44.6%2C15.6%2C59.9%2C22.6-2.3-22-2.6-42.5-1.6-60.9-8.7%2C4.2-17%2C7.6-25.3%2C9.9-18.1%2C5.1-36.5%2C4.7-52.7-5.1l9.7-16c11.2%2C6.8%2C23.1%2C7.3%2C38%2C3.1%2C14.9-4.2%2C32.3-13.5%2C51.4-25.6%2C35.9-22.7%2C77.7-54.9%2C125.5-78.2-5.9-11.3-12.3-17.2-19.1-19.9-3.6-1.4-7.7-2.1-12.1-2h0ZM302.45%2C184.319c-43.3%2C13.6-86.5%2C27.6-129.3%2C43.7%2C16.3%2C4.3%2C32.8%2C11%2C45.4%2C21.7%2C26.2-16.5%2C53.1-32.3%2C80.1-47.8%2C1.5-6%2C2.5-11.6%2C3.8-17.6h0ZM141.75%2C240.319c-11%2C4.5-21.9%2C9.1-32.8%2C13.9l15.7%2C16.9.2.1c8.1%2C8.4%2C12.8%2C19.6%2C15.1%2C33%2C20.1-15.5%2C41-30.1%2C62.5-44.1-16.1-10.7-41.3-17.2-60.7-19.8ZM88.55%2C291.419c-4.7-.1-12.6%2C2-21%2C5.7-9.1%2C4.1-18.98%2C10-28.03%2C16-4.74%2C3.1-9.18%2C6.3-13.25%2C9.2%2C12.94.6%2C26.58%2C1.7%2C40.38%2C4.9%2C19.1%2C4.5%2C37.9%2C13.4%2C51%2C29.9%2C8.5-17.2%2C8.2-29.5%2C1.2-41-9.5-12.9-22.7-24.2-29.4-24.7h-.9ZM140.65%2C346.019c-1.1%2C13.4-3.4%2C27.9-5.6%2C39.5%2C61.2%2C9.5%2C110.1%2C34.1%2C160.2%2C55.3-4.7-16.7-8.2-32.8-10.6-48.3-11.6-6.2-39.4-17.3-68.4-26.9-27.4-9-56.6-16.8-75.6-19.6ZM119.45%2C375.719c-18%2C9.3-39.4%2C17.1-69.54%2C17.8-6.97%2C17.7-14.01%2C37.1-31.64%2C55.6%2C22.6.7%2C37.95-3.1%2C51.38-11%2C16.5-9.7%2C27.2-27%2C46.9-51.4l2.9-11ZM131.35%2C403.119c-3.5%2C15.6-7.9%2C32.1-12.8%2C49.3%2C20.7-13.2%2C44.9-27.1%2C71.9-34.8-18.7-6.2-38.2-11.3-59.1-14.5h0ZM223.45%2C429.819c-38.4%2C2.9-73.6%2C23.8-103.1%2C42.9h185.3c-1.2-3.2-2.3-6.4-3.4-9.6-26.9-10.8-52.5-22.7-78.8-33.3h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-spikeWall: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20468.221%20473.812%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M88.406%2C0l1.468%2C24.844c-7.493%2C3.44-14.667%2C7.408-21.436%2C11.968C56.525%2C30.617%2C7.843.876%2C7.843.876l26.438%2C68.563c-18.827%2C25.903-24.476%2C56.148-20.5%2C87.5-4.036%2C10.546-6.775%2C21.543-8.157%2C32.75-4.28%2C34.82%2C4.443%2C73.208%2C29.564%2C111.78C24.178%2C318.869%2C0%2C354.813%2C0%2C354.813l61.22-19.875c1.98%2C2.18%2C3.998%2C4.36%2C6.093%2C6.532%2C31.825%2C33.022%2C64.816%2C56.735%2C97.343%2C72.436-1.357%2C21.98-4.532%2C59.906-4.532%2C59.906l40.532-45.656c34.34%2C10.635%2C67.452%2C12.538%2C97.282%2C7.22%2C8.957%2C1.915%2C17.79%2C3.232%2C26.437%2C3.874%2C26.46%2C1.964%2C51.463-2.464%2C72.283-15.5%2C1.942-1.211%2C3.839-2.493%2C5.687-3.844%2C15.444%2C4.942%2C64.094%2C23.25%2C64.094%2C23.25l-34.906-57.062c4.48-8.064%2C8.3-17.044%2C11.375-26.97%2C9.51-30.692%2C13.66-59.886%2C13.375-87.374.002-.02-.003-.042%2C0-.063%2C4.158-29.67.89-60.38-8.282-89.562-3.378-10.728-7.514-21.202-12.375-31.344%2C15.212-13.58%2C32.595-28.75%2C32.595-28.75l-47.5%2C2.032c-8.474-13.175-18.222-25.552-29.094-36.843%2C5.347-17.464%2C21.908-64.907%2C21.908-64.907l-55.25%2C36.343c-.262-.183-.52-.38-.782-.562-24.558-17.015-52.748-28.888-83.125-33.25.924-11.743%2C1.72-21.625%2C1.72-21.625l-17.406%2C19.593c-31.27-10.284-63.304-15.307-93.656-14.47-21.283.588-41.732%2C4.05-60.532%2C10.595C95.875%2C8.82%2C88.405%2C0%2C88.405%2C0h.001ZM173.156%2C28.28c8.26.09%2C16.652.658%2C25.125%2C1.626-23.352%2C6.245-43.81%2C15.013-61.438%2C25.75-1.82-1.457-9.677-10.352-18.53-20.594%2C15.102-4.23%2C31.386-6.447%2C48.31-6.75%2C2.168-.038%2C4.345-.055%2C6.532-.03v-.002ZM241.843%2C41.78l-11.938%2C13.44c-11.7-2.576-23.596-4.165-35.562-4.75%2C4.397-1.344%2C8.9-2.63%2C13.563-3.782%2C11.515-2.845%2C22.86-4.438%2C33.937-4.907h0ZM91.093%2C45.626l1.53%2C26.344c-3.953%2C2.024-7.83%2C4.193-11.624%2C6.5-19.415%2C11.843-36.164%2C27.058-49%2C44.843%2C2.444-17.23%2C9.253-33.295%2C21.157-47.72%2C10.37-12.565%2C23.26-22.493%2C37.937-29.967ZM272.531%2C49.032c10.435%2C4.212%2C20.627%2C9.001%2C30.53%2C14.345l-4.562%2C19.28c-8.983-5.375-18.067-10.048-27.22-14.03.283-5.274.724-12.21%2C1.252-19.594h0ZM190.749%2C68.722c33.724%2C1.065%2C69.257%2C11.17%2C103.25%2C32.874l-4.656%2C19.594s6.89-5.636%2C15.22-12.438c21.385%2C15.353%2C42.013%2C35.488%2C61%2C61.094%2C6.913%2C9.325%2C12.885%2C18.596%2C18.03%2C27.75-11.63%2C10.287-22.28%2C19.594-22.28%2C19.594l31.5-1.344c7.023%2C15.705%2C11.562%2C31.02%2C13.905%2C45.72-16.35%2C8.71-59%2C29.373-59%2C29.373l59.625%2C13.875c-3.29%2C23.663-12.567%2C44.827-26.53%2C62.375-19.992%2C15.673-45.71%2C28.626-78.095%2C37.625-14.812-16.555-37.688-43.125-37.688-43.125l2.594%2C45.032c-31.706-11.987-64.888-30.877-95.874-54.283%2C6.14-19.402%2C20.97-61.843%2C20.97-61.843l-53.314%2C35.062c-26.48-23.94-50.176-50.712-68.562-78.156-.16-.976-.29-1.96-.438-2.938%2C21.096-4.256%2C50.813-9.75%2C50.813-9.75l-52.938-28.75c.747-17.35%2C3.87-34.413%2C9.532-50.625l24.186%2C7.75-17.625-23.718c.764-1.607%2C1.526-3.2%2C2.345-4.782%2C12.316-23.79%2C30.94-45.024%2C57.156-61.563%2C1.988-.446%2C3.987-.868%2C6-1.25%2C15.965%2C10.75%2C53.22%2C37.75%2C53.22%2C37.75l-12.346-40.905v.002ZM335.593%2C83.722c31.624%2C22.824%2C58.832%2C52.246%2C77.188%2C87.5-3.304%2C3.178-8.728%2C8.14-14.907%2C13.686-5.072-8.723-10.825-17.47-17.31-26.22-18.905-25.494-39.566-45.996-61.158-62.03%2C5.793-4.68%2C11.46-9.222%2C16.188-12.937h0ZM91.813%2C93.815c-7.594%2C8.932-14.254%2C18.618-19.876%2C28.906l-6.688-9c7.668-7.166%2C16.218-13.62%2C25.5-19.282.35-.214.71-.414%2C1.063-.626v.002ZM40.937%2C143.658l19.062%2C6.094c-6.742%2C19.452-10.13%2C39.89-10.53%2C60.47-.04-.085-.086-.168-.126-.25-8.156-17.232-13.81-34.135-16.53-50.376%2C2.316-5.497%2C5.046-10.808%2C8.124-15.938ZM23.687%2C196.846c2.588%2C7.178%2C5.518%2C14.227%2C8.78%2C21.125%2C5.833%2C12.32%2C12.784%2C24.582%2C20.657%2C36.655%2C1.034%2C5.658%2C2.275%2C11.277%2C3.72%2C16.844%2C4.967%2C19.042%2C12.262%2C37.398%2C21.72%2C54.655-43.19-45.79-58.08-90.447-54.876-129.28h0ZM429.717%2C214.283c4.823%2C17.464%2C7.594%2C36%2C7.938%2C55.532-2.115%2C14.63-6.24%2C28.865-12.562%2C42.375.395-2.295.74-4.602%2C1.03-6.937%2C3.503-28.023-.497-58.67-13.374-90.25l16.97-.72h-.002ZM85.313%2C297.188c21.512%2C24.926%2C46.452%2C48.21%2C73%2C68.5%2C24.674%2C18.86%2C50.713%2C35.157%2C76.81%2C47.625-32.876-2.213-62.096-14.434-86.81-33.28-27.445-20.928-49.14-50.188-63-82.844h0ZM427.593%2C344.97c-.803%2C2.886-1.646%2C5.761-2.53%2C8.624-8.284%2C26.728-21.605%2C43.83-38.345%2C54.312-12.555%2C7.862-27.34%2C12.04-43.875%2C12.906%2C5.973-2.924%2C11.756-6.222%2C17.313-9.875%2C12.958-8.522%2C24.402-18.87%2C34.03-30.687%2C13.3-10.688%2C24.41-22.53%2C33.407-35.28Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-rendingFrenzy: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20470.093%20476.752%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M338.72%2C0c-46.192%2C28.665-87.92%2C57.815-125.188%2C87.345-28.504-20.858-59.194-41.493-92.094-61.908%2C27.144%2C27.17%2C51.856%2C51.637%2C75.657%2C75.218-12.494%2C10.31-24.464%2C20.64-35.875%2C31.033C118.592%2C99.55%2C71.478%2C67.818%2C19.876%2C36.563c43.876%2C42.25%2C83.107%2C79.44%2C120.25%2C114.968-10.25%2C9.972-20.223%2C20.226-29.906%2C30.75-32.703-24.725-68.48-49.164-107.344-73.28%2C33.158%2C33.19%2C63.178%2C62.832%2C91.594%2C91.03C49.604%2C252.325%2C18.078%2C305.393%2C0%2C358.751c43.352-52.554%2C81.404-95.843%2C118-135.345%2C8.92%2C8.9%2C17.697%2C17.714%2C26.407%2C26.5-45.706%2C52.888-77.744%2C106.583-96.032%2C160.564%2C43.905-53.225%2C82.38-96.934%2C119.406-136.844%2C9.387%2C9.605%2C18.72%2C19.262%2C28%2C28.97-49.978%2C55.818-84.697%2C112.556-104.03%2C169.624%2C46.973-56.946%2C87.73-103.024%2C127.155-145.188%2C40.668%2C43.46%2C82.702%2C90.943%2C131.187%2C149.72-19.925-58.813-55.8-117.274-107.47-174.782%2C8.262-8.64%2C16.51-17.176%2C24.782-25.657%2C51.97%2C52.87%2C105.448%2C110.348%2C168.03%2C182.75-26.815-70.89-73.77-141.354-140.656-210.562%2C8.05-8.112%2C16.168-16.22%2C24.407-24.437%2C46.908%2C49.238%2C94.57%2C102.33%2C150.907%2C170.624-22.28-65.762-64.422-131.106-126.22-195.156%2C26.944-26.726%2C55.307-54.743%2C86.626-86.093-37.095%2C23.02-71.31%2C46.346-102.656%2C69.937-11.98-11.744-24.626-23.447-37.938-35.094%2C30.035-29.847%2C61.767-61.106%2C97.187-96.562-42.52%2C26.386-81.26%2C53.187-116.22%2C80.312-11.822-9.839-23.844-19.435-36.06-28.78C266.822%2C71.39%2C300.646%2C38.112%2C338.717.002l.003-.002ZM217.314%2C120.72c10.063%2C9.978%2C20.105%2C19.978%2C30.125%2C30-10.192%2C8.371-20.214%2C16.945-30.062%2C25.718-10.055-8.494-20.243-16.828-30.562-25%2C10.046-10.22%2C20.225-20.434%2C30.5-30.72v.002ZM267.344%2C170.78c11.128%2C11.248%2C22.165%2C22.485%2C33.157%2C33.845-9.159%2C7.335-18.191%2C14.826-27.094%2C22.47-10.528-10.215-21.271-20.207-32.22-29.97%2C8.691-8.809%2C17.41-17.59%2C26.157-26.344h0ZM164.22%2C174.656c9%2C8.656%2C17.979%2C17.334%2C26.937%2C26.033-8.795%2C8.487-17.391%2C17.176-25.782%2C26.062-9.33-8.041-18.8-15.917-28.406-23.625%2C9.11-9.65%2C18.182-19.092%2C27.25-28.47h.001ZM214.97%2C223.906c9.846%2C9.685%2C19.648%2C19.416%2C29.406%2C29.19-8.461%2C7.908-16.755%2C15.993-24.875%2C24.25-9.402-9.581-19.03-18.939-28.875-28.064%2C8.07-8.501%2C16.185-16.959%2C24.344-25.375h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-lightningStorm: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20476.969%20474%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M271.623%2C0l19%2C40.594L45.407%2C8.25l295.716%2C129.375-18.967-40.594%2C149.218%2C15.282L271.623%2C0ZM19.623%2C23.375l277.784%2C370.095-5.408-65.97%2C184.97%2C146.5-203.876-307.844%2C5.406%2C65.97L19.623%2C23.375ZM0%2C55.72l36.5%2C316.405%2C25.623-40.875%2C68.095%2C139.344-9.594-241.125-25.624%2C40.843L0%2C55.718v.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-pommelStrike: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20474.9%20475.7%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M137%2C0L62.47%2C20.98l15.9%2C55.79%2C187.13-52.82-6.7-23.95h-121.8ZM242.5%2C48l-131%2C37%2C61.1%2C216.4%2C130.9-37-61-216.4ZM295.8%2C100.9l-19.4%2C5.5%2C24%2C85%2C19.5-5.5-24.1-85ZM113.1%2C152.5l-19.5%2C5.5%2C24%2C85%2C19.5-5.4-24-85.1ZM82.2%2C180.1L0%2C203.3v54.3l96.5-27.4-14.3-50.1ZM369.6%2C199.8l-55.7%2C34.7%2C6.5%2C24.6%2C28.4-8%2C24.4%2C89.6-220.2%2C62.6c-8.4-30-16.9-60-25.3-90l27.3-7.7-6.3-22.7-70.53-3.8%2C40.83%2C39.6-108.74%2C48.9s117.34%2C4.1%2C114.34%2C4.6c-3.1.5-31.3%2C84.4-31.3%2C84.4l88-45.2%2C22.9%2C64.3%2C70.6-76.4%2C94.4%2C49.7-24.7-70.9%2C113.5-5.6-77.7-53.7%2C94.6-66.3-113.4%2C3.5%2C8.1-56.2ZM336%2C272.7l-187.3%2C52.9%2C15.7%2C55.9%2C187.2-52.9-15.6-55.9Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-rupture: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20479.424%20480.935%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C0c47.647%2C56.45%2C115.417%2C144.717%2C81.997%2C187.354%2C56.01%2C18.077%2C119.235%2C143.897%2C150.99%2C175.052%2C1.477-24.13%2C23.964-14.4%2C51.776%2C7.51%2C10.106-14.555%2C19.463-30.113%2C28.04-46.437-71.51-21.026-159.736-152.712-108.915-135.123C145.611%2C134.59%2C52.79%2C42.258.001%2C0h-.001ZM392.732.126c.013.28.022.557.035.838%2C3.71%2C31.3%2C4.355%2C64.147%2C2.094%2C97.443%2C35.58%2C48.458%2C39.525%2C120.59%2C24.836%2C190.244-11.444%2C54.268-34.302%2C107.376-64.797%2C147.394%2C23.478%2C24.646%2C40.965%2C44.89%2C40.965%2C44.89%2C56.49-99.385%2C157.33-291.34-3.133-480.808h0ZM391.867%2C129.974c-11.03%2C90.59-42.957%2C181.907-92.518%2C252.078%2C14.08%2C12.273%2C28.75%2C26.505%2C42.31%2C40.304%2C27.426-37.093%2C49.073-86.927%2C59.75-137.562%2C11.892-56.388%2C10.05-113.31-9.542-154.82h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-dazingBlow: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20477.548%20479.169%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M1.657%2C0v54.064l76.18%2C58.4%2C141.902-7.525%2C8.45%2C30.682-60.562%2C5.877%2C37.727%2C19.617-41.247%2C32.694%2C31.352-.88c-24.938%2C26.547-49.458%2C53.393-74.567%2C78.935-15.745-23.004-28.3-47.16-35.853-71.05l-4.64-14.67L7.259%2C259.294l80.737%2C80.73c-25.172%2C32.576-54.14%2C58.558-84.51%2C83l-3.486%2C2.808v4.474c0%2C14.94%2C4.783%2C27.6%2C13.722%2C36.057%2C8.94%2C8.457%2C21.28%2C12.248%2C34.582%2C12.247h4.7l2.802-3.773c23.665-31.872%2C49.886-60.988%2C82.572-84.426l83.473%2C83.47%2C73.14-73.142-14.67-4.637c-25.647-8.106-50.247-21.622-73.74-38.29%2C29.318-28.954%2C59.594-57.008%2C88.91-85.312l8.352%2C48.865%2C86.038%2C9.654%2C42.137%2C148.15h45.53v-58.333l-51.237-117.03-99.217-1.42-13.776-47.277c71.532-70.573%2C134.693-144.153%2C159.935-238.356l3.15-11.76h-13.41l-1.188.317c-72.727%2C19.486-131.702%2C59.128-184.81%2C106.556l.353-33.556-32.925%2C44.076-11.1-42.062-124.79-10.03L65.683%2C0H1.656h0ZM450.295%2C28.228c-25.662%2C78.606-80.402%2C143.39-143.707%2C206.694l-12.17-57.89-29.593%2C21.755-10.73-39.038c57.485-56.983%2C118.99-106.68%2C196.2-131.52h0ZM238.915%2C175.031l15.087%2C54.904%2C28.097-20.655%2C8.674%2C41.264c-34.216%2C33.456-70.35%2C66.784-105.384%2C101.817l-7.597%2C7.598%2C8.577%2C6.468c23.2%2C17.497%2C47.904%2C32.252%2C74.082%2C42.422l-38.603%2C38.604-81.322-81.322-6.39%2C4.323c-36.53%2C24.72-65.005%2C55.87-90.137%2C89.17-7.597-.68-13.423-3.04-17.434-6.835-4.11-3.888-6.865-9.7-7.574-18.362%2C31.536-25.61%2C62.357-53.572%2C88.947-89.65l4.768-6.47-79.02-79.016%2C38.594-38.6c9.494%2C24.59%2C23.172%2C48.765%2C39.827%2C71.45l6.44%2C8.777%2C7.7-7.698c38.51-38.51%2C74.93-79.613%2C112.665-118.19h.003Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-exposeArmor: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20444.845%20479.125%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M140.5%2C0l16.156%2C53.81L62.282%2C4.905l63.063%2C77.625L12.062%2C101.686l113.28%2C19.625-59.718%2C75.19%2C65.03-33.407-1.78%2C58.843%2C19.844-37.344v-64.218l.75-1.75%2C31.906-74.75L140.499%2C0h.001ZM286.75%2C0l-36.905%2C39.623%2C33.342%2C79.03.75%2C1.75v69.723l15.5%2C29.187-1.625-54.436%2C65.532%2C34.062-63.064-77.625%2C113.28-19.624-113.28-19.156L363.343%2C4.909l-92.44%2C47.906L286.748.005l.002-.005ZM216.155%2C7.84l-49.186%2C114.5v153.5l34.936%2C34.94c2.916-65.435%2C7.976-128.936%2C15.25-187.72%2C7.606%2C61.433%2C12.744%2C128.775%2C15.532%2C198l32.625-32.624V122.342L216.156%2C7.842v-.002ZM0%2C191.125l37.344%2C94.062%2C193.905%2C193.938h30.813c-66.34-68.503-128.483-139.002-180.625-205.875%2C74.705%2C58.246%2C155.104%2C130.333%2C231.312%2C205.874h31.063L93.688%2C228.968%2C0%2C191.124h0ZM444.845%2C191.125l-93.626%2C37.812-115.594%2C115.593%2C18.156%2C18.125c36.278-32.102%2C72.315-62.265%2C107.125-89.406-27.302%2C35.015-57.36%2C71.02-89.31%2C107.217l20.339%2C20.314%2C115.532-115.53%2C37.375-94.126h.003ZM152.935%2C427.218l-51.906%2C51.906h28.594c12.594-12.481%2C25.292-24.857%2C38.094-37.125l-14.78-14.783-.002.002ZM192.31%2C466.624c-3.995%2C4.173-8.003%2C8.34-12.03%2C12.5h24.53l-12.5-12.5Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-bloodlust: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20469.529%20473.655%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M218.998%2C0c103.702%2C97.21%2C183.912%2C194.304%2C250.529%2C282.09v-112.404c-7.062-6.39-14.155-12.677-21.343-18.844%2C2.986-3.465%2C4.813-7.972%2C4.813-12.906%2C0-10.927-8.855-19.78-19.782-19.78-6.285%2C0-11.875%2C2.96-15.5%2C7.53-43.25-34.448-88.287-64.956-134-91.312%2C1.006-2.025%2C1.594-4.274%2C1.594-6.688%2C0-8.35-6.773-15.125-15.125-15.125-5.416%2C0-10.142%2C2.848-12.813%2C7.126C244.717%2C12.86%2C231.922%2C6.296%2C218.996%2C0h.002ZM79.435%2C18.123c5.11%2C5.177%2C10.18%2C10.36%2C15.22%2C15.593-4.225%2C1.173-7.38%2C4.29-8.345%2C9-1.812%2C8.844%2C4.727%2C19.92%2C14.625%2C24.72%2C3.642%2C1.766%2C7.237%2C2.42%2C10.406%2C2.124-2.535%2C4.11-4%2C8.974-4%2C14.157%2C0%2C14.89%2C12.05%2C26.938%2C26.94%2C26.938%2C8.68%2C0%2C16.41-4.097%2C21.343-10.47%2C88.686%2C101.2%2C165.598%2C208.4%2C235.156%2C306.72-7.4%2C6.047-12.126%2C15.23-12.126%2C25.53%2C0%2C18.213%2C14.756%2C32.97%2C32.97%2C32.97%2C6.274%2C0%2C12.13-1.77%2C17.123-4.813%2C3.086%2C4.354%2C6.193%2C8.76%2C9.25%2C13.063h31.532v-114.345c-41.357-69.223-154.77-193.34-184.533-213.31%2C24.14%2C33.4%2C45.1%2C64.336%2C64.813%2C94.03C262.319%2C144.28%2C166.366%2C60.442%2C79.434%2C18.124h0ZM51.215%2C33.373c-1.919.092-3.8.571-5.53%2C1.406-7.176%2C3.433-10.214%2C12.042-6.78%2C19.22%2C3.432%2C7.175%2C12.04%2C10.213%2C19.218%2C6.78%2C7.176-3.433%2C10.214-12.042%2C6.78-19.22-2.574-5.38-8.08-8.445-13.687-8.186h-.001ZM406.965%2C53.748c-1.454.05-2.858.357-4.155.968-6.918%2C3.256-8.265%2C13.625-3%2C23.156%2C5.265%2C9.53%2C15.144%2C14.632%2C22.063%2C11.375%2C6.918-3.258%2C8.264-13.627%2C3-23.157-4.278-7.744-11.6-12.56-17.907-12.344v.002ZM255.841%2C88.998c-1.983.123-3.845.72-5.436%2C1.78-6.366%2C4.236-6.168%2C14.688.437%2C23.344%2C6.607%2C8.655%2C17.104%2C12.236%2C23.47%2C8s6.168-14.688-.438-23.344c-4.954-6.492-12.078-10.155-18.03-9.78h-.003ZM0%2C127.31c91.018%2C100.043%2C158.696%2C190.397%2C212%2C271.595-8.48-1.364-18.445%2C4.948-20.25%2C13.594-6.22%2C29.777%2C12.896%2C53.913%2C47.593%2C61.155h125.657C267.028%2C333.914%2C130.218%2C190.704%2C0%2C127.31ZM30.03%2C229.155c-3.807.078-7.195%2C1.333-9.406%2C3.844-5.052%2C5.738-2.15%2C15.785%2C6.47%2C22.436%2C8.62%2C6.65%2C19.697%2C7.396%2C24.75%2C1.656%2C5.052-5.74%2C2.182-15.786-6.438-22.437-4.85-3.74-10.48-5.6-15.375-5.5h0ZM77.218%2C267.28c-14.89%2C0-26.937%2C12.048-26.937%2C26.938s12.047%2C26.968%2C26.936%2C26.968%2C26.97-12.08%2C26.97-26.97-12.08-26.936-26.97-26.936h0ZM156.938%2C370.75c-10.928%2C0-19.782%2C8.853-19.782%2C19.78s8.854%2C19.78%2C19.78%2C19.78%2C19.782-8.853%2C19.782-19.78-8.854-19.78-19.78-19.78Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-guardian: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20421.396%20474.247%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M18.5.005c-4.548-.098-8.965%2C1.524-12.37%2C4.541C-1.378%2C11.178-2.088%2C22.64%2C4.544%2C30.148c4.394%2C4.974%2C10.906%2C6.945%2C16.986%2C5.792l57.838%2C65.475-50.373%2C44.498%2C24.188%2C27.38c9.69-21.368%2C22.255-39.484%2C37.427-54.65l6.91%2C36.188c25.092-6.29%2C49.834-10.563%2C74.366-12.873l-23.912-27.07-38.66-12.483c17.117-12.9%2C36.734-22.97%2C58.62-30.474l-24.19-27.385-50.37%2C44.496L35.454%2C23.472c1.79-5.835.617-12.43-3.72-17.34C28.378%2C2.323%2C23.575.099%2C18.499.004h0ZM402.897.005c-5.075.096-9.876%2C2.319-13.232%2C6.127-4.338%2C4.91-5.514%2C11.506-3.723%2C17.343l-57.92%2C65.568-50.37-44.497-24.188%2C27.385c21.884%2C7.504%2C41.5%2C17.573%2C58.62%2C30.472l-38.66%2C12.485-23.255%2C26.324c24.71%2C1.863%2C49.367%2C5.706%2C74.118%2C11.46l6.498-34.03c15.173%2C15.166%2C27.74%2C33.282%2C37.43%2C54.65l24.185-27.38-50.372-44.498%2C57.838-65.475c6.08%2C1.153%2C12.593-.818%2C16.987-5.792%2C6.63-7.508%2C5.92-18.97-1.586-25.602-3.405-3.017-7.822-4.639-12.37-4.541h0ZM216.472%2C158.515c-39.56-.098-79.467%2C5.226-120.633%2C16.095-2.046%2C90.448%2C34.484%2C209.35%2C118.47%2C259.905%2C81.295-49.13%2C122.402-169.902%2C120.552-259.914-39.75-10.496-78.91-15.988-118.39-16.086h0ZM99.296%2C312.015L12.43%2C410.353.23%2C474.247l61.9-19.994%2C68.49-77.535c-12.86-20.108-23.246-42.03-31.324-64.703h0ZM327.499%2C318.125c-8.69%2C22.238-19.577%2C43.634-32.706%2C63.142l64.473%2C72.986%2C61.898%2C19.994-12.2-63.894-81.466-92.23v.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-warBanner: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20387.189%20381.543%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M375.84%2C17.553c-3.72.82-7.68%2C3.38-10.87%2C7.9-208.61-97.68-93.19%2C125.01-313.82%2C16.25C31.2%2C71.993%2C9.3%2C162.803%2C0%2C203.173c217.63%2C107.29%2C105.2-109.94%2C302.28-22.13l-79.78%2C200.5c8.98-.19%2C17.83-.9%2C26.53-2.08L385.78%2C35.073c4.33-12.66-1.98-19.3-9.94-17.52ZM309.44%2C162.983c-10.69-34.92%2C11.17-101.9%2C47.27-118.84l-47.27%2C118.84Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-aegis: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20482.039%20482.039%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M240.385%2C0l-9.232%2C1.437-62.868%2C9.765%2C3.586%2C23.08c-12.948%2C4.269-25.473%2C9.727-37.416%2C16.303l-14.51-18.03-7.28%2C5.86-49.56%2C39.89%2C14.163%2C17.594c-9.221%2C10.234-17.449%2C21.321-24.573%2C33.111l-20.78-8.046-3.374%2C8.715-22.976%2C59.325%2C20.26%2C7.846c-2.928%2C13.637-4.537%2C27.525-4.805%2C41.47l-21.02%2C3.267%2C11.2%2C72.1%2C20.634-3.206c4.348%2C13.326%2C9.953%2C26.209%2C16.74%2C38.474l-16.165%2C13.012%2C45.75%2C56.84%2C15.858-12.764c10.55%2C9.461%2C21.999%2C17.869%2C34.183%2C25.104l-7.27%2C18.773%2C68.042%2C26.347%2C7.266-18.76c13.846%2C2.856%2C27.937%2C4.357%2C42.074%2C4.482l3.115%2C20.05%2C72.1-11.2-3.168-20.386c13.329-4.499%2C26.199-10.26%2C38.433-17.205l13.075%2C16.24%2C56.84-45.747-13.315-16.543c9.2-10.494%2C17.369-21.848%2C24.394-33.906l20.11%2C7.787%2C26.35-68.038-20.63-7.988c2.676-13.521%2C4.059-27.267%2C4.133-41.05l22.29-3.462-1.434-9.234-9.765-62.866-22.85%2C3.55c-4.412-12.951-10.019-25.464-16.746-37.378l18.103-14.57-5.86-7.28-39.89-49.56-18.28%2C14.715c-10.177-8.962-21.17-16.953-32.835-23.868l8.562-22.112-8.713-3.375-59.326-22.973-8.564%2C22.12c-13.151-2.713-26.525-4.202-39.95-4.45-.166-.004-.33-.002-.494-.005L240.387.003l-.002-.003ZM224.787%2C21.337l3.108%2C20.008-35.164%2C5.463-3.11-20.006%2C35.166-5.465ZM303.684%2C29.767l33.184%2C12.85-7.312%2C18.882-33.184-12.853%2C7.31-18.88h.002ZM246.905%2C41.98c10.2.34%2C20.456%2C1.458%2C30.687%2C3.406l-5.4%2C13.94%2C68.042%2C26.35%2C5.402-13.952c8.757%2C5.376%2C17.085%2C11.42%2C24.91%2C18.08l-11.842%2C9.53%2C45.75%2C56.84%2C12.098-9.735c4.991%2C9.139%2C9.266%2C18.65%2C12.787%2C28.45l-15.443%2C2.398%2C11.2%2C72.1%2C15.98-2.483c-.232%2C10.497-1.293%2C20.96-3.174%2C31.29l-15.395-5.964-3.373%2C8.714-22.977%2C59.327%2C15.975%2C6.188c-5.507%2C9.141-11.738%2C17.825-18.633%2C25.97l-10.926-13.575-7.278%2C5.86-49.56%2C39.89%2C11.24%2C13.964c-9.468%2C5.197-19.337%2C9.624-29.514%2C13.24l-2.78-17.908-9.235%2C1.433-62.866%2C9.766%2C2.828%2C18.202c-10.853-.275-21.664-1.435-32.328-3.47l6.7-17.3-8.713-3.375-59.327-22.974-6.695%2C17.29c-9.279-5.7-18.075-12.15-26.3-19.286l14.302-11.512-5.86-7.28-39.888-49.56-14.02%2C11.285c-5.056-9.485-9.345-19.36-12.826-29.53l17.688-2.75-1.436-9.232-9.765-62.867-17.182%2C2.67c.388-10.657%2C1.63-21.265%2C3.715-31.723l15.826%2C6.128%2C26.35-68.04-15.258-5.91c5.568-8.893%2C11.829-17.333%2C18.726-25.24l10.118%2C12.57%2C56.84-45.75-9.778-12.147c9.156-4.855%2C18.672-8.996%2C28.465-12.387l2.366%2C15.234%2C72.1-11.202-2.324-14.96v-.003ZM117.105%2C58.834l12.694%2C15.772-27.723%2C22.312-12.694-15.77%2C27.723-22.316v.002ZM400.758%2C89.482l22.313%2C27.722-15.774%2C12.696-22.312-27.72%2C15.773-12.697h0ZM316.514%2C131.482c-1.922-.016-3.843.046-5.76.187-23.033%2C1.7-45.933%2C15.003-61.29%2C44.006l-7.906%2C14.933-8.445-14.636c-20.227-35.054-56.5-47.824-87.093-41.81-30.592%2C6.012-55.328%2C29.383-53.947%2C72.85%2C1.278%2C40.24%2C29.05%2C67.447%2C63.59%2C97.54%2C30.045%2C26.176%2C64.672%2C53.784%2C85.763%2C93.478%2C22.093-39.507%2C57.856-65.95%2C88.133-91.453%2C17.386-14.644%2C33.017-28.982%2C43.86-44.736%2C10.846-15.755%2C17.13-32.66%2C16.456-54.243-1.262-40.46-26.58-66.478-56.316-73.916-5.576-1.402-11.298-2.14-17.047-2.2h.002ZM42.591%2C145.143l18.88%2C7.31-12.85%2C33.186-18.88-7.31s12.85-33.186%2C12.85-33.186ZM455.241%2C189.779l5.463%2C35.164-20.01%2C3.11-5.462-35.164%2C20.01-3.11h-.001ZM41.341%2C254.079l5.465%2C35.165-20.006%2C3.108-5.465-35.163%2C20.007-3.11h0ZM433.187%2C296.409l18.88%2C7.312-12.85%2C33.185-18.88-7.312%2C12.85-33.186h0ZM74.461%2C352.11l22.313%2C27.723-15.775%2C12.695-22.312-27.722%2C15.774-12.696ZM379.735%2C385.13l12.695%2C15.77-27.723%2C22.316-12.695-15.774%2C27.723-22.312ZM152.42%2C420.36l33.186%2C12.852-7.31%2C18.88-33.185-12.85%2C7.31-18.882h-.001ZM289.082%2C435.233l3.11%2C20.01-35.164%2C5.463-3.11-20.008%2C35.164-5.465h0Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-unbreakable: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20434.08%20473.916%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M151.41%2C0l13.176%2C64.625h41.957l-.002%2C18.69h-38.145l7.635%2C37.438h82.63l7.45-37.44h-40.88v-18.687h44.597L282.683.016%2C151.41.002v-.002ZM292.82%2C44.832l-18.823%2C94.608h-113.23l-18.99-93.127L0%2C95.989l148.973%2C247.342-60.967-203.168%2C17.9-5.37%2C39.247%2C130.784%2C72.35%2C10.62%2C71.53-10.696%2C39.094-130.664%2C17.905%2C5.358-60.018%2C200.587%2C148.066-244.865-141.26-51.085ZM283.112%2C285.282l-65.582%2C9.81-66.447-9.754%2C56.59%2C188.578v-152.847h18.69v152.847h.31l56.44-188.633h-.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-adrenaline: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20473.64%20473.639%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M63.891%2C0c46.3%2C37.518%2C62.25%2C65.617%2C53.53%2C93.102C79.824%2C63.87%2C40.104%2C47.112%2C0%2C32.598v36.608c36.057%2C8.926%2C71.558%2C21.116%2C104.804%2C46.54-13.053%2C16.635-34.362%2C33.918-62.75%2C53.73l81.99%2C35.407c-.466%2C3.448-.636%2C6.93-.507%2C10.407.573%2C15.082%2C7.218%2C28.014%2C16.3%2C38.914%2C7.177%2C8.615%2C15.9%2C16.206%2C25.077%2C23.468l-63.877%2C46.57L0%2C265.522v45.738c112.43%2C11.546%2C144.12%2C112.475%2C0%2C135.832v26.547h22.818l115.01-54.788c-46.436-55.056-3.446-101.025%2C44.4-127.89%2C20.244%2C15.41%2C39.46%2C30.752%2C47.838%2C48.93l8.487%2C18.41%2C8.485-18.41c3.777-8.196%2C9.772-15.81%2C17.055-23.118l15.303%2C115.51c49.028-28.366%2C133.015%2C6.997%2C141.394%2C41.355h52.85v-4.72l-68.87-83.24c-66.362%2C44.197-111.586-5.474-118.148-88.37%2C5.94-4.64%2C12.094-9.252%2C18.2-13.913%2C10.46-7.983%2C20.702-16.163%2C29.213-25.492%2C35.543%2C15.528%2C46.467%2C41.64%2C24.895%2C79.65l114.71-8.654v-43.199l-80.105%2C17.2c-5.02-24.163-5.625-41.7%2C22.13-65.864-21.682-3.325-43.248-5.917-64.68-7.045%2C1.468-4.655%2C2.386-9.55%2C2.58-14.7v-.002c.274-7.05-.69-14.093-2.848-20.81%2C32.581-10.003%2C64.05-23.323%2C93.912-39.75l-94.375-56.003c37.818-26.36%2C78.284-37.675%2C123.385-49.07V0h-70.675c-19.42%2C39.684-67.117%2C76.64-126.712%2C112.08%2C38.692%2C3.463%2C133.353%2C27.43%2C62.64%2C61.05-9.054-10.854-21.457-18.803-34.85-22.495-13.712-3.78-28.856-3.107-42.388%2C3.856-8.82%2C4.54-16.73%2C11.757-23.1%2C21.516-6.373-9.76-14.283-16.977-23.103-21.515-6.766-3.48-13.933-5.39-21.125-5.954-7.19-.566-14.406.21-21.262%2C2.1-16.032%2C4.418-30.65%2C14.93-39.792%2C29.236l-36.323-17.405c29.32-43.383%2C61.55-71.547%2C96.914-85.156C158.47%2C49.739%2C135.803%2C31.375%2C120.657.003h-56.766v-.003ZM189.124%2C167.023c1.23-.02%2C2.453.02%2C3.67.113%2C4.87.377%2C9.63%2C1.668%2C14.106%2C3.97%2C8.953%2C4.607%2C17.226%2C13.358%2C22.86%2C29.026l8.793%2C24.455%2C8.792-24.455c5.633-15.668%2C13.907-24.42%2C22.86-29.025%2C8.95-4.606%2C19.04-5.164%2C28.87-2.455%2C19.66%2C5.418%2C36.654%2C23.902%2C35.82%2C45.928-.386%2C10.132-4.602%2C18.803-11.982%2C27.66-7.38%2C8.86-17.894%2C17.5-29.428%2C26.302-18.87%2C14.403-40.57%2C29.167-54.933%2C49.314-14.363-20.146-36.062-34.91-54.933-49.314-11.533-8.803-22.048-17.443-29.428-26.3-7.38-8.86-11.597-17.53-11.98-27.66-.836-22.026%2C16.156-40.51%2C35.815-45.93%2C3.686-1.015%2C7.41-1.572%2C11.096-1.628h.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-goodBoys: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20408.373%20471.609%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M88.934%2C0l19.276%2C96.028c-12.818%2C11.406-22.692%2C26.194-29.42%2C43.24L0%2C130.63l64.453%2C63.37c-2.586%2C23.357.03%2C49.043%2C8.258%2C74.657l-42.033%2C54.215%2C68.018-1.02c15.12%2C22.18%2C33.708%2C39.877%2C53.62%2C51.962l10.68%2C90.296%2C40.932-68.666c17.495%2C4.93%2C35.126%2C5.94%2C51.883%2C2.508l63.63%2C73.657-19.257-95.92c12.855-11.425%2C22.75-26.248%2C29.487-43.34l78.702%2C8.628-68.175-67.03c.046-20.525-3.275-42.147-10.17-63.734l47.664-61.48-77.165%2C1.158c-12.764-18.617-27.715-34.38-43.844-46.768l-11.306-95.627-40.964%2C68.72c-17.463-4.908-35.06-5.91-51.786-2.485L88.934%2C0ZM190.732%2C93.45c44.422-.03%2C92.8%2C34.067%2C119.69%2C89.082%2C33.42%2C68.38%2C21.35%2C143.925-26.5%2C171.895%2C26.868-38.838%2C28.765-101.318.618-158.906-28.146-57.587-78.34-93.93-125.113-95.814%2C9.96-4.224%2C20.515-6.248%2C31.305-6.256h0ZM159.749%2C120.43c41.018-.062%2C85.61%2C31.394%2C110.477%2C82.274%2C31.83%2C65.127%2C19.096%2C137.01-28.506%2C160.9-.988.494-1.986.956-2.988%2C1.403-43.015-2.403-88.815-35.974-114.7-88.938-25.887-52.963-24.482-110.224-.3-146.35.96-.542%2C1.933-1.062%2C2.916-1.56%2C10.413-5.224%2C21.617-7.712%2C33.1-7.73h.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-bulwark: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20397.95%20468.351%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M194.71.007C133.165.412%2C71.063%2C9.547%2C7.24%2C27.819l-6.467%2C1.844-.28%2C6.72c-6.405%2C147.46%2C49.12%2C346.625%2C192.28%2C429.28l4.688%2C2.688%2C4.656-2.688c139.03-80.27%2C201.88-281.764%2C195.376-429.28l-.125-5.907-6.624-2.657C327.114%2C9.604%2C264.174.169%2C200.682.007c-1.984-.005-3.984-.013-5.97%2C0h-.002ZM195.054%2C18.632c1.86-.013%2C3.73-.006%2C5.593%2C0%2C59.47.15%2C118.43%2C8.782%2C178.28%2C25.343%2C3.956%2C139.034-57.428%2C327.223-181.468%2C402.625C69.369%2C368.954%2C14.909%2C183.58%2C19.021%2C44.006c60.047-16.615%2C118.307-25.005%2C176.034-25.373h-.001ZM198.835%2C35.193l-28.438%2C126.72-45.312-25.313%2C26.97%2C48.25-92.5%2C26.157%2C91.655%2C25.937-26.688%2C47.72%2C45.625-25.5%2C28.657%2C127.688%2C28.655-127.625%2C45.875%2C25.656-26.72-47.814%2C91.845-26-92.75-26.25%2C27.063-48.406-45.5%2C25.438-28.437-126.658Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-wideSwing: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20470.807%20466.219%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M213.314.011C131.224.711%2C50.444%2C37.746%2C0%2C103.636c26.08-22.208%2C57.052-38.305%2C90.063-47.5C27.823%2C109.84-4.52%2C195.226%2C10.437%2C281.416c1.081-27.888%2C7.632-55.293%2C19.28-80.655%2C1.154%2C51.488%2C18.492%2C102.143%2C52.22%2C143.344-38.003-76.004-22.756-193.02%2C39.844-240.313%2C11.844-6.056%2C24.272-10.893%2C37.093-14.436%2C107.067-29.575%2C216.937%2C36.285%2C245.627%2C146.655%2C16.562%2C63.723%2C2.315%2C128.343-33.25%2C177.313-4.68%2C4.68-9.852%2C8.942-15.47%2C12.875-5.947-1.8-11.324-4.187-16.03-7.22-12.01-7.737-19.51-19.947-20.656-33.624-2.096-24.99%2C14.13-53.014%2C46.53-80.53l-29.717-22.095c-16.038%2C39.73-38.954%2C61.946-64.188%2C65.186-13.836%2C1.777-27.648-2.677-39.03-11.844-8.41-6.77-15.634-16.017-21.5-27.406-16.69%2C19.306-20.72%2C43.155-16%2C67.28%2C5.483%2C28.04%2C23.502%2C55.683%2C47.28%2C72.252%2C21.973%2C15.312%2C49.595%2C21.202%2C74.813%2C16.375%2C9.043-1.732%2C17.75-4.832%2C25.843-9.344%2C18.055-8.925%2C34.396-20.126%2C47.25-35%2C65.17-57.975%2C96.26-151.12%2C72.47-242.658C434.864%2C69.926%2C340.087-.707%2C236.814.386c-1.612.017-3.23.042-4.845.094-6.22-.368-12.44-.523-18.656-.47h.001ZM122.657%2C145.136c-12.53-.06-18.07%2C15.934-6.063%2C23.656l188.688%2C133.032c4.29-6.45%2C8.42-14.145%2C12.25-23.187l-185.22-130.596c-3.503-2.022-6.764-2.89-9.655-2.905Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-allTolerances: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20466%20438.765%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M233%2C0c-18.38%2C16.053-47.185%2C33.518-77.79%2C49.72-31.429%2C16.64-63.92%2C31.224-88.325%2C39.985%2C1.978%2C11.276%2C8.625%2C32.908%2C19.18%2C58.363%2C12.599%2C30.386%2C29.991%2C66.674%2C48.845%2C101.404%2C18.854%2C34.731%2C39.218%2C67.959%2C57.514%2C92.11%2C9.148%2C12.075%2C17.812%2C21.879%2C25.164%2C28.322%2C7.351%2C6.443%2C13.412%2C8.861%2C15.412%2C8.861s8.06-2.418%2C15.412-8.861%2C16.016-16.247%2C25.164-28.322c18.296-24.151%2C38.66-57.379%2C57.514-92.11%2C18.854-34.73%2C36.246-71.018%2C48.846-101.404%2C10.554-25.455%2C17.201-47.087%2C19.18-58.363-24.406-8.761-56.897-23.345-88.327-39.985-30.604-16.202-59.41-33.667-77.789-49.72ZM100.975%2C9.716C68.995%2C25.706%2C36.817%2C41.638%2C4.943%2C57.732l-4.943%2C2.496v5.537c0%2C11%2C4.334%2C26.468%2C10.46%2C44.848%2C6.127%2C18.38%2C14.22%2C38.641%2C22.49%2C55.178l16.1-8.05c-7.73-15.463-15.637-35.2-21.51-52.821-4.531-13.591-7.698-26.391-8.933-33.895%2C29.99-15.11%2C60.25-30.124%2C90.418-45.209l-8.05-16.1h0ZM365.025%2C9.716l-8.05%2C16.1c30.169%2C15.085%2C60.429%2C30.1%2C90.418%2C45.21-1.234%2C7.503-4.402%2C20.303-8.932%2C33.894-5.874%2C17.62-13.78%2C37.358-21.512%2C52.822l16.102%2C8.049c8.268-16.537%2C16.362-36.799%2C22.488-55.178%2C6.127-18.381%2C10.461-33.848%2C10.461-44.848v-5.537l-4.943-2.496c-31.874-16.094-64.053-32.026-96.032-48.016h0ZM233%2C46.088l6.777%2C7.755c7.366%2C8.43%2C27.707%2C20.13%2C49.31%2C29.832%2C21.605%2C9.702%2C44.603%2C18.144%2C59.12%2C23.682l5.793%2C2.21v6.198c0%2C6.305-1.831%2C12.916-4.621%2C21.258s-6.69%2C18.085-11.389%2C28.78c-9.396%2C21.389-21.982%2C46.542-35.078%2C70.706-13.096%2C24.165-26.675%2C47.295-38.152%2C64.67-5.739%2C8.688-10.92%2C15.916-15.477%2C21.313-2.278%2C2.698-4.372%2C4.938-6.594%2C6.808-2.221%2C1.87-4.282%2C3.976-9.265%2C4.211l-.424.02-.424-.02c-4.983-.235-7.044-2.34-9.265-4.21-2.222-1.87-4.316-4.11-6.594-6.81-4.556-5.396-9.738-12.624-15.477-21.312-11.477-17.375-25.056-40.505-38.152-64.67-13.096-24.164-25.682-49.317-35.078-70.707-4.698-10.694-8.599-20.437-11.389-28.779-2.79-8.342-4.621-14.953-4.621-21.258v-6.199l5.793-2.209c14.517-5.538%2C37.515-13.98%2C59.12-23.682%2C21.603-9.702%2C41.944-21.402%2C49.31-29.832l6.777-7.755ZM233%2C72.242c-12.288%2C10.561-30.065%2C19.479-48.713%2C27.853-19.6%2C8.803-38.986%2C16.077-53.34%2C21.506.608%2C2.68%2C1.504%2C6.005%2C2.744%2C9.713%2C2.523%2C7.542%2C6.247%2C16.888%2C10.8%2C27.25%2C9.103%2C20.724%2C21.517%2C45.56%2C34.421%2C69.37%2C12.904%2C23.809%2C26.325%2C46.638%2C37.348%2C63.325%2C5.511%2C8.344%2C10.454%2C15.172%2C14.21%2C19.622%2C1.073%2C1.27%2C1.707%2C1.816%2C2.53%2C2.654.823-.838%2C1.457-1.384%2C2.53-2.654%2C3.756-4.45%2C8.699-11.278%2C14.21-19.622%2C11.023-16.687%2C24.444-39.516%2C37.348-63.326s25.318-48.645%2C34.422-69.369c4.552-10.362%2C8.276-19.708%2C10.799-27.25%2C1.074-3.191%2C1.989-6.432%2C2.744-9.713-14.354-5.429-33.74-12.703-53.34-21.506-18.648-8.374-36.425-17.292-48.713-27.853h0ZM176.104%2C376.24l-14.208%2C11.05s9.676%2C12.468%2C22.915%2C25.01c13.238%2C12.543%2C29.456%2C26.465%2C48.189%2C26.465s34.95-13.922%2C48.19-26.465c13.238-12.542%2C22.914-25.01%2C22.914-25.01l-14.208-11.05s-8.991%2C11.534-21.085%2C22.992c-12.095%2C11.458-27.878%2C21.533-35.811%2C21.533s-23.716-10.075-35.81-21.533c-12.095-11.458-21.086-22.992-21.086-22.992Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-rewatch: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20473.412%20473.421%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M235.643.005C163.607.368%2C92.653%2C33.539%2C46.463%2C95.975c-69.83%2C94.39-59.125%2C223.32%2C19.85%2C304.993l-37.238%2C50.332%2C151.22-22.613-22.616-151.219-43.137%2C58.308c-44.08-54.382-47.723-133.646-4.16-192.53%2C30.676-41.466%2C77.863-63.504%2C125.758-63.753%2C16.507-.087%2C32.924%2C2.433%2C48.645%2C7.467l-6.963-46.55c-23.402-4.768-47.49-5.106-71.017-.997-59.232%2C7.322-113.994%2C39.918-148.157%2C91.215C94.298%2C64.738%2C162.422%2C24.71%2C234.691%2C22.884c16.676-.418%2C33.34%2C1.207%2C49.62%2C4.84l48.608-7.268C301.779%2C6.55%2C268.599-.164%2C235.645.003l-.002.002ZM448.573%2C22.06l-151.217%2C22.61%2C22.614%2C151.22%2C41.126-55.588c42.204%2C54.29%2C45.092%2C132.048%2C2.187%2C190.043-40.22%2C54.367-108.82%2C75.32-170.19%2C57.566l6.522%2C43.598c28.597%2C5.504%2C58.07%2C4.454%2C86.203-3.07%2C37.448-5.957%2C73.34-22.05%2C103.16-47.728-49.196%2C54.65-122.615%2C77.514-191.744%2C64.34l-55.8%2C8.344c99.03%2C43.7%2C218.402%2C14.77%2C285.51-75.938%2C69.13-93.445%2C59.34-220.743-17.483-302.53l39.114-52.866h-.002Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-chat: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%201504.002%201317.441%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2030.5.1%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.4%20Build%203)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M0%2C928.002C0%2C998.721%2C57.279%2C1056.003%2C128.001%2C1056.003h192v197.439c0%2C35.52%2C28.8%2C63.999%2C63.999%2C63.999%2C17.952%2C0%2C34.209-7.359%2C45.759-19.2l242.241-242.238h704.001c70.719%2C0%2C128.001-57.279%2C128.001-128.001l-.003-800.001c0-70.719-57.279-128.001-128.001-128.001L128.001.003C57.279.003%2C0%2C57.282%2C0%2C128.001v800.001h0ZM384%2C560.001c0-44.16%2C35.841-80.001%2C80.001-80.001s80.001%2C35.841%2C80.001%2C80.001-35.841%2C80.001-80.001%2C80.001-80.001-35.841-80.001-80.001ZM672%2C560.001c0-44.16%2C35.841-80.001%2C80.001-80.001s80.001%2C35.841%2C80.001%2C80.001-35.841%2C80.001-80.001%2C80.001-80.001-35.841-80.001-80.001ZM960%2C560.001c0-44.16%2C35.841-80.001%2C80.001-80.001s80.001%2C35.841%2C80.001%2C80.001-35.841%2C80.001-80.001%2C80.001-80.001-35.841-80.001-80.001Z%22%2F%3E%0A%3C%2Fsvg%3E'); +} +@layer modifiers { + icon, + .icon { + --icon: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20viewBox%3D%220%200%20120%20120%22%3E%0A%20%20%3Cpath%0A%20%20%20%20d%3D%22M111.82%2C60.419c-26.177%2C4.938-46.869%2C25.364-52.226%2C51.388-4.951-26.164-25.377-46.844-51.414-52.201%2C26.177-4.951%2C46.869-25.377%2C52.214-51.414%2C4.938%2C26.177%2C25.39%2C46.882%2C51.427%2C52.226Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + display: inline-block; + width: 1em; + height: 1em; + background-color: var(--color, currentColor); + mask-image: var(--icon); + mask-repeat: no-repeat; + mask-size: cover; + } + icon[checkmark], + icon.checkmark { + --icon: var(--icon-checkmark); + width: 1em; + height: 1em; + } + icon[maxArmor], + icon.maxArmor { + --icon: var(--icon-maxArmor); + width: 1.009765625em; + height: 1em; + } + icon[criticalChance], + icon.criticalChance { + --icon: var(--icon-criticalChance); + width: 1em; + height: 1.0921501706484642em; + } + icon[criticalDamage], + icon.criticalDamage { + --icon: var(--icon-criticalDamage); + width: 1em; + height: 1.0062893081761006em; + } + icon[spin], + icon.spin { + --icon: var(--icon-spin); + width: 1em; + height: 1em; + } + icon[blockChance], + icon.blockChance { + --icon: var(--icon-blockChance); + width: 0.763671875em; + height: 1em; + } + icon[error], + icon.error { + --icon: var(--icon-error); + width: 1em; + height: 1em; + } + icon[defeat], + icon.defeat { + --icon: var(--icon-defeat); + width: 1em; + height: 1em; + } + icon[coin], + icon.coin { + --icon: var(--icon-coin); + width: 1.0011547344110856em; + height: 1em; + } + icon[menu], + icon.menu { + --icon: var(--icon-menu); + width: 1em; + height: 1em; + } + icon[info], + icon.info { + --icon: var(--icon-info); + width: 1em; + height: 1em; + } + icon[light], + icon.light { + --icon: var(--icon-light); + width: 1em; + height: 1em; + } + icon[spinner-circle], + icon.spinner-circle { + --icon: var(--icon-spinner-circle); + width: 1em; + height: 1em; + } + icon[success], + icon.success { + --icon: var(--icon-success); + width: 1em; + height: 1em; + } + icon[maxHealth], + icon.maxHealth { + --icon: var(--icon-maxHealth); + width: 1.080078125em; + height: 1em; + } + icon[__armor], + icon.__armor { + --icon: var(--icon-__armor); + width: 0.7841796875em; + height: 1em; + } + icon[dice], + icon.dice { + --icon: var(--icon-dice); + width: 1em; + height: 1.0062893081761006em; + } + icon[spinner-inner], + icon.spinner-inner { + --icon: var(--icon-spinner-inner); + width: 1em; + height: 1em; + } + icon[stun], + icon.stun { + --icon: var(--icon-stun); + width: 1em; + height: 1.005893909626719em; + } + icon[warning], + icon.warning { + --icon: var(--icon-warning); + width: 1em; + height: 1em; + } + icon[victory], + icon.victory { + --icon: var(--icon-victory); + width: 0.9580078125em; + height: 1em; + } + icon[magicChance], + icon.magicChance { + --icon: var(--icon-magicChance); + width: 1.159375em; + height: 1em; + } + icon[damage], + icon.damage { + --icon: var(--icon-damage); + width: 1em; + height: 1.009861932938856em; + } + icon[claw], + icon.claw { + --icon: var(--icon-claw); + width: 1.154296875em; + height: 1em; + } + icon[logo-apeegg-simple], + icon.logo-apeegg-simple { + --icon: var(--icon-logo-apeegg-simple); + width: 1em; + height: 1.3176470588235294em; + } + icon[cross], + icon.cross { + --icon: var(--icon-cross); + width: 1em; + height: 1em; + } + icon[dodgeChance], + icon.dodgeChance { + --icon: var(--icon-dodgeChance); + width: 1.009375em; + height: 1em; + } + icon[logo-apeegg], + icon.logo-apeegg { + --icon: var(--icon-logo-apeegg); + width: 1.734375em; + height: 1em; + } + icon[dark], + icon.dark { + --icon: var(--icon-dark); + width: 1em; + height: 1em; + } + icon[bite], + icon.bite { + --icon: var(--icon-bite); + width: 1.019047619047619em; + height: 1em; + } + icon[block], + icon.block { + --icon: var(--icon-block); + width: 0.763671875em; + height: 1em; + } + icon[bowshot], + icon.bowshot { + --icon: var(--icon-bowshot); + width: 1em; + height: 1.0037604859704947em; + } + icon[demoShout], + icon.demoShout { + --icon: var(--icon-demoShout); + width: 1.0243829018663457em; + height: 1em; + } + icon[fillArmor], + icon.fillArmor { + --icon: var(--icon-fillArmor); + width: 1em; + height: 1.1360294117647058em; + } + icon[cheese], + icon.cheese { + --icon: var(--icon-cheese); + width: 1.1668372569089047em; + height: 1em; + } + icon[lacerate], + icon.lacerate { + --icon: var(--icon-lacerate); + width: 1em; + height: 1.0130133024869867em; + } + icon[kick], + icon.kick { + --icon: var(--icon-kick); + width: 1em; + height: 1.0394668737060042em; + } + icon[punch], + icon.punch { + --icon: var(--icon-punch); + width: 0.6884765625em; + height: 1em; + } + icon[shieldBash], + icon.shieldBash { + --icon: var(--icon-shieldBash); + width: 1.1842708517016398em; + height: 1em; + } + icon[slam], + icon.slam { + --icon: var(--icon-slam); + width: 1.343124165554072em; + height: 1em; + } + icon[stab], + icon.stab { + --icon: var(--icon-stab); + width: 1em; + height: 1.0063492063492063em; + } + icon[slash], + icon.slash { + --icon: var(--icon-slash); + width: 1em; + height: 1.0224719101123596em; + } + icon[exposed], + icon.exposed { + --icon: var(--icon-exposed); + width: 1em; + height: 1em; + } + icon[concussed], + icon.concussed { + --icon: var(--icon-concussed); + width: 1em; + height: 1em; + } + icon[wounded], + icon.wounded { + --icon: var(--icon-wounded); + width: 1em; + height: 1em; + } + icon[cog], + icon.cog { + --icon: var(--icon-cog); + width: 1em; + height: 1em; + } + icon[h1h1], + icon.h1h1 { + --icon: var(--icon-h1h1); + width: 1em; + height: 1.009861932938856em; + } + icon[h1], + icon.h1 { + --icon: var(--icon-h1); + width: 1em; + height: 1.009861932938856em; + } + icon[h2], + icon.h2 { + --icon: var(--icon-h2); + width: 1em; + height: 1em; + } + icon[chevron], + icon.chevron { + --icon: var(--icon-chevron); + width: 1em; + height: 1em; + } + icon[vulnerable], + icon.vulnerable { + --icon: var(--icon-vulnerable); + width: 1em; + height: 1em; + } + icon[bleeding], + icon.bleeding { + --icon: var(--icon-bleeding); + width: 1em; + height: 1em; + } + icon[isBlocking], + icon.isBlocking { + --icon: var(--icon-isBlocking); + width: 1em; + height: 1em; + } + icon[earth], + icon.earth { + --icon: var(--icon-earth); + width: 1em; + height: 1em; + } + icon[fire], + icon.fire { + --icon: var(--icon-fire); + width: 1em; + height: 1em; + } + icon[frost], + icon.frost { + --icon: var(--icon-frost); + width: 1em; + height: 1em; + } + icon[lightning], + icon.lightning { + --icon: var(--icon-lightning); + width: 1em; + height: 1em; + } + icon[nature], + icon.nature { + --icon: var(--icon-nature); + width: 1em; + height: 1em; + } + icon[whirlwind], + icon.whirlwind { + --icon: var(--icon-whirlwind); + width: 1em; + height: 1em; + } + icon[hitChance], + icon.hitChance { + --icon: var(--icon-hitChance); + width: 1em; + height: 1em; + } + icon[stoneSkin], + icon.stoneSkin { + --icon: var(--icon-stoneSkin); + width: 1em; + height: 1em; + } + icon[smokeBomb], + icon.smokeBomb { + --icon: var(--icon-smokeBomb); + width: 1em; + height: 1em; + } + icon[warCry], + icon.warCry { + --icon: var(--icon-warCry); + width: 1em; + height: 1em; + } + icon[intimidatingRoar], + icon.intimidatingRoar { + --icon: var(--icon-intimidatingRoar); + width: 1em; + height: 1em; + } + icon[alorasTouch], + icon.alorasTouch { + --icon: var(--icon-alorasTouch); + width: 1em; + height: 1em; + } + icon[armorPenetration], + icon.armorPenetration { + --icon: var(--icon-armorPenetration); + width: 1em; + height: 1em; + } + icon[the-arena], + icon.the-arena { + --icon: var(--icon-the-arena); + width: 1em; + height: 1em; + } + icon[powerShot], + icon.powerShot { + --icon: var(--icon-powerShot); + width: 1em; + height: 1em; + } + icon[brawlers], + icon.brawlers { + --icon: var(--icon-brawlers); + width: 1em; + height: 1em; + } + icon[provocation], + icon.provocation { + --icon: var(--icon-provocation); + width: 1em; + height: 1em; + } + icon[buff], + icon.buff { + --icon: var(--icon-buff); + width: 1em; + height: 1.1641051065939516em; + } + icon[daggerThrow], + icon.daggerThrow { + --icon: var(--icon-daggerThrow); + width: 1.0042435815828559em; + height: 1em; + } + icon[weave], + icon.weave { + --icon: var(--icon-weave); + width: 1.0006341154090044em; + height: 1em; + } + icon[recharge], + icon.recharge { + --icon: var(--icon-recharge); + width: 1.011802575107296em; + height: 1em; + } + icon[skewer], + icon.skewer { + --icon: var(--icon-skewer); + width: 1.0871912744173609em; + height: 1em; + } + icon[stomp], + icon.stomp { + --icon: var(--icon-stomp); + width: 1.1098556401281552em; + height: 1em; + } + icon[endGame], + icon.endGame { + --icon: var(--icon-endGame); + width: 1em; + height: 1.0657790778190082em; + } + icon[riposte], + icon.riposte { + --icon: var(--icon-riposte); + width: 1.001260990482113em; + height: 1em; + } + icon[deflect], + icon.deflect { + --icon: var(--icon-deflect); + width: 1.0297125435540069em; + height: 1em; + } + icon[emberStrike], + icon.emberStrike { + --icon: var(--icon-emberStrike); + width: 1em; + height: 1em; + } + icon[sunder], + icon.sunder { + --icon: var(--icon-sunder); + width: 1em; + height: 1.1276531136051977em; + } + icon[aimedShot], + icon.aimedShot { + --icon: var(--icon-aimedShot); + width: 1em; + height: 1.0000042406662935em; + } + icon[frostStrike], + icon.frostStrike { + --icon: var(--icon-frostStrike); + width: 1em; + height: 1.0037378080755113em; + } + icon[stormStrike], + icon.stormStrike { + --icon: var(--icon-stormStrike); + width: 1em; + height: 1.0014340545784302em; + } + icon[wildGrowth], + icon.wildGrowth { + --icon: var(--icon-wildGrowth); + width: 1.0328794369977266em; + height: 1em; + } + icon[stoneShatter], + icon.stoneShatter { + --icon: var(--icon-stoneShatter); + width: 1em; + height: 1.0001220040639973em; + } + icon[cut], + icon.cut { + --icon: var(--icon-cut); + width: 1.0251596815119433em; + height: 1em; + } + icon[doublePersona], + icon.doublePersona { + --icon: var(--icon-doublePersona); + width: 1em; + height: 1.510372781820503em; + } + icon[ripAndTear], + icon.ripAndTear { + --icon: var(--icon-ripAndTear); + width: 1.004261163766037em; + height: 1em; + } + icon[pounce], + icon.pounce { + --icon: var(--icon-pounce); + width: 1.0616277099515754em; + height: 1em; + } + icon[unstoppable], + icon.unstoppable { + --icon: var(--icon-unstoppable); + width: 1.0054011434739345em; + height: 1em; + } + icon[poisonousSting], + icon.poisonousSting { + --icon: var(--icon-poisonousSting); + width: 1.0871912744173609em; + height: 1em; + } + icon[venom], + icon.venom { + --icon: var(--icon-venom); + width: 1.0157030768249378em; + height: 1em; + } + icon[gore], + icon.gore { + --icon: var(--icon-gore); + width: 1.008525591477349em; + height: 1em; + } + icon[haymaker], + icon.haymaker { + --icon: var(--icon-haymaker); + width: 1em; + height: 1em; + } + icon[charge], + icon.charge { + --icon: var(--icon-charge); + width: 1em; + height: 1em; + } + icon[execute], + icon.execute { + --icon: var(--icon-execute); + width: 1em; + height: 1.022159265556518em; + } + icon[boom], + icon.boom { + --icon: var(--icon-boom); + width: 1.0054733469994108em; + height: 1em; + } + icon[slingshot], + icon.slingshot { + --icon: var(--icon-slingshot); + width: 1em; + height: 1.0392568895808414em; + } + icon[dragonBreath], + icon.dragonBreath { + --icon: var(--icon-dragonBreath); + width: 1.0012087797773848em; + height: 1em; + } + icon[hatch], + icon.hatch { + --icon: var(--icon-hatch); + width: 1em; + height: 1.0000021008138553em; + } + icon[shrug], + icon.shrug { + --icon: var(--icon-shrug); + width: 1.0238611713665944em; + height: 1em; + } + icon[potion], + icon.potion { + --icon: var(--icon-potion); + width: 1em; + height: 1.2183816713018143em; + } + icon[armory], + icon.armory { + --icon: var(--icon-armory); + width: 1em; + height: 1.0593799550349072em; + } + icon[experience], + icon.experience { + --icon: var(--icon-experience); + width: 1em; + height: 1.0000021593981325em; + } + icon[immobilize], + icon.immobilize { + --icon: var(--icon-immobilize); + width: 1.0795011423958065em; + height: 1em; + } + icon[dot], + icon.dot { + --icon: var(--icon-dot); + width: 1em; + height: 1.0042502596910785em; + } + icon[debuff], + icon.debuff { + --icon: var(--icon-debuff); + width: 1em; + height: 1.1646205357142858em; + } + icon[uninterruptable], + icon.uninterruptable { + --icon: var(--icon-uninterruptable); + width: 1.0000687010505016em; + height: 1em; + } + icon[crystal], + icon.crystal { + --icon: var(--icon-crystal); + width: 1em; + height: 1.3999725580382578em; + } + icon[stunned], + icon.stunned { + --icon: var(--icon-stunned); + width: 0.97265625em; + height: 1em; + } + icon[meat], + icon.meat { + --icon: var(--icon-meat); + width: 1.4088675101955455em; + height: 1em; + } + icon[confused], + icon.confused { + --icon: var(--icon-confused); + width: 1em; + height: 1.1522464018198697em; + } + icon[all-elements], + icon.all-elements { + --icon: var(--icon-all-elements); + width: 1em; + height: 1.0000042535362836em; + } + icon[taunt], + icon.taunt { + --icon: var(--icon-taunt); + width: 1.0098144520966281em; + height: 1em; + } + icon[dynamite], + icon.dynamite { + --icon: var(--icon-dynamite); + width: 1.110253254955418em; + height: 1em; + } + icon[berserk], + icon.berserk { + --icon: var(--icon-berserk); + width: 1.0349795454545454em; + height: 1em; + } + icon[crushingBlow], + icon.crushingBlow { + --icon: var(--icon-crushingBlow); + width: 1em; + height: 1.0186496061046793em; + } + icon[sound-off], + icon.sound-off { + --icon: var(--icon-sound-off); + width: 1.2601250000000002em; + height: 1em; + } + icon[sound-on], + icon.sound-on { + --icon: var(--icon-sound-on); + width: 1.2601250000000002em; + height: 1em; + } + icon[mend], + icon.mend { + --icon: var(--icon-mend); + width: 1em; + height: 1.107718804920914em; + } + icon[spikeWall], + icon.spikeWall { + --icon: var(--icon-spikeWall); + width: 1em; + height: 1.011940942418217em; + } + icon[rendingFrenzy], + icon.rendingFrenzy { + --icon: var(--icon-rendingFrenzy); + width: 1em; + height: 1.0141652821888434em; + } + icon[lightningStorm], + icon.lightningStorm { + --icon: var(--icon-lightningStorm); + width: 1.0062637130801688em; + height: 1em; + } + icon[pommelStrike], + icon.pommelStrike { + --icon: var(--icon-pommelStrike); + width: 1em; + height: 1.001684565171615em; + } + icon[rupture], + icon.rupture { + --icon: var(--icon-rupture); + width: 1em; + height: 1.0031516987051128em; + } + icon[dazingBlow], + icon.dazingBlow { + --icon: var(--icon-dazingBlow); + width: 1em; + height: 1.0033944231784029em; + } + icon[exposeArmor], + icon.exposeArmor { + --icon: var(--icon-exposeArmor); + width: 1em; + height: 1.0770605491800513em; + } + icon[bloodlust], + icon.bloodlust { + --icon: var(--icon-bloodlust); + width: 1em; + height: 1.0087875296307576em; + } + icon[guardian], + icon.guardian { + --icon: var(--icon-guardian); + width: 1em; + height: 1.1254188459311432em; + } + icon[warBanner], + icon.warBanner { + --icon: var(--icon-warBanner); + width: 1.0147978078486566em; + height: 1em; + } + icon[aegis], + icon.aegis { + --icon: var(--icon-aegis); + width: 1em; + height: 1em; + } + icon[unbreakable], + icon.unbreakable { + --icon: var(--icon-unbreakable); + width: 1em; + height: 1.0917711021009953em; + } + icon[adrenaline], + icon.adrenaline { + --icon: var(--icon-adrenaline); + width: 1.000002111312624em; + height: 1em; + } + icon[goodBoys], + icon.goodBoys { + --icon: var(--icon-goodBoys); + width: 1em; + height: 1.1548486310309447em; + } + icon[bulwark], + icon.bulwark { + --icon: var(--icon-bulwark); + width: 1em; + height: 1.176909159442141em; + } + icon[wideSwing], + icon.wideSwing { + --icon: var(--icon-wideSwing); + width: 1.009840868776262em; + height: 1em; + } + icon[allTolerances], + icon.allTolerances { + --icon: var(--icon-allTolerances); + width: 1.0620719519560584em; + height: 1em; + } + icon[rewatch], + icon.rewatch { + --icon: var(--icon-rewatch); + width: 1em; + height: 1.000019010924945em; + } + icon[chat], + icon.chat { + --icon: var(--icon-chat); + width: 1.1416086185263703em; + height: 1em; + } +} diff --git a/css/animations.css b/css/animations.css new file mode 100644 index 00000000..c2fd379f --- /dev/null +++ b/css/animations.css @@ -0,0 +1,384 @@ +@keyframes attack-blocked { + 0%, + 100% { + background-color: transparent; + opacity: 0; + } + 25% { + background-color: gray; + opacity: 1; + } +} + +@keyframes sprite-hurt { + 0% { + background-color: transparent; + opacity: 0; + } + 25% { + background-color: oklch(from var(--hue-red) l c h / 0.4); + opacity: 1; + } + 100% { + background-color: transparent; + opacity: 0; + } +} + +@keyframes bb-basicAttackFast { + 0% { + transform: translate(var(--position-x), var(--position-y)); + } + 90% { + transform: translate(var(--attack-start-x), var(--attack-start-y)); + animation-timing-function: cubic-bezier(0.2, 0.8, 0.5, 1.33); + } + 100% { + transform: translate(var(--attack-end-x), var(--attack-end-y)); + } +} + +@keyframes bb-basicAttackRegular { + 0% { + transform: translate(var(--position-x), var(--position-y)); + } + 90% { + transform: translate(var(--attack-start-x), var(--attack-start-y)); + animation-timing-function: cubic-bezier(0.2, 0.8, 0.5, 1.33); + } + 100% { + transform: translate(var(--attack-end-x), var(--attack-end-y)); + } +} + +@keyframes bb-basicAttackSlow { + 0% { + transform: translate(var(--position-x), var(--position-y)); + } + 90% { + transform: translate(var(--attack-start-x), var(--attack-start-y)); + animation-timing-function: cubic-bezier(0.2, 0.8, 0.5, 1.33); + } + 100% { + transform: translate(var(--attack-end-x), var(--attack-end-y)); + } +} + +@keyframes bb-pounce { + 0% { + transform: translate(var(--position-x), var(--position-y)); + animation-timing-function: cubic-bezier(0.3, 0, 0.4, 1); + } + 80% { + transform: translate(var(--attack-start-x), var(--attack-start-y)) + translateY(calc(var(--unit) * 1)); + animation-timing-function: cubic-bezier(0.25, 0.7, 0.4, 1); + } + 90% { + transform: translate(var(--attack-end-x), var(--attack-end-y)) + translateY(calc(var(--unit) * -2.5)); + animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1); + } + 100% { + transform: translate(var(--attack-end-x), var(--attack-end-y)); + } +} + +@keyframes bb-whirlwind { + 0% { + transform: translate(var(--position-x), var(--position-y)) scaleX(1); + } + 50% { + transform: translate(var(--position-x), var(--position-y)) scaleX(-1); + } + 100% { + transform: translate(var(--position-x), var(--position-y)) scaleX(1); + } +} + +@keyframes bb-boom { + 0% { + transform: translate(var(--position-x), var(--position-y)) scale(1); + animation-timing-function: ease-in; + } + 85% { + transform: translate(var(--position-x), var(--position-y)) scale(0.95); + animation-timing-function: cubic-bezier(0.15, 0.9, 0.25, 1.6); + } + 90% { + transform: translate(var(--position-x), var(--position-y)) scale(1.03); + animation-timing-function: ease-out; + } + 95% { + transform: translate(var(--position-x), var(--position-y)) scale(0.99); + } + 100% { + transform: translate(var(--position-x), var(--position-y)) scale(1); + } +} + +@keyframes bb-stomp { + 0% { + rotate: 0deg; + animation-timing-function: ease-in; + } + 90% { + rotate: calc(-13deg * var(--dir, 1)); + animation-timing-function: cubic-bezier(0.5, 0, 0.7, 0); + } + 97% { + rotate: calc(6deg * var(--dir, 1)); + animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); + } + 100% { + rotate: 0deg; + } +} + +@keyframes bb-catchThrow { + 0% { + rotate: 0deg; + animation-timing-function: ease-in; + } + 58% { + rotate: calc(-10deg * var(--dir, 1)); + animation-timing-function: cubic-bezier(0.5, 0, 0.75, 0); + } + 74% { + rotate: calc(10deg * var(--dir, 1)); + animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); + } + 80% { + rotate: 0deg; + } + 100% { + rotate: 0deg; + } +} + +@keyframes projectile-travel { + to { + translate: var(--p-end-x) var(--p-end-y); + } +} + +@keyframes projectile-hop { + 0% { + transform: translateY(0); + animation-timing-function: ease-out; + } + 50% { + transform: translateY(calc(var(--p-arc, 0px) * -1)); + animation-timing-function: ease-in; + } + 100% { + transform: translateY(0); + } +} + +@keyframes projectile-spin { + to { + rotate: var(--p-spin, 0deg); + } +} + +@keyframes bb-wiggle { + 0%, + 55% { + rotate: 0deg; + } + 61% { + rotate: -7deg; + } + 67% { + rotate: 7deg; + } + 73% { + rotate: -5deg; + } + 79% { + rotate: 4deg; + } + 85% { + rotate: -2deg; + } + 91%, + 100% { + rotate: 0deg; + } +} + +@keyframes sprite-ability-release { + from { + --squish-x: 0.94; + --squish-y: 0.89; + } + 55% { + --squish-x: 1.05; + --squish-y: 1.07; + } + to { + --squish-x: 1; + --squish-y: 1; + } +} + +@keyframes hp-floater-fade { + 0% { + opacity: 0; + } + 20% { + opacity: 1; + } + 80% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes hp-floater-heal-fade { + 0% { + opacity: 1; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes hp-floater-x { + 0% { + transform: translateY(var(--y-offset, 0)) translateX(calc(var(--dir, 1) * -15px)) + scale(calc(var(--scale, 1) * 3)); + } + 100% { + transform: translateY(var(--y-offset, 0)) + translateX(calc(var(--dir, 1) * (5px + var(--rnd, 0.5) * 25px))) scale(var(--scale, 1)); + } +} + +@keyframes hp-floater-y { + 0% { + transform: translateY(0); + } + 100% { + transform: translateY(-40px); + } +} + +@keyframes hp-floater-heal-y { + 0% { + transform: translateY(0); + } + 100% { + transform: translateY(-20px); + } +} + +@keyframes combat-shake { + 0%, + 100% { + transform: translate(0, 0); + } + 20% { + transform: translate(calc(var(--unit) * -1), calc(var(--unit) * 0.5)); + } + 40% { + transform: translate(calc(var(--unit) * 0.75), calc(var(--unit) * -0.75)); + } + 60% { + transform: translate(calc(var(--unit) * -0.75), calc(var(--unit) * -0.5)); + } + 80% { + transform: translate(calc(var(--unit) * 0.5), calc(var(--unit) * 0.75)); + } +} + +@keyframes combatant-armor-hit { + 0% { + transform: scale(1.5); + filter: brightness(2); + } + 100% { + transform: scale(1); + filter: brightness(1); + } +} + +@keyframes status-announce { + 0% { + opacity: 0; + scale: 0.7; + } + 12% { + opacity: 1; + scale: 1; + } + 57% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes status-pop { + 0% { + scale: 0; + } + 60% { + scale: 1.2; + } + 100% { + scale: 1; + } +} + +@keyframes immobilized-in { + 0% { + opacity: 0; + scale: 2.4; + animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.4); + } + 62% { + opacity: 0.9; + scale: 1; + animation-timing-function: ease-out; + } + 76% { + scale: 1.08 0.85; + animation-timing-function: ease-in-out; + } + 90% { + scale: 0.98 1.04; + } + 100% { + opacity: 0.9; + scale: 1; + } +} + +@keyframes immobilized-ability-impact { + 35% { + translate: 0 calc(var(--unit) * 0.75); + } + 75% { + translate: 0 calc(var(--unit) * -0.2); + } +} + +@keyframes live-pulse { + 0% { + box-shadow: 0 0 0 0 oklch(from var(--hue-red) l c h / 0.7); + } + 70% { + box-shadow: 0 0 0 calc(var(--unit) * 2.5) oklch(from var(--hue-red) l c h / 0); + } + 100% { + box-shadow: 0 0 0 0 oklch(from var(--hue-red) l c h / 0); + } +} diff --git a/css/index.css b/css/index.css new file mode 100644 index 00000000..04342921 --- /dev/null +++ b/css/index.css @@ -0,0 +1,1627 @@ +@import url('https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:wght@300;400;500;600;700&family=Cinzel:wght@400;500;600;700&family=Alfa+Slab+One&family=Bree+Serif&display=swap'); +@import url('/node_modules/@ape-egg/vibe/vibe.css'); +@import url('/css/stylecheat.css'); +@import url('/css/Iconice.css'); +@import url('/css/animations.css'); + +:root, +[battleborn-brawlers] { + --unit: 4px; + --font-sans: 'Fira Sans Condensed', 'Trebuchet MS', sans-serif; + --font-heading: 'Cinzel', serif; + --font-display: 'Alfa Slab One', cursive; + --font-accent: 'Bree Serif', serif; + --radius: calc(var(--unit) * 1.5); + + --background: oklch(0.94 0.02 60); + --foreground: oklch(0.2 0 0); + --muted: oklch(0.7 0.03 50); + --c-panel: oklch(0.975 0.016 85); + --c-inset: oklch(0.935 0.028 82); + --c-fg: oklch(0.27 0.03 55); + --c-muted: oklch(0.5 0.035 60); + --c-line: oklch(0.42 0.05 55 / 0.22); + --c-accent: var(--gold-deep); + --primary: oklch(0.6 0.15 70); + --primary-foreground: #fff; + --destructive: oklch(0.55 0.2 25); + + --sidebar: oklch(0.2 0.03 50); + --sidebar-foreground: oklch(0.85 0.02 60); + --sidebar-primary: oklch(0.6 0.15 70); + + --white: #fff; + --black: #000; + --z-cutscene: 60; + --slate: #374151; + --stone: #b3ad9f; + --combatant-name-color: #57534e; + + --coin-copper: oklch(0.666 0.156 63); + --coin-silver: oklch(0.705 0.015 286); + --coin-gold: oklch(0.795 0.17 86); + --coin-platinum: oklch(0.715 0.143 215); + + --hue-red: oklch(0.55 0.2 27); + --hue-orange: oklch(0.65 0.18 55); + --hue-yellow: oklch(0.78 0.16 90); + --hue-green: oklch(0.6 0.17 142); + --hue-blue: oklch(0.55 0.18 250); + --hue-blue-frost: oklch(0.78 0.08 220); + --hue-purple: oklch(0.52 0.18 305); + --hue-brown: oklch(0.5 0.08 65); + + --rarity-common: oklch(0.65 0.01 60); + --rarity-uncommon: var(--hue-green); + --rarity-rare: var(--hue-blue); + --rarity-epic: var(--hue-purple); + --rarity-legendary: var(--hue-orange); + --rarity-exotic: var(--hue-red); + + --element-fire: var(--hue-red); + --element-frost: var(--hue-blue-frost); + --element-earth: var(--hue-brown); + --element-nature: var(--hue-green); + --element-lightning: var(--hue-yellow); + --element-rainbow: conic-gradient( + from 90deg, + var(--element-fire), + var(--element-lightning), + var(--element-nature), + var(--element-frost), + var(--element-earth), + var(--element-fire) + ); + /* Soft pastel sweep of every element — the light "all elements" surface that + the ability bar's hybrid tiles use (matches elementSpectrum(..., 'face')). */ + --element-spectrum: linear-gradient( + 105deg, + oklch(from var(--element-fire) 0.95 0.045 h), + oklch(from var(--element-lightning) 0.95 0.045 h), + oklch(from var(--element-nature) 0.95 0.045 h), + oklch(from var(--element-frost) 0.95 0.045 h), + oklch(from var(--element-earth) 0.95 0.045 h) + ); + + --status-bleeding: oklch(from var(--hue-red) l calc(c * 0.6) h); + --status-wounded: oklch(from var(--status-bleeding) calc(l * 0.85) c h); + --status-poisoned: oklch(from var(--hue-green) l calc(c * 0.6) h); + --status-envenomed: oklch(from var(--status-poisoned) calc(l * 0.85) c h); + --status-stunned: oklch(from var(--hue-purple) l calc(c * 0.6) h); + --status-concussed: oklch(from var(--status-stunned) calc(l * 0.85) c h); + --status-vulnerable: oklch(from var(--hue-blue) l calc(c * 0.6) h); + --status-exposed: oklch(from var(--status-vulnerable) calc(l * 0.85) c h); + --status-cocooned: oklch(0.75 0.04 95); + --status-webbed: oklch(from var(--status-cocooned) calc(l * 0.85) c h); + + --status-buff: oklch(from var(--hue-green) calc(l * 0.85) c h); + --status-debuff: oklch(from var(--hue-red) calc(l * 0.85) c h); + + --team-1: var(--hue-red); + --team-2: var(--hue-blue); + --team-3: var(--hue-green); + --team-4: var(--hue-yellow); + --team-5: var(--hue-purple); + --team-6: var(--hue-orange); + --team-7: var(--hue-blue-frost); + --team-8: oklch(0.62 0.21 340); + + --icon-arrow-up: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23000%22%20d%3D%22M12%202%202%2014h6v8h8v-8h6z%22%2F%3E%3C%2Fsvg%3E'); + --icon-arrow-down: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23000%22%20d%3D%22M12%2022%2022%2010h-6V2H8v8H2z%22%2F%3E%3C%2Fsvg%3E'); + + --floater-default: oklch(from var(--hue-red) calc(l * 0.75) c h); + --floater-heal: var(--hue-green); + --health-buffer: var(--floater-default); + --health-ghost: oklch(from var(--floater-default) calc(l * 1.9) calc(c * 0.45) h / 0.5); + + --scrim-1: rgb(0 0 0 / 0.1); + --scrim-2: rgb(0 0 0 / 0.25); + --scrim-3: rgb(0 0 0 / 0.5); + --sheen-1: rgb(255 255 255 / 0.1); + --sheen-2: rgb(255 255 255 / 0.25); + --sheen-3: rgb(255 255 255 / 0.5); + + --divider: var(--scrim-2); + + --gold-shine: #fedb37; + --gold-warm: #fdb931; + --gold-deep: #b8860b; + --gold-shadow: #8a6e2f; + + --modal-frame: oklch(from var(--card) calc(l - 0.04) 0 h); + + --bar-bg: + linear-gradient( + oklch(from var(--c-accent) l c h / 0.1), + oklch(from var(--c-accent) l c h / 0.1) + ), + var(--c-panel); +} + +combat-frame, +combat-viewport, +combat-arena, +combat-preview-arena, +combat-preview-ring { + --ring-d: calc(var(--unit) * 125); + --combat-outer-d: calc( + (var(--ring-d) + var(--unit) * 15 + var(--unit) * 66 * var(--combat-scale, 1)) * 0.855 + ); +} + +badge[neutral], +badge[red], +badge[gold], +badge[green], +badge[health] { + background: oklch(from currentColor l c h / 0.08); + border: 1px solid currentColor; +} + +badge[health] { + color: hsl(var(--health-hue) 70% 42%); +} + +[dark] badge[health] { + color: hsl(var(--health-hue) 70% 62%); +} + +badge[neutral] { + color: oklch(from var(--slate) calc(l * 0.85) c h / 0.75); +} + +badge[red] { + color: oklch(from var(--hue-red) calc(l * 0.85) c h); +} + +badge[gold] { + color: oklch(from var(--gold-deep) calc(l * 0.85) c h); +} + +badge[green] { + color: oklch(from var(--hue-green) calc(l * 0.75) c h); +} + +[dark] badge[neutral] { + color: oklch(from var(--slate) 0.78 c h / 0.9); +} + +[dark] badge[red] { + color: oklch(from var(--hue-red) 0.72 c h); +} + +[dark] badge[gold] { + color: oklch(from var(--gold-deep) 0.82 c h); +} + +[dark] badge[green] { + color: oklch(from var(--hue-green) 0.78 c h); +} + +badge[clickable] { + cursor: pointer; +} + +@property --status-spread { + syntax: ''; + inherits: true; + initial-value: 0deg; +} + +@property --squish-x { + syntax: ''; + inherits: false; + initial-value: 1; +} + +@property --squish-y { + syntax: ''; + inherits: false; + initial-value: 1; +} + +[data-hidden='true'] { + display: none; +} + +/* Available Abilities lives in a collapsible accordion. A tile added while the + accordion is collapsed (grid-template-rows: 0fr + overflow: hidden) is skipped + by Chromium's paint and stays invisible after the accordion opens. Switching + overflow to visible once the open animation has finished forces that repaint. + The transition delay keeps the content clipped during the open reveal (so the + open animation is unchanged); removing [open] drops this rule and the base + overflow:hidden returns instantly, so the close animation is unchanged too. + App-level override scoped to the brawler slots — stylecheat is untouched. */ +brawler-slot accordion[open] > accordion-content { + overflow: visible; + transition: overflow 0s 200ms; + transition-behavior: allow-discrete; +} + +/* Canonical element colour — any element-attributed element exposes its theme + hue as --element-color, so the element→colour mapping lives in one place. + Consumers below (ability slabs, race dots, icons, equipment splashes) read it. */ +[fire] { + --element-color: var(--element-fire); +} +[frost] { + --element-color: var(--element-frost); +} +[earth] { + --element-color: var(--element-earth); +} +[nature] { + --element-color: var(--element-nature); +} +[lightning] { + --element-color: var(--element-lightning); +} +/* The Heirloom's "all" element — every hue at once. --element-color stays a solid + so the oklch-derived text/borders keep working; --element-rainbow paints the + prominent surfaces (emblem, dot) with the full spread. */ +[all] { + --element-color: var(--hue-purple); +} + +/* Element icons render in their original multi-tone colours everywhere: the + source SVG painted as a background image, not the monochrome Iconice mask. */ +icon[fire], +icon[frost], +icon[earth], +icon[nature], +icon[lightning] { + -webkit-mask: none; + mask: none; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + --element-icon-shadow: drop-shadow( + 1px 1px 0 oklch(from var(--element-color, var(--hue-purple)) calc(l * 0.6) c h / 0.5) + ); + filter: var(--element-icon-shadow); +} + +icon[fire] { + background-image: url('/static/icons/elements/fire.svg'); +} +icon[frost] { + background-image: url('/static/icons/elements/frost.svg'); +} +icon[earth] { + background-image: url('/static/icons/elements/earth.svg'); +} +icon[nature] { + background-image: url('/static/icons/elements/nature.svg'); +} +icon[lightning] { + background-image: url('/static/icons/elements/lightning.svg'); +} + +icon[tolerance] { + --icon: var(--icon-allTolerances); +} + +/* "All elements": the source shape carries no fills, so paint it with the full + rainbow spread through the mask — the multi-element counterpart to the colour + icons above. */ +icon[all], +icon.all { + --icon: var(--icon-all-elements); + background: var(--element-rainbow); + filter: drop-shadow( + 1px 1px 0 oklch(from var(--element-color, var(--hue-purple)) calc(l * 0.6) c h / 0.7) + ); +} + +eq-link[all] eq-link-hex { + background: var(--element-rainbow); +} + +icon[lock-closed] { + --icon: var(--icon-lock-closed); +} + +icon[potion], +icon.potion { + aspect-ratio: 377.55 / 460; + mask-size: contain; + mask-position: center; + background: radial-gradient( + circle at 40% 65%, + oklch(from var(--red) l c h) 20%, + oklch(from black l c h) 70% + ); +} + +button:disabled icon[potion] { + background: var(--muted-foreground); +} + +ability-tile[fire], +ability-tile[frost], +ability-tile[earth], +ability-tile[nature], +ability-tile[lightning], +ability-tile[all], +ability-segment[fire], +ability-segment[frost], +ability-segment[earth], +ability-segment[nature], +ability-segment[lightning], +ability-segment[all], +design-render[fire], +design-render[frost], +design-render[earth], +design-render[nature], +design-render[lightning], +design-render[all] { + --c-top: oklch(from var(--element-color) 0.985 0.03 h); + --c-bot: oklch(from var(--element-color) 0.92 0.03 h); + --edge: oklch(from var(--element-color) 0.82 0.035 h); + --deep1: oklch(from var(--element-color) 0.9 0.03 h); + --deep2: oklch(from var(--element-color) 0.85 0.03 h); + --ink: oklch(from var(--element-color) 0.46 0.072 h); + --glyph-top: oklch(from var(--element-color) 0.75 0.06 h); + --glyph-bot: oklch(from var(--element-color) 0.53 0.072 h); + --glyph-edge: oklch(from var(--element-color) 0.4 0.072 h / 0.8); + --shade: oklch(from var(--element-color) 0.79 0.03 h / 0.5); + --face: linear-gradient(180deg, var(--c-top), var(--c-bot)); +} + +circle[fire], +circle[frost], +circle[earth], +circle[nature], +circle[lightning] { + width: calc(var(--unit) * 3); + background: oklch(from var(--element-color) l calc(c * 0.4) h); +} + +circle[all] { + width: calc(var(--unit) * 3); + background: var(--element-rainbow); +} + +[coin-copper], +.coin-copper { + color: var(--coin-copper); +} + +[coin-silver], +.coin-silver { + color: var(--coin-silver); +} + +[coin-gold], +.coin-gold { + color: var(--coin-gold); +} + +[coin-platinum], +.coin-platinum { + color: var(--coin-platinum); +} + +[dark] { + --background: oklch(0.15 0.01 60); + --foreground: oklch(0.9 0 0); + --card: oklch(0.31 0.025 65); + --c-panel: oklch(0.185 0.013 65); + --c-inset: oklch(0.13 0.011 60); + --c-fg: oklch(0.91 0.015 85); + --c-muted: oklch(0.63 0.02 75); + --c-line: oklch(0.8 0.05 85 / 0.13); + --c-accent: var(--gold-warm); + --border: oklch(0.3 0.02 60 / 15%); + --divider: oklch(from var(--foreground) l c h / 0.28); + --input: oklch(0.42 0.008 80); +} + +html { + font-family: var(--font-sans); + overflow-x: hidden; + overflow-y: scroll; + -webkit-tap-highlight-color: transparent; +} + +* { + -webkit-user-select: none; + user-select: none; +} + +input, +textarea { + -webkit-user-select: text; + user-select: text; +} + +card { + color: var(--muted-foreground); +} + +body { + background-color: var(--background); + background-size: cover; + background-position: center; + background-attachment: fixed; + background-image: url('/static/images/bg/parchment-2080x1170.webp'); +} + +body[the-wild]:not([dark]) { + background-image: url('/static/images/bg/the-wild-grassland-2250x1500.webp'); +} + +body[the-wild][dark] { + background-image: url('/static/images/bg/the-wild-grassland-dark-4096x2304.webp'); +} + +html:has(body[cutscene-open]), +body[cutscene-open] { + overflow: hidden; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-heading); + color: var(--foreground); + font-weight: 300; +} + +badge { + font-weight: normal; +} + +hr { + border-color: var(--divider); +} + +hr[vertical] { + align-self: stretch; + width: 1px; + height: auto; + margin-block: calc(var(--unit) * 1); + border: none; + background: linear-gradient(to bottom, transparent, var(--muted-foreground), transparent); +} + +icon[maxHealth], +icon.maxHealth { + --color: var(--floater-default); +} + +icon[maxArmor], +icon.maxArmor { + --color: oklch(from var(--hue-blue) calc(l * 0.85) c h); +} + +icon[damage], +icon.damage { + --color: oklch(from var(--hue-green) calc(l * 0.75) c h); +} + +icon[maxHealth], +icon[maxArmor], +icon[damage] { + background: radial-gradient( + circle at 35% 28%, + oklch(from var(--color) calc(l + 0.18) c h), + var(--color) 55%, + oklch(from var(--color) calc(l - 0.13) c h) + ); + filter: drop-shadow(1px 0 0 var(--icon-edge)) drop-shadow(-1px 0 0 var(--icon-edge)) + drop-shadow(0 1px 0 var(--icon-edge)) drop-shadow(0 -1px 0 var(--icon-edge)); + --icon-edge: oklch(from var(--color) calc(l - 0.4) c h / 0.85); +} + +icon[bleeding] { + --color: var(--status-bleeding); +} + +icon[wounded] { + --color: var(--status-wounded); +} + +icon[venom] { + --color: var(--status-poisoned); +} + +icon[stunned] { + --color: var(--status-stunned); +} + +icon[concussed] { + --color: var(--status-concussed); +} + +icon[vulnerable] { + --color: var(--status-vulnerable); +} + +icon[exposed] { + --color: var(--status-exposed); +} + +icon[cocooned] { + --icon: var(--icon-spin); + --color: var(--status-cocooned); + width: 1em; + height: 1em; +} + +icon[webbed] { + --icon: var(--icon-smokeBomb); + --color: var(--status-webbed); + width: 1em; + height: 1em; +} + +icon[arrow-up] { + --icon: var(--icon-arrow-up); +} + +icon[arrow-down] { + --icon: var(--icon-arrow-down); +} + +icon[experience] { + --icon: var(--icon-experience); + --color: var(--hue-yellow); +} + +icon[buff] { + --color: var(--status-buff); +} + +icon[debuff] { + --color: var(--status-debuff); +} + +[cinzel] { + font-family: var(--font-heading); +} + +[alfa-slab] { + font-family: var(--font-display); +} + +[bree-serif] { + font-family: var(--font-accent); +} + +[hexagon] { + corner-shape: bevel; + border-radius: var(--hexagon-point, calc(var(--unit) * 6)) / 50%; +} + +[sticky-bar]:not([glass]) { + background: linear-gradient( + to bottom, + oklch(from var(--background) calc(l * 0.96) c h), + oklch(from var(--background) calc(l * 0.9) c h) + ); +} +[sticky-bar][topbar-stay] { + background: var(--bar-bg); + + box-shadow: + 0 1px 0 oklch(from var(--c-accent) l c h / 0.3), + 0 calc(var(--unit) * 0.5) calc(var(--unit) * 1.5) calc(var(--unit) * -0.5) var(--scrim-2); +} + +[sticky-bar][tab-bar] { + background: var(--bar-bg); + box-shadow: + inset 0 2px 0 oklch(from var(--c-accent) l c h / 0.4), + inset 0 -1px 0 var(--c-line); +} + +page-content:has([sticky-foot]) { + padding-bottom: 0; +} + +[sticky-foot] { + margin-top: auto; + margin-inline: calc(var(--unit) * -6); + padding: calc(var(--unit) * 3) calc(var(--unit) * 6); + background: var(--bar-bg); +} + +@media (width <= 768px) { + [sticky-foot] { + margin-inline: calc(var(--unit) * -3); + padding-inline: calc(var(--unit) * 3); + } +} + +[glass] { + background: var(--sheen-3); + box-shadow: 0 4px 6px -1px var(--scrim-1); + backdrop-filter: blur(4px); +} + +[dark] [glass] { + background-color: oklch(from var(--card) calc(l * 0.75) c h / 0.6); + box-shadow: 0 4px 6px -1px var(--scrim-2); +} + +[fat-number] { + filter: drop-shadow(0 1.2px 1.2px var(--scrim-3)); + -webkit-text-stroke: 0.5px black; +} + +eq-link { + --eq-h: calc(var(--unit) * 6.5); + --eq-r: calc(var(--eq-h) * 0.2887); + --eq-color: var(--rarity-common); + --c: var(--element-color, var(--eq-color)); + display: inline-flex; + align-items: stretch; + height: var(--eq-h); + min-width: 0; + overflow: hidden; + corner-shape: bevel; + border-radius: var(--eq-r) / 50%; + line-height: 1; + font-weight: 600; + font-size: calc(var(--unit) * 3.5); + cursor: default; + color: oklch(from var(--c) calc(l * 0.82) c h); + background: oklch(from var(--c) l c h / 0.14); + box-shadow: inset 0 0 0 1px oklch(from var(--c) l c h / 0.45); +} + +eq-link[all] { + background: var(--element-spectrum); +} + +[dark] eq-link { + color: oklch(from var(--c) calc(l + 0.2) c h); +} + +eq-link eq-link-hex { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + aspect-ratio: 2 / 1.7320508; + corner-shape: bevel; + border-radius: var(--eq-r) / 50%; + color: var(--white); + background: oklch(from var(--c) calc(l + 0.07) calc(c * 0.85) h); +} + +eq-link eq-link-hex icon { + font-size: calc(var(--unit) * 4.5); +} + +element-hex { + --hex-h: calc(var(--unit) * 9); + display: flex; + align-items: center; + justify-content: center; + flex: none; + height: var(--hex-h); + aspect-ratio: 2 / 1.7320508; + corner-shape: bevel; + border-radius: calc(var(--hex-h) * 0.2887) / 50%; + color: var(--white); + background: oklch(from var(--element-color, var(--hue-purple)) calc(l + 0.07) calc(c * 0.85) h); +} + +element-hex[all] { + background: var(--element-rainbow); +} + +element-hex icon { + font-size: calc(var(--hex-h) * 0.6); +} + +eq-link eq-name { + display: block; + min-width: 0; + line-height: var(--eq-h); + padding: 0 calc(var(--unit) * 4); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +eq-link:has(eq-link-hex) eq-name { + padding-left: calc(var(--unit) * 2.5); +} + +team-badge { + display: inline-block; + padding: calc(var(--unit) * 1) calc(var(--unit) * 2.5); + background: var(--team-color, var(--scrim-3)); + border-radius: calc(var(--unit) * 1.5); + color: var(--white); + font-family: var(--font-heading); + font-weight: 600; + font-size: calc(var(--unit) * 4.5); + letter-spacing: 0.02em; + line-height: 1.15; + text-align: center; + white-space: pre-line; + box-shadow: + inset 0 1px 0 oklch(from var(--team-color, var(--white)) calc(l + 0.18) c h), + 0 calc(var(--unit) * 0.5) calc(var(--unit) * 1) var(--scrim-2); +} + +team-badge[sm] { + padding: calc(var(--unit) * 0.5) calc(var(--unit) * 1.5); + border-radius: calc(var(--unit) * 1); + font-size: calc(var(--unit) * 2.75); +} + +[text-sm] { + font-size: calc(var(--unit) * 3.5); +} + +[text-xs] { + font-size: calc(var(--unit) * 3); +} + +[text-lg] { + font-size: calc(var(--unit) * 4.5); +} + +[text-muted] { + color: var(--muted-foreground); +} + +[text-center] { + text-align: center; +} + +[text-right] { + text-align: right; +} + +[capitalize] { + text-transform: capitalize; +} + +[font-bold] { + font-weight: 700; +} + +[font-medium] { + font-weight: 500; +} + +[flex-none] { + flex: none; +} + +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background-color: oklch(from var(--background) l c h / 50%); + border-radius: calc(var(--radius) - (calc(var(--unit) * 1) - 12px)); +} + +::-webkit-scrollbar-thumb { + background-color: var(--slate); + border-radius: calc(var(--radius) - (calc(var(--unit) * 1) - 12px)); +} + +::-webkit-scrollbar-thumb:hover { + background-color: var(--muted-foreground); +} + +page { + display: flex; + flex-direction: column; + flex: 1; +} + +page[pve] game-table { + display: flex; + flex-direction: column; + align-items: flex-start; + width: auto; + margin-top: calc(var(--unit) * 4); + margin-inline: calc(var(--unit) * -6); + margin-bottom: calc(var(--unit) * -6); +} + +page[pve] [game-table-header], +page[pve] [game-table-row] { + display: flex; + align-items: center; + width: 100%; + gap: calc(var(--unit) * 4); + padding: calc(var(--unit) * 3) calc(var(--unit) * 6); +} + +page[pve] [game-table-header] { + font-size: calc(var(--unit) * 3); + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--c-muted); + border-bottom: 1px solid var(--c-line); +} + +page[pve] [game-table-row] { + font-size: calc(var(--unit) * 4); + text-decoration: none; + color: var(--c-fg); + border-bottom: 1px solid var(--c-line); + transition: background 200ms ease; +} + +page[pve] [game-table-row]:last-child { + border-bottom: 0; +} + +page[pve] [game-table-row][even] { + background: oklch(from var(--c-fg) l c h / 0.05); +} + +@media (width <= 768px) { + page[pve] game-table { + margin-bottom: calc(var(--unit) * -3); + } +} + +page-content { + display: flex; + flex-direction: column; + flex: 1; + padding: calc(var(--unit) * 6); + gap: calc(var(--unit) * 4); +} + +@media (width <= 768px) { + page-content { + padding: calc(var(--unit) * 3); + gap: calc(var(--unit) * 3); + } +} + +@layer modifiers { + kingstone { + display: block; + } +} + +icon-cell { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: calc(var(--unit) * 7); + height: calc(var(--unit) * 7); + flex: none; + border-radius: calc(var(--unit) * 0.75); + background: oklch(from var(--foreground) l c h / 0.05); +} + +ability-tile-ticks { + top: 100%; + left: 50%; + transform: translate(-50%, -75%); + width: calc(var(--unit) * 3.5); + height: calc(var(--unit) * 3.5); + background: linear-gradient(180deg, oklch(0.99 0.006 85), oklch(0.925 0.006 85)); + border: 1px solid var(--edge, oklch(0.825 0.011 85)); + border-radius: calc(var(--unit) * 1); + color: oklch(0.465 0.0144 85); + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: calc(var(--unit) * 2.5); + line-height: 0; +} + +icon-cell ability-tile-ticks { + width: auto; + min-width: calc(var(--unit) * 3); + height: calc(var(--unit) * 3); + margin-top: calc(var(--unit) * 0.5); + font-size: calc(var(--unit) * 2.75); +} + +progress-bar { + display: block; + height: calc(var(--unit) * 2); + background: var(--border); + border-radius: calc(var(--unit) * 1); + overflow: hidden; +} + +progress-bar > div { + height: 100%; + background: var(--primary); + transition: width 200ms ease; +} + +[combat-ring] { + position: relative; + width: calc(var(--unit) * 125); + height: calc(var(--unit) * 125); + margin: 0 auto; +} + +[dnd-item]:not([dnd-item='false']) { + cursor: grab; + user-select: none; + touch-action: none; +} + +[dnd-item]:not([dnd-item='false']):active { + cursor: grabbing; +} + +[dnd-ghost] { + cursor: grabbing; +} + +[dnd-placeholder] { + pointer-events: none; +} + +coin { + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + /* background: var(--white); + border: 1px solid var(--coin-platinum); */ + /* box-shadow: 1px 1px 0 oklch(from var(--black) l c h / 0.5); */ +} + +coin stack icon[coin-platinum] { + background: radial-gradient( + circle at 35% 28%, + oklch(from var(--coin-platinum) calc(l + 0.18) c h), + var(--coin-platinum) 55%, + oklch(from var(--coin-platinum) calc(l - 0.13) c h) + ); + filter: drop-shadow(1px 0 0 var(--coin-outline)) drop-shadow(-1px 0 0 var(--coin-outline)) + drop-shadow(0 1px 0 var(--coin-outline)) drop-shadow(0 -1px 0 var(--coin-outline)); + --coin-outline: oklch(from var(--coin-platinum) calc(l - 0.4) c h / 0.85); +} + +coin stack icon[back] { + background: oklch(from var(--coin-platinum) calc(l - 0.62) c h / 0.55); + transform: scale(1.2, 1.1); +} + +icon-cell coin stack { + transform: scaleY(0.88); +} + +[golden-btn] { + all: unset; + cursor: pointer; + position: relative; + font-family: var(--font-sans); + font-weight: 700; + font-size: calc(var(--unit) * 4); + text-transform: uppercase; + letter-spacing: 0.2em; + text-indent: 0.2em; + padding: calc(var(--unit) * 2) calc(var(--unit) * 6); + color: oklch(from var(--gold-deep) 0.34 calc(c * 0.85) h); + text-shadow: 0 1px 0 oklch(from var(--gold-shine) l c h / 0.55); + clip-path: polygon( + calc(var(--unit) * 2) 0, + calc(100% - var(--unit) * 2) 0, + 100% calc(var(--unit) * 2), + 100% calc(100% - var(--unit) * 2), + calc(100% - var(--unit) * 2) 100%, + calc(var(--unit) * 2) 100%, + 0 calc(100% - var(--unit) * 2), + 0 calc(var(--unit) * 2) + ); + background: + radial-gradient( + ellipse farthest-corner at right bottom, + var(--gold-shine) 0%, + var(--gold-warm) 15%, + var(--gold-deep) 45%, + var(--gold-shadow) 65%, + transparent 90% + ), + radial-gradient( + ellipse farthest-corner at left top, + var(--white) 0%, + var(--gold-shine) 12%, + var(--gold-warm) 35%, + var(--gold-shadow) 75%, + var(--gold-shadow) 100% + ); + box-shadow: + inset 0 1px 0 oklch(from var(--gold-shine) l c h / 0.9), + inset 0 -2px 3px oklch(from var(--gold-shadow) l c h / 0.7); + filter: drop-shadow(0 2px 4px var(--scrim-3)); +} + +[golden-btn]:disabled { + cursor: not-allowed; + filter: grayscale(0.9) brightness(0.85); + text-shadow: none; +} + +/* ---- Stylecheat form-element overrides ---- */ +input:not([type='checkbox'], [type='radio'], [type='range']):not(:disabled)::placeholder, +textarea:not(:disabled)::placeholder { + color: oklch(0.6 0 0); +} + +select:not(:disabled) { + color: var(--popover-foreground); +} + +input:not([type='checkbox'], [type='radio'], [type='range']):disabled, +textarea:disabled, +select:disabled { + background-color: var(--input); + color: var(--foreground); + -webkit-text-fill-color: var(--foreground); + box-shadow: inset 0 0 0 1px var(--border); + opacity: 0.45; +} + +button[primary]:disabled { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + box-shadow: inset 0 0 0 1px oklch(from var(--primary) l c h / 0.2); + opacity: 0.45; +} + +button[danger] { + background-color: oklch(from var(--destructive) l c h / 0.12); + color: oklch(from var(--destructive) calc(l - 0.2 * var(--theme-sign)) c h); + box-shadow: inset 0 0 0 1px oklch(from var(--destructive) l c h / 0.2); +} + +button[danger]:not(:disabled):hover { + background-color: oklch(from var(--destructive) l c h / 0.2); + box-shadow: inset 0 0 0 1px oklch(from var(--destructive) l c h / 0.3); +} + +button[success] { + background-color: oklch(from var(--hue-green) l c h / 0.12); + color: oklch(from var(--hue-green) calc(l - 0.2 * var(--theme-sign)) c h); + box-shadow: inset 0 0 0 1px oklch(from var(--hue-green) l c h / 0.2); +} + +button[success]:not(:disabled):hover { + background-color: oklch(from var(--hue-green) l c h / 0.2); + box-shadow: inset 0 0 0 1px oklch(from var(--hue-green) l c h / 0.3); +} + +button[secondary]:disabled { + background-color: var(--secondary); + color: var(--secondary-foreground); + box-shadow: inset 0 0 0 1px var(--border); + opacity: 0.45; +} + +button[tertiary]:disabled { + background-color: transparent; + box-shadow: none; + color: var(--secondary-foreground); + opacity: 0.45; +} + +tabs { + --tab-surface: var(--card); + padding-inline: calc(var(--unit) * 6); +} + +tabs > tab { + font-family: var(--font-heading); +} + +tab-count { + margin-inline: 0; + opacity: 0.55; + font-variant-numeric: tabular-nums; +} + +teamplay-list tabs { + margin-inline: calc(var(--unit) * -6); +} + +page[armory] [vendor-filters] { + padding-top: calc(var(--unit) * 2); +} + +@media (width <= 768px) { + teamplay-list tabs { + margin-inline: calc(var(--unit) * -3); + } + + page[armory] [vendor-filters] { + flex-wrap: wrap; + } +} + +input[type='checkbox']:disabled, +input[type='radio']:disabled { + background-color: var(--input); + box-shadow: inset 0 0 0 1px var(--border); + opacity: 0.45; +} + +label:has(input[type='checkbox']:disabled, input[type='radio']:disabled) { + color: var(--foreground); + opacity: 0.45; + cursor: not-allowed; +} + +label input[type='checkbox']:disabled, +label input[type='radio']:disabled { + opacity: 1; +} +/* ---- end Stylecheat form-element overrides ---- */ + +@media (max-width: 768px) { + [sm-hide] { + display: none; + } +} + +[tooltip-card] { + --tooltip-base: var(--card); + width: calc(var(--unit) * 76); + gap: calc(var(--unit) * 3); + padding: calc(var(--unit) * 5); + font-size: calc(var(--unit) * 3.75); + background: var(--tooltip-base); +} + +[tooltip-card]:has([equipment-name]) { + width: fit-content; + min-width: calc(var(--unit) * 76); +} + +[tooltip-card]:has([equipment-name]) [tooltip-desc] { + max-width: calc(var(--unit) * 66); +} + +[tooltip-card]:has([equipment-name]) crow [tooltip-desc] { + font-size: calc(var(--unit) * 3.5); +} + +[tooltip-card] > crow:has([equipment-name]):has(ability-tile) { + margin-top: calc(var(--unit) * -2); +} + +[equipment-abilities] { + align-items: flex-end; +} + +[tooltip-card]:has([equipment-name]):not(:has([equipment-abilities])) [tooltip-name] { + max-width: none; +} + +[tooltip-card][tinted], +[tooltip-card][ability-card] { + --tint: var(--card); + position: relative; + border-color: oklch(from var(--tint) l calc(c * 0.5) h / 0.5); + background: + linear-gradient( + 180deg, + oklch(from var(--tint) l c h / 0.14), + oklch(from var(--tint) l c h / 0.03) 60% + ), + var(--tooltip-base); +} + +[tooltip-card]:is([fire], [frost], [earth], [nature], [lightning]) { + --tint: var(--element-color); + --tooltip-base: var(--card); + box-shadow: inset 0 0 0 1px oklch(from var(--element-color) l c h / 0.7); +} + +[tooltip-card][all] { + --tooltip-base: var(--card); + box-shadow: inset 0 0 0 1px oklch(from var(--element-color) l c h / 0.6); + background: + linear-gradient(180deg, transparent, var(--tooltip-base) 70%), + linear-gradient( + 90deg, + oklch(from var(--element-fire) l c h / 0.16), + oklch(from var(--element-lightning) l c h / 0.16), + oklch(from var(--element-nature) l c h / 0.16), + oklch(from var(--element-frost) l c h / 0.16), + oklch(from var(--element-earth) l c h / 0.16) + ), + var(--tooltip-base); +} + +[tooltip-card]:is([fire], [frost], [earth], [nature], [lightning], [all]) [tooltip-name] { + color: oklch(from var(--element-color) calc(l - 0.2 * var(--theme-sign)) c h); +} + +[tooltip-card][multi] { + --element-color: var(--hue-purple); + --tooltip-base: var(--card); + box-shadow: inset 0 0 0 1px oklch(from var(--hue-purple) l c h / 0.6); + background: + linear-gradient(180deg, transparent, var(--tooltip-base) 70%), var(--spectrum-wash), + var(--tooltip-base); +} + +[tooltip-heading] status-chip[round] { + width: calc(var(--unit) * 7); + height: calc(var(--unit) * 7); + transform: none; +} + +[tooltip-heading] status-chip[round] [status-icon] icon { + font-size: calc(var(--unit) * 4.2); +} + +[tooltip-card]:has(tooltip-stats) [tooltip-name] { + min-height: calc(var(--unit) * 8); +} + +[tooltip-card] hr { + margin-top: calc(var(--unit) * 2); +} + +[tooltip-name] { + text-wrap: pretty; + font-size: calc(var(--unit) * 5); + font-weight: normal; + color: var(--foreground); + min-width: calc(var(--unit) * 25); + max-width: calc(var(--unit) * 40); +} + +[tooltip-desc] { + font-size: calc(var(--unit) * 3.25); + color: var(--muted-foreground); + text-wrap: pretty; + text-align: left; + font-style: italic; +} + +[tooltip-card]:has([equipment-name]) > p[tooltip-desc] { + font-style: italic; + text-align: center; + margin: 0 auto; +} + +[tooltip-card]:has([equipment-name]) > p[tooltip-desc]::before { + content: '“'; +} + +[tooltip-card]:has([equipment-name]) > p[tooltip-desc]::after { + content: '”'; +} + +[tooltip-card] strong:is([fire], [frost], [earth], [nature], [lightning]) { + color: oklch(from var(--element-color) calc(l - 0.2 * var(--theme-sign)) c h); +} + +[tooltip-card] strong[multi] { + color: oklch(from var(--hue-purple) calc(l - 0.2 * var(--theme-sign)) c h); +} + +[tooltip-title] { + color: var(--muted-foreground); +} + +[tooltip-stat] { + display: flex; + align-items: center; + gap: calc(var(--unit) * 2); + font-size: calc(var(--unit) * 3.75); + color: var(--muted-foreground); +} + +[tooltip-stat] strong { + flex: none; +} + +[tooltip-stat] > span:last-child { + flex: 0 1 auto; + min-width: 0; + text-align: right; +} + +[tooltip-stat] stat-leader { + flex: 1; + align-self: center; + height: 0; + border-bottom: 1px dotted var(--divider); + opacity: 0.6; + transform: translateY(calc(var(--unit) * 1.5)); +} + +[tooltip-card] ability-track[small] [ability-icon] > icon { + font-size: calc(var(--unit) * 4.8); +} + +[tooltip-tag] { + display: inline-block; + font-size: calc(var(--unit) * 2); + padding: calc(var(--unit) * 0.25) calc(var(--unit) * 1.5); + border-radius: calc(var(--unit) * 0.75); + margin-top: calc(var(--unit) * 1); + background: var(--accent); + color: var(--muted-foreground); +} + +[tooltip-tag][special] { + background: oklch(from var(--rarity-epic) calc(l + 0.3) calc(c * 0.4) h); + color: oklch(from var(--rarity-epic) calc(l * 0.7) c h); +} + +/* Achievement banner (Royal Double-Frame) — shared by /achievements, the center + reveal, and the deep-link flip. Earned by default; [locked] strips it to a drab + placeholder. */ +achievement-card { + /* Light (default) theme tokens; the [dark] block below swaps them so the banner + follows the global dark-mode toggle on both the page and the reveal. */ + --gold-grad: linear-gradient(180deg, var(--gold-warm), var(--gold-deep) 55%, var(--gold-shadow)); + --ac-bg: linear-gradient(180deg, oklch(0.97 0.02 85), oklch(0.9 0.035 80)); + --ac-inset: oklch(0.99 0.012 90); + --ac-drop: oklch(0 0 0 / 0.2); + --ac-icon-color: var(--gold-deep); + --ac-icon-bg: radial-gradient(circle at 30% 25%, oklch(0.99 0.012 90), oklch(0.9 0.035 80)); + --ac-eyebrow: oklch(from var(--gold-deep) calc(l - 0.05) c h); + --ac-ink: oklch(0.42 0.05 70); + --ac-track: oklch(0 0 0 / 0.15); + --ac-locked-bg: oklch(0.9 0.01 80); + --ac-locked-icon-bg: oklch(0.94 0.01 85); + --ac-locked-icon-ring: oklch(from var(--gold-deep) l c h / 0.3); + --ac-locked-ink: oklch(0.38 0.02 75); + --ac-locked-filter: brightness(0.98); + --ac-locked-opacity: 0.95; + position: relative; + display: flex; + align-items: center; + gap: calc(var(--unit) * 5); + width: 100%; + max-width: calc(var(--unit) * 150); + padding: calc(var(--unit) * 5) calc(var(--unit) * 8); + overflow: hidden; + background: var(--ac-bg); + border: calc(var(--unit) * 1) solid transparent; + border-image: var(--gold-grad) 1; + box-shadow: + inset 0 0 0 1px var(--ac-inset), + inset 0 0 0 calc(var(--unit) * 1.5) oklch(from var(--gold-deep) l c h / 0.5), + 0 0 calc(var(--unit) * 16) oklch(from var(--gold-warm) l c h / 0.3), + 0 calc(var(--unit) * 4) calc(var(--unit) * 10) var(--ac-drop); +} + +[dark] achievement-card { + --gold-grad: linear-gradient( + 180deg, + var(--gold-shine), + var(--gold-warm) 45%, + var(--gold-deep) 55%, + var(--gold-shadow) + ); + --ac-bg: linear-gradient(180deg, oklch(0.3 0.03 70), oklch(0.18 0.02 65)); + --ac-inset: oklch(0.1 0.02 60); + --ac-drop: oklch(0 0 0 / 0.6); + --ac-icon-color: var(--gold-shine); + --ac-icon-bg: radial-gradient(circle at 30% 25%, oklch(0.4 0.05 70), oklch(0.16 0.02 60)); + --ac-eyebrow: oklch(from var(--gold-warm) calc(l + 0.05) c h); + --ac-ink: oklch(0.82 0.02 70); + --ac-track: oklch(0 0 0 / 0.45); + --ac-locked-bg: oklch(0.2 0.01 65); + --ac-locked-icon-bg: oklch(0.16 0.01 60); + --ac-locked-icon-ring: oklch(0 0 0 / 0.5); + --ac-locked-ink: oklch(0.84 0.015 75); + --ac-locked-filter: brightness(0.92); + --ac-locked-opacity: 0.9; +} + +achievement-card icon { + display: block; +} + +achievement-card icon[lock] { + display: none; +} + +achievement-card[locked] icon:not([lock]) { + display: none; +} + +achievement-card[locked] icon[lock] { + display: block; +} + +ac-corner { + position: absolute; + width: calc(var(--unit) * 3.5); + height: calc(var(--unit) * 3.5); + border: calc(var(--unit) * 0.75) solid var(--gold-warm); +} + +ac-corner[tl] { + top: calc(var(--unit) * 3.5); + left: calc(var(--unit) * 3.5); + border-right: 0; + border-bottom: 0; +} + +ac-corner[tr] { + top: calc(var(--unit) * 3.5); + right: calc(var(--unit) * 3.5); + border-left: 0; + border-bottom: 0; +} + +ac-corner[bl] { + bottom: calc(var(--unit) * 3.5); + left: calc(var(--unit) * 3.5); + border-right: 0; + border-top: 0; +} + +ac-corner[br] { + bottom: calc(var(--unit) * 3.5); + right: calc(var(--unit) * 3.5); + border-left: 0; + border-top: 0; +} + +ac-icon { + flex: none; + width: calc(var(--unit) * 17); + height: calc(var(--unit) * 17); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + font-size: calc(var(--unit) * 9); + color: var(--ac-icon-color); + background: var(--ac-icon-bg); + box-shadow: + inset 0 0 0 calc(var(--unit) * 0.75) var(--gold-deep), + 0 0 0 calc(var(--unit) * 0.5) var(--ac-inset), + 0 0 calc(var(--unit) * 6) oklch(from var(--gold-warm) l c h / 0.4); +} + +ac-body { + flex: 1; + display: flex; + flex-direction: column; + gap: calc(var(--unit) * 0.5); +} + +ac-eyebrow { + font-family: var(--font-sans); + font-size: calc(var(--unit) * 2.75); + font-weight: 600; + letter-spacing: 0.22em; + text-transform: uppercase; + color: var(--ac-eyebrow); +} + +ac-title { + display: block; + font-family: var(--font-heading); + font-weight: 700; + line-height: 1.05; + font-size: calc(var(--unit) * 8); + background: var(--gold-grad); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +ac-desc { + font-family: var(--font-sans); + font-size: calc(var(--unit) * 3.5); + color: var(--ac-ink); +} + +ac-progress { + margin-top: calc(var(--unit) * 1.5); + height: calc(var(--unit) * 1.5); + border-radius: calc(var(--unit) * 1); + background: var(--ac-track); + overflow: hidden; +} + +ac-progress-fill { + display: block; + height: 100%; + width: calc(attr(p type()) * 100%); + border-radius: inherit; + background: var(--gold-grad); +} + +achievement-card:not([locked]) ac-progress { + display: none; +} + +achievement-card[locked] { + filter: grayscale(1) var(--ac-locked-filter); + opacity: var(--ac-locked-opacity); + border-image: none; + border-color: oklch(from var(--gold-deep) l c h / 0.35); + background: var(--ac-locked-bg); + box-shadow: + inset 0 0 0 1px var(--ac-inset), + inset 0 0 0 calc(var(--unit) * 1.5) oklch(from var(--gold-deep) l c h / 0.45); +} + +achievement-card[locked] ac-corner { + display: none; +} + +achievement-card[locked] ac-icon { + border-radius: calc(var(--unit) * 1); + background: var(--ac-locked-icon-bg); + box-shadow: inset 0 0 0 1px var(--ac-locked-icon-ring); + color: var(--ac-locked-ink); +} + +achievement-card[locked] ac-title { + background: none; + -webkit-background-clip: border-box; + background-clip: border-box; + -webkit-text-fill-color: currentColor; + color: var(--ac-locked-ink); +} + +/* Deep-link reveal: shake the locked face, then flip to the earned face. */ +ac-flip { + display: block; + perspective: calc(var(--unit) * 300); +} + +ac-flip-inner { + position: relative; + transform-style: preserve-3d; + animation: + acShake 0.8s ease both, + acFlip 0.5s ease 0.8s forwards; +} + +ac-flip-face { + display: block; + backface-visibility: hidden; +} + +ac-flip-face[back] { + position: absolute; + inset: 0; + transform: rotateY(180deg); +} + +@keyframes acShake { + 10%, + 30%, + 50%, + 70%, + 90% { + transform: translateX(calc(var(--unit) * -1)) rotate(-0.6deg); + } + 20%, + 40%, + 60%, + 80% { + transform: translateX(calc(var(--unit) * 1)) rotate(0.6deg); + } +} + +@keyframes acFlip { + to { + transform: rotateY(180deg); + } +} diff --git a/css/stylecheat.css b/css/stylecheat.css new file mode 100644 index 00000000..f35882b5 --- /dev/null +++ b/css/stylecheat.css @@ -0,0 +1,4101 @@ +@layer context, elements, modifiers; + +@layer context { + /* ---- Iconice.css ---- */ + :root { + --icon-bell: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M16.023%2012.5c0-4.5-4-3.5-4-7%200-0.29-0.028-0.538-0.079-0.749-0.263-1.766-1.44-3.183-2.965-3.615%200.014-0.062%200.021-0.125%200.021-0.191%200-0.52-0.45-0.945-1-0.945s-1%200.425-1%200.945c0%200.065%200.007%200.129%200.021%200.191-1.71%200.484-2.983%202.208-3.020%204.273-0.001%200.030-0.001%200.060-0.001%200.091%200%203.5-4%202.5-4%207%200%201.191%202.665%202.187%206.234%202.439%200.336%200.631%201.001%201.061%201.766%201.061s1.43-0.43%201.766-1.061c3.568-0.251%206.234-1.248%206.234-2.439%200-0.004-0-0.007-0-0.011l0.024%200.011zM12.91%2013.345c-0.847%200.226-1.846%200.389-2.918%200.479-0.089-1.022-0.947-1.824-1.992-1.824s-1.903%200.802-1.992%201.824c-1.072-0.090-2.071-0.253-2.918-0.479-1.166-0.311-1.724-0.659-1.928-0.845%200.204-0.186%200.762-0.534%201.928-0.845%201.356-0.362%203.1-0.561%204.91-0.561s3.554%200.199%204.91%200.561c1.166%200.311%201.724%200.659%201.928%200.845-0.204%200.186-0.762%200.534-1.928%200.845z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-book: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14%202v13h-10.5c-0.829%200-1.5-0.672-1.5-1.5s0.671-1.5%201.5-1.5h9.5v-12h-10c-1.1%200-2%200.9-2%202v12c0%201.1%200.9%202%202%202h12v-14h-1z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M3.501%2013v0c-0%200-0.001%200-0.001%200-0.276%200-0.5%200.224-0.5%200.5s0.224%200.5%200.5%200.5c0%200%200.001-0%200.001-0v0h9.498v-1h-9.498z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-bullhorn: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M16%206.707c0-3.139-0.919-5.687-2.054-5.707%200.005-0%200.009-0%200.014-0h-1.296c0%200-3.044%202.287-7.425%203.184-0.134%200.708-0.219%201.551-0.219%202.523s0.085%201.816%200.219%202.523c4.382%200.897%207.425%203.184%207.425%203.184h1.296c-0.005%200-0.009-0-0.014-0.001%201.136-0.020%202.054-2.567%202.054-5.707zM13.513%2011.551c-0.147%200-0.305-0.152-0.387-0.243-0.197-0.22-0.387-0.562-0.55-0.989-0.363-0.957-0.564-2.239-0.564-3.611s0.2-2.655%200.564-3.611c0.162-0.428%200.353-0.77%200.55-0.99%200.081-0.091%200.24-0.243%200.387-0.243s0.305%200.152%200.387%200.243c0.197%200.22%200.387%200.562%200.55%200.99%200.363%200.957%200.564%202.239%200.564%203.611s-0.2%202.655-0.564%203.611c-0.162%200.428-0.353%200.77-0.55%200.989-0.081%200.091-0.24%200.243-0.387%200.243zM3.935%206.707c0-0.812%200.060-1.6%200.173-2.33-0.74%200.102-1.39%200.161-2.193%200.161-1.048%200-1.048%200-1.048%200l-0.867%201.479v1.378l0.867%201.479c0%200%200%200%201.048%200%200.803%200%201.453%200.059%202.193%200.161-0.113-0.729-0.173-1.518-0.173-2.33zM5.752%2010.034l-2-0.383%201.279%205.024c0.066%200.26%200.324%200.391%200.573%200.291l1.852-0.741c0.249-0.1%200.349-0.374%200.222-0.611l-1.926-3.581zM13.513%208.574c-0.057%200-0.118-0.059-0.149-0.094-0.076-0.085-0.149-0.217-0.212-0.381-0.14-0.369-0.217-0.863-0.217-1.392s0.077-1.023%200.217-1.392c0.063-0.165%200.136-0.297%200.212-0.381%200.031-0.035%200.092-0.094%200.149-0.094s0.118%200.059%200.149%200.094c0.076%200.085%200.149%200.217%200.212%200.381%200.14%200.369%200.217%200.863%200.217%201.392s-0.077%201.023-0.217%201.392c-0.063%200.165-0.136%200.297-0.212%200.381-0.031%200.035-0.092%200.094-0.149%200.094z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-checkmark: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M432%2064l-240%20240-112-112-80%2080%20192%20192%20320-320z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-chevron-left: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.4%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%206)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M10.25%2C1.75l1.5%2C1.5-4.5%2C4.5%2C4.5%2C4.5-1.5%2C1.5-6-6L10.25%2C1.75Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-chevron-down: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M2%205.5l1.5-1.5%204.5%204.5%204.5-4.5%201.5%201.5-6%206-6-6z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-chevron-right: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.4%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%206)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M5.75%2C13.75l-1.5-1.5%2C4.5-4.5L4.25%2C3.25l1.5-1.5%2C6%2C6-6%2C6Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-clock: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M10.293%2011.707l-3.293-3.293v-4.414h2v3.586l2.707%202.707zM8%200c-4.418%200-8%203.582-8%208s3.582%208%208%208%208-3.582%208-8-3.582-8-8-8zM8%2014c-3.314%200-6-2.686-6-6s2.686-6%206-6c3.314%200%206%202.686%206%206s-2.686%206-6%206z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-chevron-up: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%20%20%3C!--%20Generator%3A%20Adobe%20Illustrator%2029.8.4%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%202.1.1%20Build%206)%20%20--%3E%0A%20%20%3Cpath%20d%3D%22M14%2C10l-1.5%2C1.5-4.5-4.5-4.5%2C4.5-1.5-1.5%2C6-6%2C6%2C6Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-cog: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14.59%209.535c-0.839-1.454-0.335-3.317%201.127-4.164l-1.572-2.723c-0.449%200.263-0.972%200.414-1.529%200.414-1.68%200-3.042-1.371-3.042-3.062h-3.145c0.004%200.522-0.126%201.051-0.406%201.535-0.839%201.454-2.706%201.948-4.17%201.106l-1.572%202.723c0.453%200.257%200.845%200.634%201.123%201.117%200.838%201.452%200.336%203.311-1.12%204.16l1.572%202.723c0.448-0.261%200.967-0.41%201.522-0.41%201.675%200%203.033%201.362%203.042%203.046h3.145c-0.001-0.517%200.129-1.040%200.406-1.519%200.838-1.452%202.7-1.947%204.163-1.11l1.572-2.723c-0.45-0.257-0.839-0.633-1.116-1.113zM8%2011.24c-1.789%200-3.24-1.45-3.24-3.24s1.45-3.24%203.24-3.24c1.789%200%203.24%201.45%203.24%203.24s-1.45%203.24-3.24%203.24z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-credit-card: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14.5%202h-13c-0.825%200-1.5%200.675-1.5%201.5v9c0%200.825%200.675%201.5%201.5%201.5h13c0.825%200%201.5-0.675%201.5-1.5v-9c0-0.825-0.675-1.5-1.5-1.5zM1.5%203h13c0.271%200%200.5%200.229%200.5%200.5v1.5h-14v-1.5c0-0.271%200.229-0.5%200.5-0.5zM14.5%2013h-13c-0.271%200-0.5-0.229-0.5-0.5v-4.5h14v4.5c0%200.271-0.229%200.5-0.5%200.5zM2%2010h1v2h-1zM4%2010h1v2h-1zM6%2010h1v2h-1z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-cross: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M507.331%20411.33c-0.002-0.002-0.004-0.004-0.006-0.005l-155.322-155.325%20155.322-155.325c0.002-0.002%200.004-0.003%200.006-0.005%201.672-1.673%202.881-3.627%203.656-5.708%202.123-5.688%200.912-12.341-3.662-16.915l-73.373-73.373c-4.574-4.573-11.225-5.783-16.914-3.66-2.080%200.775-4.035%201.984-5.709%203.655%200%200.002-0.002%200.003-0.004%200.005l-155.324%20155.326-155.324-155.325c-0.002-0.002-0.003-0.003-0.005-0.005-1.673-1.671-3.627-2.88-5.707-3.655-5.69-2.124-12.341-0.913-16.915%203.66l-73.374%2073.374c-4.574%204.574-5.784%2011.226-3.661%2016.914%200.776%202.080%201.985%204.036%203.656%205.708%200.002%200.001%200.003%200.003%200.005%200.005l155.325%20155.324-155.325%20155.326c-0.001%200.002-0.003%200.003-0.004%200.005-1.671%201.673-2.88%203.627-3.657%205.707-2.124%205.688-0.913%2012.341%203.661%2016.915l73.374%2073.373c4.575%204.574%2011.226%205.784%2016.915%203.661%202.080-0.776%204.035-1.985%205.708-3.656%200.001-0.002%200.003-0.003%200.005-0.005l155.324-155.325%20155.324%20155.325c0.002%200.001%200.004%200.003%200.006%200.004%201.674%201.672%203.627%202.881%205.707%203.657%205.689%202.123%2012.342%200.913%2016.914-3.661l73.373-73.374c4.574-4.574%205.785-11.227%203.662-16.915-0.776-2.080-1.985-4.034-3.657-5.707z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E'); + --icon-crow: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20345.5%20341.9%22%3E%3Cpath%20d%3D%22M157.4%20249.7c-.3-.7-12-6-13-6l-46%2016.9c-13.8%2013.2-52.6%2068.1-71.8%2066.6-2.9-.2-4.3-2.8-7.1-2.9s-5.2%203.7-10.9%202.9c-13.3-1.9-10.8-4%205.4-22.4s35.9-34.2%2053.4-51.3c7.6-7.4%2015.1-14.9%2022-23l.4-1.4c-2.9-2.7-4.7%204-2.7-7.9s18.3-37.5%2025.3-48.5c15-23.8%2034.5-53.6%2055.2-72.4%206.2-5.6%2023.1-16%2026.8-21.1%2010.9-14.8%208.8-41.6%2022.1-58.7%2017.9-22.9%2056.4-27.6%2078.8-9%202.4%202%206.7%209.3%2010%2011s15.2%202.8%2020.5%204.5c3.4%201.1%2022.6%209.2%2019.4%2013.9l-36.7%2013.6c-4.7%208-11.4%2014.8-12.2%2025.2s2%204.9%209.2%2032.6-.3%2048.8-13.7%2072.6-32.6%2041.2-57.1%2053.1l-3.2%2013.3%2030.9%2032.9c5.8-1.5%2013-1.6%2018.2-2.7s6.8-5%2013.9-2.5c4.9%201.8%205.3%205.3%206.8%206.2s3.8.5%205.7%201.3c4.8%202%207.2%208.2%206.2%2013.2-1.6-.2-1.3-2.3-3-3.5-8.1-6.1-8.2%203.3-16.9%201.5%201.4%205.7%207%209.4%202.5%2016-.6%200-1.9-7.7-6.4-8.6-11.5%208.2-24.2-9-34.6-9.4-5.3-.2-12%204-19.9%203-5.2-.7-7.4-6.8-12.4-2.5-1.7%201.4-1.6%204.6-4%205.4-1.9-16.6%2015.3-14.2%2026.4-15%201.5-.1%202.9.8%202.5-1.5L220%20254.6c-4-1.5-6.8-3.2-9.5-6.5l-21.2%201.7c-3%202.5-12%2011.4-11.5%2015l27%2045.3c12%206.9%2031.1-4%2042.1%205.2%205%204.1%203.4%207.5%204.7%2012.2s4.9%207.6%201.8%2013.7c-3%20.6%201.3%202.6-2.9-4.5s-6.4-2.4-10.4-2.5c-2.1-.1-8-3.6-8.6-3l2%2010c-3.2%201.1-4.3-3.3-6.6-3.8s-5.5%201.4-10.2%200c-7.8-2.3-16.2-16-20.8-17.1s-11%203.2-18.6-1.3c-4-2.3-5.3-8.2-11.4-5.1-2%201.1-1.5%203.1-3.2%203.3-.5-9.3%206.1-12%2014.4-10.9%203.4.4%206.5%202.6%2010.1%202.9%201.5.1%203%20.6%202.5-1.5-7.3-12.7-14.6-25.7-22.9-37.9-2.8-4.3-8.1-7.9-8.9-13-.2-2.1.5-6.2-.2-7.3z%22%2F%3E%3C%2Fsvg%3E'); + --icon-css-3: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%202048%202048%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22evenodd%22%20d%3D%22M1582.48%2C1627.13l120.816-1353.38%2C1.585-17.752H343.116l1.582%2C17.752%2C120.689%2C1353.6%2C1.006%2C11.285%2C10.872%2C3.018%2C541.588%2C150.346h8.685l543.064-150.568%2C10.87-3.014%2C1.009-11.289v.002ZM1025.111%2C555.45h395.75l-11.913%2C138.491-390.414%2C173.558%2C6.576%2C31.226h366.391l-42.175%2C483.261-325.538%2C90.259-325.432-90.106-20.667-231.443h134l10.737%2C117.345%2C1.042%2C11.374%2C11.027%2C2.929%2C186.463%2C49.539%2C8.493-.064%2C184.316-51.231%2C10.978-3.053.964-11.315%2C18.428-216.732%2C1.504-17.688h-578.959l-12.198-139.091%2C377.014-161.362%2C26.761-11.469-6.386-31.354h-414.572l-11.81-133.074h399.62Z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-dark: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20448%20448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M355.656%20325.63c-9%201.5-18.25%202.25-27.5%202.25-92.75%200-168-75.25-168-168%200-31.75%209.25-62.75%2026-89.25-66.5%2019.75-114%2080.75-114%20153.25%200%2088.25%2071.75%20160%20160%20160%2048.25%200%2093.5-22%20123.5-58.25m50.75-21.249c-31.25%2067.75-99.75%20111.5-174.25%20111.5-105.75%200-192-86.25-192-192%200-103.75%2081.25-188%20184.75-191.75%207-.25%2012.75%203.75%2015.25%209.75%202.75%206.25%201%2013.5-3.75%2018-28.5%2026-44.25%2061.5-44.25%20100%200%2075%2061%20136%20136%20136q29.625%200%2057-12.75c6.25-2.75%2013.25-1.5%2018%203.25s6%2012%203.25%2018%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-desktop: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M0%201v10h16v-10h-16zM15%2010h-14v-8h14v8zM10.5%2012h-5l-0.5%202-1%201h8l-1-1z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-download: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M8%209l4-4h-3v-4h-2v4h-3zM11.636%207.364l-1.121%201.121%204.064%201.515-6.579%202.453-6.579-2.453%204.064-1.515-1.121-1.121-4.364%201.636v4l8%203%208-3v-4z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-earth: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M8%200c-4.418%200-8%203.582-8%208s3.582%208%208%208%208-3.582%208-8-3.582-8-8-8zM8%2015c-0.984%200-1.92-0.203-2.769-0.57l3.643-4.098c0.081-0.092%200.126-0.21%200.126-0.332v-1.5c0-0.276-0.224-0.5-0.5-0.5-1.765%200-3.628-1.835-3.646-1.854-0.094-0.094-0.221-0.146-0.354-0.146h-2c-0.276%200-0.5%200.224-0.5%200.5v3c0%200.189%200.107%200.363%200.276%200.447l1.724%200.862v2.936c-1.813-1.265-3-3.366-3-5.745%200-1.074%200.242-2.091%200.674-3h1.826c0.133%200%200.26-0.053%200.354-0.146l2-2c0.094-0.094%200.146-0.221%200.146-0.354v-1.21c0.634-0.189%201.305-0.29%202-0.29%201.1%200%202.141%200.254%203.067%200.706-0.065%200.055-0.128%200.112-0.188%200.172-0.567%200.567-0.879%201.32-0.879%202.121s0.312%201.555%200.879%202.121c0.569%200.569%201.332%200.879%202.119%200.879%200.049%200%200.099-0.001%200.149-0.004%200.216%200.809%200.605%202.917-0.131%205.818-0.007%200.027-0.011%200.055-0.013%200.082-1.271%201.298-3.042%202.104-5.002%202.104z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-embed: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M13%2011.5l1.5%201.5%205-5-5-5-1.5%201.5%203.5%203.5z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M7%204.5l-1.5-1.5-5%205%205%205%201.5-1.5-3.5-3.5z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M10.958%202.352l1.085%200.296-3%2011-1.085-0.296%203-11z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-eye: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201536%201536%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M575.841%20768c0%20105.951%2086.049%20192%20192%20192s192-86.049%20192-192v-1.599c-20.511%2020.799-48.639%2033.6-80.001%2033.6-61.791%200-111.999-50.241-111.999-111.999%200-44.481%2026.208-83.199%2063.681-101.121-19.839-7.041-41.28-10.881-63.681-10.881-105.921%200-192%2086.079-192%20192zM1492.959%20658.881c-119.040-151.362-408.96-402.882-724.8-402.882-316.161%200-606.369%20251.52-725.439%20402.879-26.88%2034.56-41.601%2072-42.561%20109.119%200.96%2037.119%2015.681%2074.559%2042.561%20109.119%20119.073%20151.395%20408.96%20402.885%20725.121%20402.885s606.048-251.487%20725.121-402.879c27.201-34.56%2041.919-72%2042.879-109.119-0.96-37.122-15.681-74.562-42.882-109.122zM767.841%201088.001c-176.64%200-320.001-143.361-320.001-320.001s143.361-320.001%20320.001-320.001%20320.001%20143.361%20320.001%20320.001c-0.003%20176.64-143.361%20320.001-320.001%20320.001z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-folder: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M13%2015l3-8h-13l-3%208zM2%206l-2%209v-13h4.5l2%202h6.5v2z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-heart-broken: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M11.8%201c2.318%200%204.2%201.882%204.2%204.2%200%204.566-4.935%205.982-8%2010.616-3.243-4.663-8-5.9-8-10.616%200-2.319%201.882-4.2%204.2-4.2%200.943%200%201.812%200.43%202.512%201.060l-1.213%201.94%203.5%202-2%205%205.5-6-3.5-2%200.967-1.451c0.553-0.34%201.175-0.549%201.833-0.549z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-heart: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M11.8%201c-1.682%200-3.129%201.368-3.799%202.797-0.671-1.429-2.118-2.797-3.8-2.797-2.318%200-4.2%201.882-4.2%204.2%200%204.716%204.758%205.953%208%2010.616%203.065-4.634%208-6.050%208-10.616%200-2.319-1.882-4.2-4.2-4.2z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-home: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M16%209.226l-8-6.21-8%206.21v-2.532l8-6.21%208%206.21zM14%209v6h-4v-4h-4v4h-4v-6l6-4.5z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-html-5: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M0.946%200l1.284%2014.4%205.762%201.6%205.777-1.602%201.286-14.398h-14.108zM12.668%2013.482l-4.644%201.287v0.007l-0.012-0.004-0.012%200.004v-0.007l-4.644-1.287-1.098-12.304h11.508l-1.098%2012.304zM10.168%208.284l-0.204%202.29-1.972%200.532-1.967-0.53-0.126-1.41h-1.773l0.247%202.774%203.626%201.003%203.615-1.003%200.485-5.422h-6.437l-0.161-1.809h6.758l0.158-1.766h-8.847l0.477%205.341z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M13%2014h-10v-2l3-5%204.109%205%202.891-2v4z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M13%207.5c0%200.828-0.672%201.5-1.5%201.5s-1.5-0.672-1.5-1.5%200.672-1.5%201.5-1.5c0.828%200%201.5%200.672%201.5%201.5z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14.341%203.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-7.75c-0.689%200-1.25%200.561-1.25%201.25v13.5c0%200.689%200.561%201.25%201.25%201.25h11.5c0.689%200%201.25-0.561%201.25-1.25v-9.75c0-0.224-0.068-0.615-0.659-1.421zM12.271%202.729c0.48%200.48%200.856%200.912%201.134%201.271h-2.406v-2.405c0.359%200.278%200.792%200.654%201.271%201.134zM14%2014.75c0%200.136-0.114%200.25-0.25%200.25h-11.5c-0.135%200-0.25-0.114-0.25-0.25v-13.5c0-0.135%200.115-0.25%200.25-0.25%200%200%207.749-0%207.75%200v3.5c0%200.276%200.224%200.5%200.5%200.5h3.5v9.75z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-layout: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20768%20768%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M160%2064c-26.496%200-50.56%2010.784-67.872%2028.128s-28.128%2041.376-28.128%2067.872v448c0%2026.496%2010.784%2050.56%2028.128%2067.872s41.376%2028.128%2067.872%2028.128h448c26.496%200%2050.56-10.784%2067.872-28.128s28.128-41.376%2028.128-67.872v-448c0-26.496-10.784-50.56-28.128-67.872s-41.376-28.128-67.872-28.128zM640%20256h-512v-96c0-8.832%203.552-16.8%209.376-22.624s13.792-9.376%2022.624-9.376h448c8.832%200%2016.8%203.552%2022.624%209.376s9.376%2013.792%209.376%2022.624zM256%20320v320h-96c-8.832%200-16.8-3.552-22.624-9.376s-9.376-13.792-9.376-22.624v-288zM320%20640v-320h320v288c0%208.832-3.552%2016.8-9.376%2022.624s-13.792%209.376-22.624%209.376z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-images: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2018%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M17%202h-1v-1c0-0.55-0.45-1-1-1h-14c-0.55%200-1%200.45-1%201v12c0%200.55%200.45%201%201%201h1v1c0%200.55%200.45%201%201%201h14c0.55%200%201-0.45%201-1v-12c0-0.55-0.45-1-1-1zM2%203v10h-0.998c-0.001-0.001-0.001-0.001-0.002-0.002v-11.996c0.001-0.001%200.001-0.001%200.002-0.002h13.996c0.001%200.001%200.001%200.001%200.002%200.002v0.998h-12c-0.55%200-1%200.45-1%201v0zM17%2014.998c-0.001%200.001-0.001%200.001-0.002%200.002h-13.996c-0.001-0.001-0.001-0.001-0.002-0.002v-11.996c0.001-0.001%200.001-0.001%200.002-0.002h13.996c0.001%200.001%200.001%200.001%200.002%200.002v11.996z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M15%205.5c0%200.828-0.672%201.5-1.5%201.5s-1.5-0.672-1.5-1.5%200.672-1.5%201.5-1.5%201.5%200.672%201.5%201.5z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M16%2014h-12v-2l3.5-6%204%205h1l3.5-3z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-light: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20768%20768%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M576%20384c0-53.024-21.536-101.056-56.224-135.776S437.024%20192%20384%20192s-101.056%2021.536-135.776%2056.224S192%20330.976%20192%20384s21.536%20101.056%2056.224%20135.776S330.976%20576%20384%20576s101.056-21.536%20135.776-56.224S576%20437.024%20576%20384m-64%200c0%2035.36-14.304%2067.296-37.504%2090.496S419.36%20512%20384%20512s-67.296-14.304-90.496-37.504S256%20419.36%20256%20384s14.304-67.296%2037.504-90.496S348.64%20256%20384%20256s67.296%2014.304%2090.496%2037.504S512%20348.64%20512%20384M352%2032v64c0%2017.664%2014.336%2032%2032%2032s32-14.336%2032-32V32c0-17.664-14.336-32-32-32s-32%2014.336-32%2032m0%20640v64c0%2017.664%2014.336%2032%2032%2032s32-14.336%2032-32v-64c0-17.664-14.336-32-32-32s-32%2014.336-32%2032M112.416%20157.664l45.44%2045.44c12.512%2012.512%2032.768%2012.512%2045.248%200s12.512-32.768%200-45.248l-45.44-45.44c-12.512-12.512-32.768-12.512-45.248%200s-12.512%2032.768%200%2045.248m452.48%20452.48%2045.44%2045.44c12.512%2012.512%2032.768%2012.512%2045.248%200s12.512-32.768%200-45.248l-45.44-45.44c-12.512-12.512-32.768-12.512-45.248%200s-12.512%2032.768%200%2045.248M32%20416h64c17.664%200%2032-14.336%2032-32s-14.336-32-32-32H32c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032m640%200h64c17.664%200%2032-14.336%2032-32s-14.336-32-32-32h-64c-17.664%200-32%2014.336-32%2032s14.336%2032%2032%2032M157.664%20655.584l45.44-45.44c12.512-12.512%2012.512-32.768%200-45.248s-32.768-12.512-45.248%200l-45.44%2045.44c-12.512%2012.512-12.512%2032.768%200%2045.248s32.768%2012.512%2045.248%200m452.48-452.48%2045.44-45.44c12.512-12.512%2012.512-32.768%200-45.248s-32.768-12.512-45.248%200l-45.44%2045.44c-12.512%2012.512-12.512%2032.768%200%2045.248s32.768%2012.512%2045.248%200%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-lock-open: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M128%20256v-64c0-106.039%2085.961-192%20192-192s192%2085.961%20192%20192v0h-96v64h128c35.346%200%2064%2028.654%2064%2064v0%20256c0%2035.346-28.654%2064-64%2064v0h-448c-35.346%200-64-28.654-64-64v0-256c0-35.2%2028.8-64%2064-64h32zM288%20471.36v72.64h64v-72.64c19.265-11.272%2032-31.861%2032-55.426%200-35.346-28.654-64-64-64s-64%2028.654-64%2064c0%2023.564%2012.735%2044.154%2031.698%2055.262l0.302%200.164zM224%20192v64h192v-64c0-53.019-42.981-96-96-96s-96%2042.981-96%2096v0z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-lock-closed: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20640%20640%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M128%20256v-64c0-106.039%2085.961-192%20192-192s192%2085.961%20192%20192v0%2064h32c35.346%200%2064%2028.654%2064%2064v0%20256c0%2035.346-28.654%2064-64%2064v0h-448c-35.346%200-64-28.654-64-64v0-256c0-35.2%2028.8-64%2064-64h32zM288%20471.36v72.64h64v-72.64c19.265-11.272%2032-31.861%2032-55.426%200-35.346-28.654-64-64-64s-64%2028.654-64%2064c0%2023.564%2012.735%2044.154%2031.698%2055.262l0.302%200.164zM224%20192v64h192v-64c0-53.019-42.981-96-96-96s-96%2042.981-96%2096v0z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-logo-apeegg-simple: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20340%20448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M305.249%20120.181C273.934%2053.884%20221.742%200%20169.834%200%20117.079%200%2064.323%2058.398%2033.008%20126.106%209.028%20178.861%200%20237.259%200%20278.167c0%2093.944%2076.171%20169.834%20169.834%20169.834s169.834-76.171%20169.834-169.834c0-41.753-9.31-104.383-34.418-157.985zM132.877%20390.166c-37.521.847-37.521-27.647-37.521-27.647%202.257-24.544%2020.03-19.184%2043.164-20.03s42.035%2016.927%2043.164%2026.801c.847%209.874-11.284%2020.03-48.806%2020.877zm115.949-180.272c0%2018.337%2014.952%2027.93%2018.056%2036.957%203.103%209.31%206.489%2027.083-2.821%2030.751-13.824%205.078-26.237-4.514-44.574-16.081s-7.617%2010.721-7.617%2010.721%2017.773%2028.493%2017.773%2055.295-21.441%2018.337-21.441%2018.337-30.468-25.108-69.683-25.108c-39.214%200-40.343%209.028-54.73%209.874-14.67.847-15.234-3.95-15.234-17.773s7.617-22.851%2018.056-34.7c7.335-8.181%206.489-23.134-5.925-16.927s-37.521%2015.234-38.368%200%2022.287-35.265%2022.287-49.934-32.161-29.904-33.854-41.471C29.34%20158.268%2047.678%2094.51%2081.532%2093.664c33.008-.847%2010.438%2028.493%2063.194%2029.904h6.771c7.899-.282%2021.723-.564%2043.728-20.594%2027.647-25.39%2052.192-20.03%2062.912-11.567s32.161%2020.03%2032.161%2057.552c0%2037.804-41.471%2042.317-41.471%2060.937z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M116.232%20208.201c-12.695%201.975-29.058-9.028-34.418-12.977-.847-.564-1.975-.282-2.257.847-6.489%2024.544%206.206%2023.98%2012.413%2025.955%206.489%201.975%202.539%206.489-.282%208.181-3.385%201.693-15.799-1.128-15.799-1.128.564%207.335%2014.388%205.078%2020.03%204.796%201.41%200%202.821-.564%203.95-1.693%206.489-5.642%2029.622-25.955%2016.363-23.98zm69.4%205.643c-11.849-.282%205.078%2014.67%2013.542%2021.723%203.103%202.539%206.771%204.232%2010.721%204.796%206.489.847%2015.799.847%2016.081-5.642%200%200-13.259%203.103-15.799%201.128s-7.053-6.206-.282-8.181c6.489-1.975%2030.186-1.411%2022.569-27.93-.282%200-30.186%2014.388-46.831%2014.106zm-10.72%2020.312c-6.206%200-34.418%2028.212-34.983%2033.008-.282%204.514-7.053-31.033-26.237-30.186-19.184.564-12.977%2013.259-11.003%2019.184s16.645%2017.491%2021.159%2017.773c0%200-13.824-13.541-13.824-18.902s1.41-7.053%205.36-7.053%209.31%203.103%2012.695%2010.72c2.539%205.925%206.206%2013.824%207.617%2017.491.564%201.128%201.411%201.693%202.821%201.693.847%200%201.975-.564%202.257-1.128%203.95-5.642%2021.441-28.776%2031.879-28.776%2011.849%200%207.053%2012.413%203.95%2014.952-3.103%202.821-9.874%207.617-20.03%209.592%200%200%2013.824%203.95%2029.622-11.567%2015.799-14.952-3.385-26.801-11.284-26.801z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-logo-apeegg: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20777%20448%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M305.249%20120.181C273.934%2053.884%20221.742%200%20169.834%200%20117.079%200%2064.323%2058.398%2033.008%20126.106%209.028%20178.861%200%20237.259%200%20278.167c0%2093.944%2076.171%20169.834%20169.834%20169.834s169.834-76.171%20169.834-169.834c0-41.753-9.31-104.383-34.418-157.985zM132.877%20390.166c-37.521.847-37.521-27.647-37.521-27.647%202.257-24.544%2020.03-19.184%2043.164-20.03s42.035%2016.927%2043.164%2026.801c.847%209.874-11.284%2020.03-48.806%2020.877zm115.949-180.272c0%2018.337%2014.952%2027.93%2018.056%2036.957%203.103%209.31%206.489%2027.083-2.821%2030.751-13.824%205.078-26.237-4.514-44.574-16.081s-7.617%2010.721-7.617%2010.721%2017.773%2028.493%2017.773%2055.295-21.441%2018.337-21.441%2018.337-30.468-25.108-69.683-25.108c-39.214%200-40.343%209.028-54.73%209.874-14.67.847-15.234-3.95-15.234-17.773s7.617-22.851%2018.056-34.7c7.335-8.181%206.489-23.134-5.925-16.927s-37.521%2015.234-38.368%200%2022.287-35.265%2022.287-49.934-32.161-29.904-33.854-41.471C29.34%20158.268%2047.678%2094.51%2081.532%2093.664c33.008-.847%2010.438%2028.493%2063.194%2029.904h6.771c7.899-.282%2021.723-.564%2043.728-20.594%2027.647-25.39%2052.192-20.03%2062.912-11.567s32.161%2020.03%2032.161%2057.552c0%2037.804-41.471%2042.317-41.471%2060.937z%22%20%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%0A%20%20%20%20d%3D%22M116.232%20208.201c-12.695%201.975-29.058-9.028-34.418-12.977-.847-.564-1.975-.282-2.257.847-6.489%2024.544%206.206%2023.98%2012.413%2025.955%206.489%201.975%202.539%206.489-.282%208.181-3.385%201.693-15.799-1.128-15.799-1.128.564%207.335%2014.388%205.078%2020.03%204.796%201.41%200%202.821-.564%203.95-1.693%206.489-5.642%2029.622-25.955%2016.363-23.98zm69.4%205.643c-11.849-.282%205.078%2014.67%2013.542%2021.723%203.103%202.539%206.771%204.232%2010.721%204.796%206.489.847%2015.799.847%2016.081-5.642%200%200-13.259%203.103-15.799%201.128s-7.053-6.206-.282-8.181c6.489-1.975%2030.186-1.411%2022.569-27.93-.282%200-30.186%2014.388-46.831%2014.106zm-10.72%2020.312c-6.206%200-34.418%2028.212-34.983%2033.008-.282%204.514-7.053-31.033-26.237-30.186-19.184.564-12.977%2013.259-11.003%2019.184s16.645%2017.491%2021.159%2017.773c0%200-13.824-13.541-13.824-18.902s1.41-7.053%205.36-7.053%209.31%203.103%2012.695%2010.72c2.539%205.925%206.206%2013.824%207.617%2017.491.564%201.128%201.411%201.693%202.821%201.693.847%200%201.975-.564%202.257-1.128%203.95-5.642%2021.441-28.776%2031.879-28.776%2011.849%200%207.053%2012.413%203.95%2014.952-3.103%202.821-9.874%207.617-20.03%209.592%200%200%2013.824%203.95%2029.622-11.567%2015.799-14.952-3.385-26.801-11.284-26.801zm309.199-77.3H451.95l-14.388%2043.446h-42.599l48.524-165.038h49.652l48.242%20165.038h-42.317zM601.189%2035.265c7.053%200%2013.542%201.128%2019.184%203.668s10.72%206.206%2014.67%2010.721c3.95%204.796%207.335%2010.156%209.31%2016.927q3.385%209.734%203.385%2022.005c0%207.899-1.128%2015.234-3.385%2021.723s-5.36%2012.131-9.31%2016.927-9.028%208.463-14.67%2011.003-12.131%203.95-19.184%203.95h-12.413v58.116h-37.803V35.267h50.217zm160.806%2037.239h-63.758v26.801h46.831v37.239h-46.831v26.519h63.758v37.239H660.998V35.264h100.997zM502.73%20279.013h-64.04v26.519h47.114v37.239h-47.113v26.519h64.04v37.239H401.452V241.773h101.279zm134.005%2097.048c-2.821%203.95-6.206%207.899-10.156%2011.567s-8.181%207.053-12.977%209.874-10.156%205.078-15.799%206.771-11.849%202.539-18.056%202.539h-.282c-9.874%200-18.62-1.693-26.237-4.796-7.617-3.385-13.824-7.899-18.902-13.541s-9.028-12.695-11.849-20.594-4.232-16.645-4.796-26.237v-34.136c0-8.746%201.41-17.209%203.95-25.39%202.539-7.899%206.489-14.952%2011.849-20.877%205.078-5.925%2011.567-10.721%2019.184-14.388s16.645-5.36%2026.519-5.36h.282q15.234.846%2024.544%205.078c6.206%203.103%2011.284%206.489%2014.952%2010.438s6.489%207.899%208.463%2011.849q2.963%205.925%205.078%209.31l-30.468%2020.312c-.847-1.693-1.693-3.385-2.539-5.642s-2.257-3.95-3.95-5.642-3.95-3.385-6.206-4.514c-2.539-1.128-5.642-1.975-9.592-1.975-7.335%200-13.259%202.539-17.491%207.335-4.232%205.078-6.489%2011.567-6.489%2019.748v32.161c0%203.95.564%207.617%201.975%2011.284%201.411%203.385%203.103%206.489%205.36%208.746%202.257%202.539%205.078%204.514%208.181%205.925s6.489%202.257%2010.156%202.257c5.078.282%209.31-.847%2012.413-2.539%203.103-1.975%205.642-4.232%207.335-7.335v-8.181h-17.491v-31.879h53.32v57.834zm140.212%200c-2.821%203.95-6.206%207.899-10.156%2011.567s-8.181%207.053-12.977%209.874-10.156%205.078-15.799%206.771-11.849%202.539-18.056%202.539h-.564c-9.874%200-18.62-1.693-26.237-4.796-7.617-3.385-13.824-7.899-18.902-13.541s-9.028-12.695-11.849-20.594-4.232-16.645-4.514-26.237v-34.136c0-8.746%201.41-17.209%203.95-25.39%202.539-7.899%206.489-14.952%2011.849-20.877%205.078-5.925%2011.567-10.721%2019.184-14.388s16.645-5.36%2026.519-5.36h.282q15.234.846%2024.544%205.078c6.206%203.103%2011.284%206.489%2014.952%2010.438s6.489%207.899%208.463%2011.849q2.963%205.925%205.078%209.31l-30.468%2020.312c-.847-1.693-1.693-3.385-2.539-5.642s-2.257-3.95-3.95-5.642-3.95-3.385-6.206-4.514c-2.539-1.128-5.642-1.975-9.592-1.975-7.335%200-13.259%202.539-17.491%207.335-4.232%205.078-6.489%2011.567-6.489%2019.748v32.161c0%203.95.564%207.617%201.975%2011.284%201.41%203.385%203.103%206.489%205.36%208.746%202.257%202.539%205.078%204.514%208.181%205.925s6.489%202.257%2010.156%202.257c5.078.282%209.31-.847%2012.413-2.539%203.103-1.975%205.642-4.232%207.335-7.335v-8.181h-17.491v-31.879h53.32v57.834z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-logo-react: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2023%2020.5%22%3E%0A%20%20%3Ccircle%20fill%3D%22%2361dafb%22%20cx%3D%2211.5%22%20cy%3D%2210.2%22%20r%3D%222%22%2F%3E%0A%20%20%3Cpath%20fill%3D%22%2361dafb%22%20d%3D%22M23%2C10.2c0-1.6-1.9-3-4.8-3.9.7-3%2C.5-5.3-.9-6.1-1.4-.8-3.5.1-5.8%2C2.3C9.3.4%2C7.2-.5%2C5.8.3c-1.2.7-1.6%2C2.4-1.2%2C4.8%2C0%2C.4.2.9.3%2C1.3-2.9.8-4.8%2C2.2-4.8%2C3.9s1.9%2C3%2C4.8%2C3.8c-.1.5-.2.9-.3%2C1.3-.4%2C2.4%2C0%2C4.1%2C1.2%2C4.8.3.2.7.3%2C1.2.3%2C1%2C0%2C2.2-.6%2C3.6-1.6.3-.3.7-.6%2C1-.9.3.3.7.6%2C1%2C.9%2C1.3%2C1.1%2C2.6%2C1.6%2C3.6%2C1.6s.8%2C0%2C1.2-.3c1.2-.7%2C1.6-2.4%2C1.2-4.8%2C0-.4-.2-.9-.3-1.3%2C2.9-.8%2C4.8-2.2%2C4.8-3.8ZM16.1%2C1c.2%2C0%2C.5%2C0%2C.7.2.9.5%2C1.1%2C2.4.5%2C5-.9-.2-2-.4-3.1-.5-.6-.9-1.3-1.7-1.9-2.4%2C1.5-1.5%2C2.9-2.3%2C3.9-2.3ZM7.4%2C12.6c.2.4.5.8.7%2C1.2-.7-.1-1.4-.2-2.1-.4.2-.6.4-1.3.7-2%2C.2.4.4.8.6%2C1.2ZM6.1%2C7.1c.6-.2%2C1.3-.3%2C2.1-.4-.2.4-.5.8-.7%2C1.1-.2.4-.4.8-.6%2C1.2-.3-.7-.5-1.3-.7-2ZM7.3%2C10.2c.3-.6.6-1.2%2C1-1.9.4-.6.7-1.2%2C1.1-1.8.7%2C0%2C1.4%2C0%2C2.1%2C0s1.4%2C0%2C2.1%2C0c.4.5.8%2C1.1%2C1.1%2C1.8.3.6.7%2C1.2%2C1%2C1.9-.3.6-.6%2C1.2-1%2C1.8-.4.6-.7%2C1.2-1.1%2C1.8-.7%2C0-1.4%2C0-2.1%2C0s-1.4%2C0-2.1%2C0c-.4-.6-.8-1.2-1.1-1.8-.4-.6-.7-1.2-1-1.8ZM15.6%2C12.6c.2-.4.4-.8.6-1.2.3.7.5%2C1.3.7%2C2-.6.1-1.3.3-2.1.4.2-.4.5-.8.7-1.2ZM15.6%2C7.9c-.2-.4-.5-.8-.7-1.1.7%2C0%2C1.4.2%2C2.1.4-.2.6-.4%2C1.3-.7%2C2-.2-.4-.4-.8-.6-1.2ZM11.5%2C3.9c.4.5.9%2C1%2C1.3%2C1.6-.4%2C0-.9%2C0-1.3%2C0s-.9%2C0-1.3%2C0c.5-.6.9-1.1%2C1.3-1.6ZM6.2%2C1.1c.2-.1.4-.2.7-.2.9%2C0%2C2.2.7%2C3.6%2C1.9.1%2C0%2C.2.2.3.3-.6.7-1.3%2C1.5-1.9%2C2.4-1.1%2C0-2.1.3-3.1.5-.1-.4-.2-.8-.3-1.2-.3-2%2C0-3.3.7-3.8ZM1%2C10.2c0-1.1%2C1.5-2.2%2C4.1-2.9.3.9.7%2C1.9%2C1.1%2C2.9-.5%2C1-.8%2C1.9-1.1%2C2.9-2.6-.7-4.1-1.8-4.1-2.9ZM9.9%2C18.1c-1.5%2C1.2-2.8%2C1.7-3.6%2C1.3-.8-.5-1-1.8-.7-3.8%2C0-.4.1-.8.3-1.2.9.2%2C2%2C.4%2C3.1.5.6.9%2C1.3%2C1.7%2C1.9%2C2.4-.3.3-.6.6-.9.8ZM10.2%2C14.9c.4%2C0%2C.9%2C0%2C1.3%2C0s.9%2C0%2C1.3%2C0c-.4.6-.9%2C1.1-1.3%2C1.6-.5-.5-.9-1-1.3-1.6ZM16.8%2C19.3c-.8.4-2.1%2C0-3.6-1.3-.3-.2-.6-.5-.9-.8.7-.7%2C1.3-1.5%2C1.9-2.4%2C1.1%2C0%2C2.1-.3%2C3.1-.5.1.4.2.8.3%2C1.2.3%2C2%2C0%2C3.3-.7%2C3.8ZM17.9%2C13.1c-.3-.9-.7-1.9-1.1-2.9.5-1%2C.8-2%2C1.1-2.9%2C2.6.7%2C4.1%2C1.8%2C4.1%2C2.9s-1.5%2C2.2-4.1%2C2.9Z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-logo-svelte: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2098.1%20118%22%3E%0A%20%20%3Cpath%20fill%3D%22%23ff3e00%22%20d%3D%22M91.8%2C15.6C80.9%2C0%2C59.2-4.7%2C43.6%2C5.2l-27.5%2C17.6c-7.5%2C4.7-12.7%2C12.4-14.2%2C21.1-1.3%2C7.3-.2%2C14.8%2C3.3%2C21.3-2.4%2C3.6-4%2C7.6-4.7%2C11.8-1.6%2C8.9.5%2C18.1%2C5.7%2C25.4%2C11%2C15.7%2C32.6%2C20.3%2C48.2%2C10.4l27.5-17.5c7.5-4.7%2C12.7-12.4%2C14.2-21.1%2C1.3-7.3.2-14.8-3.3-21.3%2C2.4-3.6%2C4-7.6%2C4.7-11.8%2C1.7-9-.4-18.2-5.7-25.5ZM84%2C38.1c-.2.9-.4%2C1.7-.7%2C2.6l-.5%2C1.6-1.4-1c-3.3-2.4-6.9-4.2-10.8-5.4l-1-.3v-1c.2-1.4-.2-2.9-1-4.1-1.6-2.3-4.4-3.3-7.1-2.6-.6.2-1.2.4-1.7.7l-27.4%2C17.5c-1.4.9-2.3%2C2.2-2.6%2C3.8-.3%2C1.6.1%2C3.3%2C1%2C4.6%2C1.6%2C2.3%2C4.4%2C3.3%2C7.1%2C2.6.6-.2%2C1.2-.4%2C1.7-.7l10.5-6.7c1.7-1.1%2C3.6-1.9%2C5.6-2.5%2C8.9-2.3%2C18.2%2C1.2%2C23.4%2C8.7%2C3.2%2C4.4%2C4.4%2C9.9%2C3.5%2C15.3-.9%2C5.2-4.1%2C9.9-8.6%2C12.7l-27.5%2C17.5c-1.7%2C1.1-3.6%2C1.9-5.6%2C2.5-8.9%2C2.3-18.2-1.2-23.4-8.7-3.2-4.4-4.4-9.9-3.5-15.3.2-.9.4-1.7.6-2.6l.5-1.6%2C1.4%2C1c3.3%2C2.4%2C6.9%2C4.2%2C10.8%2C5.4l1%2C.3v1c-.2%2C1.4.2%2C2.9%2C1%2C4.1%2C1.6%2C2.3%2C4.4%2C3.4%2C7.1%2C2.7.6-.2%2C1.2-.4%2C1.7-.7l27.4-17.5c1.4-.9%2C2.3-2.2%2C2.6-3.8.3-1.6%2C0-3.3-1-4.6-1.6-2.3-4.4-3.3-7.1-2.6-.6.2-1.2.4-1.7.7l-10.5%2C6.7c-1.7%2C1.1-3.6%2C1.9-5.6%2C2.4-8.9%2C2.3-18.2-1.2-23.4-8.7-3.1-4.4-4.4-9.9-3.4-15.3.9-5.2%2C4.1-9.9%2C8.6-12.7l27.5-17.5c1.7-1.1%2C3.6-1.9%2C5.6-2.5%2C8.9-2.3%2C18.2%2C1.2%2C23.4%2C8.7%2C3.2%2C4.4%2C4.4%2C9.9%2C3.5%2C15.3Z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-logo-vibe: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20260%20257%22%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M104.16%2C73.48c12.36-1.2%2C26.82%2C2.68%2C38.06%2C10.15%2C3.88%2C2.57%2C10.55%2C9.13%2C12.87%2C12.72%2C6.16%2C9.46%2C8.55%2C20.33%2C7.07%2C31.89-.8%2C5.98-.4%2C7.97%2C1.63%2C7.97%2C3.66%2C0%2C10.55-11.45%2C13.52-22.62%2C4.1-13.21.94-28.89.14-32.47-2.07-9.35-6.89-21.46-11.89-29.97-9.02-15.37-24.57-30.99-42.37-42.59-5.29-3.48-12.14-7.32-14.39-8.12-2.1-.72-6.05-.58-10.4.43-4.78%2C1.09-14.24%2C4.24-19.43%2C6.49-13.34%2C5.69-24.46%2C12.79-35.52%2C22.69-14.93%2C13.34-24.65%2C26.57-32.47%2C44.22C5.14%2C87.44%2C1.95%2C99.14.43%2C113.03c-.65%2C6.2-.54%2C21.49.22%2C27.91%2C1.49%2C12.29%2C4.82%2C24.46%2C9.39%2C34.14%2C3.77%2C7.97%2C5.55%2C9.89%2C7.36%2C7.79.83-.94.8-.91%2C2.14-11.82%2C3.41-27.47%2C16.2-54.51%2C34.47-72.7%2C14.97-14.93%2C31.42-23.09%2C50.16-24.86l-.01-.01Z%22%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M257.31%2C105.29c-3.47-19.72-9.59-34.95-20.47-50.9-8.11-11.89-16.38-20.77-27.37-29.38-4.92-3.82-17.98-11.79-23.83-14.52-11.23-5.21-23.33-8.79-33.96-10.01-8.76-1-11.33-.5-10.5%2C2.15.36%2C1.21.35%2C1.16%2C8.92%2C8.04%2C21.55%2C17.37%2C37.79%2C42.49%2C43.63%2C67.61%2C4.8%2C20.59%2C3.06%2C38.87-5.3%2C55.73-5.5%2C11.13-16.41%2C21.38-28.68%2C27-4.23%2C1.94-13.32%2C4.15-17.59%2C4.23-11.29.25-21.79-3.44-30.83-10.8-4.66-3.83-6.57-4.54-7.64-2.82-1.93%2C3.11%2C4.18%2C15%2C12.1%2C23.41%2C9.06%2C10.45%2C24.05%2C16.02%2C27.52%2C17.24%2C9.04%2C3.17%2C21.86%2C5.45%2C31.74%2C5.69%2C17.82.43%2C39.29-4.56%2C58.52-13.57%2C5.75-2.66%2C12.62-6.46%2C14.48-7.95%2C1.72-1.4%2C3.68-4.84%2C5.11-9.07%2C1.6-4.64%2C3.9-14.34%2C4.72-19.93%2C2.19-14.33%2C2.02-27.53-.57-42.14v-.01Z%22%2F%3E%0A%20%20%3Cpath%20fill%3D%22%23000%22%20d%3D%22M231.57%2C197.33c-1.23-.27-1.18-.25-11.35%2C3.92-25.63%2C10.47-55.47%2C12.54-80.27%2C5.51-20.35-5.75-35.51-16.11-46.23-31.58-7.09-10.19-10.78-24.7-9.77-38.16.35-4.64%2C2.81-13.67%2C4.8-17.45%2C5.24-10%2C13.55-17.41%2C24.36-21.77%2C5.61-2.23%2C7.15-3.55%2C6.16-5.32-1.79-3.19-15.15-3.59-26.34-.73-13.53%2C2.88-25.65%2C13.31-28.39%2C15.76-7.14%2C6.38-15.34%2C16.5-20.32%2C25.03-8.99%2C15.39-15%2C36.59-16.41%2C57.79-.45%2C6.32-.44%2C14.17-.04%2C16.52.4%2C2.19%2C2.46%2C5.56%2C5.47%2C8.86%2C3.29%2C3.64%2C10.67%2C10.35%2C15.16%2C13.77%2C11.49%2C8.85%2C23.13%2C15.08%2C37.17%2C19.88%2C18.94%2C6.5%2C35.23%2C8.5%2C54.45%2C6.69%2C14.33-1.35%2C26.1-4.29%2C38.95-9.76%2C5.72-2.46%2C19.01-10.04%2C24.23-13.84%2C9.99-7.31%2C18.98-16.17%2C25.18-24.89%2C5.11-7.19%2C5.92-9.68%2C3.2-10.23h-.01Z%22%2F%3E%0A%3C%2Fsvg%3E'); + --icon-logo-x: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M14.234%2010.162%2022.977%200h-2.072l-7.591%208.824L7.251%200H.258l9.168%2013.343L.258%2024H2.33l8.016-9.318L16.749%2024h6.993zm-2.837%203.299-.929-1.329L3.076%201.56h3.182l5.965%208.532.929%201.329%207.754%2011.09h-3.182z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-logo-github: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M8%200.198c-4.418%200-8%203.582-8%208%200%203.535%202.292%206.533%205.471%207.591%200.4%200.074%200.547-0.174%200.547-0.385%200-0.191-0.008-0.821-0.011-1.489-2.226%200.484-2.695-0.944-2.695-0.944-0.364-0.925-0.888-1.171-0.888-1.171-0.726-0.497%200.055-0.486%200.055-0.486%200.803%200.056%201.226%200.824%201.226%200.824%200.714%201.223%201.872%200.869%202.328%200.665%200.072-0.517%200.279-0.87%200.508-1.070-1.777-0.202-3.645-0.888-3.645-3.954%200-0.873%200.313-1.587%200.824-2.147-0.083-0.202-0.357-1.015%200.077-2.117%200%200%200.672-0.215%202.201%200.82%200.638-0.177%201.322-0.266%202.002-0.269%200.68%200.003%201.365%200.092%202.004%200.269%201.527-1.035%202.198-0.82%202.198-0.82%200.435%201.102%200.162%201.916%200.079%202.117%200.513%200.56%200.823%201.274%200.823%202.147%200%203.073-1.872%203.749-3.653%203.947%200.287%200.248%200.543%200.735%200.543%201.481%200%201.070-0.009%201.932-0.009%202.195%200%200.213%200.144%200.462%200.55%200.384%203.177-1.059%205.466-4.057%205.466-7.59%200-4.418-3.582-8-8-8z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-quill: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M0%2016c2-6%207.234-16%2016-16-4.109%203.297-6%2011-9%2011s-3%200-3%200l-3%205h-1z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-pencil: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M6%2010l2-1%207-7-1-1-7%207-1%202zM4.52%2013.548c-0.494-1.043-1.026-1.574-2.069-2.069l1.548-4.262%202-1.217%206-6h-3l-6%206-3%2010%2010-3%206-6v-3l-6%206-1.217%202z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-play-button: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M8%200c-4.418%200-8%203.582-8%208s3.582%208%208%208%208-3.582%208-8-3.582-8-8-8zM8%2014.5c-3.59%200-6.5-2.91-6.5-6.5s2.91-6.5%206.5-6.5%206.5%202.91%206.5%206.5-2.91%206.5-6.5%206.5zM6%204.5l6%203.5-6%203.5z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-pin: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M8%200c-2.761%200-5%202.239-5%205%200%205%205%2011%205%2011s5-6%205-11c0-2.761-2.239-5-5-5zM8%208c-1.657%200-3-1.343-3-3s1.343-3%203-3%203%201.343%203%203-1.343%203-3%203z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-search: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M496.131%20435.698l-121.276-103.147c-12.537-11.283-25.945-16.463-36.776-15.963%2028.628-33.534%2045.921-77.039%2045.921-124.588%200-106.039-85.961-192-192-192s-192%2085.961-192%20192%2085.961%20192%20192%20192c47.549%200%2091.054-17.293%20124.588-45.922-0.5%2010.831%204.68%2024.239%2015.963%2036.776l103.147%20121.276c17.661%2019.623%2046.511%2021.277%2064.11%203.678s15.946-46.449-3.677-64.11zM192%20320c-70.692%200-128-57.308-128-128s57.308-128%20128-128%20128%2057.308%20128%20128-57.307%20128-128%20128z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-spinner: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M304%2C480c-114.7%2C0-207.6-99.9-208-223.3%2C0-26.5-21.8-48.9-48.4-48.7-26.3.2-47.6%2C21.6-47.6%2C48%2C0%2C141.4%2C114.6%2C256%2C256%2C256s249.6-108.4%2C255.7-244.3c-5.6%2C118.3-96.5%2C212.3-207.7%2C212.3ZM256%2C0C118.5%2C0%2C6.4%2C108.4.3%2C244.3%2C5.9%2C126%2C96.8%2C32%2C208%2C32s207.6%2C99.9%2C208%2C223.3c0%2C26.5%2C21.8%2C48.9%2C48.4%2C48.7%2C26.3-.2%2C47.6-21.6%2C47.6-48C512%2C114.6%2C397.4%2C0%2C256%2C0Z%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + --icon-smartphone: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M12%200h-9c-0.55%200-1%200.45-1%201v14c0%200.55%200.45%201%201%201h9c0.55%200%201-0.45%201-1v-14c0-0.55-0.45-1-1-1zM7.5%2015.278c-0.43%200-0.778-0.348-0.778-0.778s0.348-0.778%200.778-0.778%200.778%200.348%200.778%200.778-0.348%200.778-0.778%200.778zM12%2013h-9v-11h9v11z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-stack: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M16%205l-8-4-8%204%208%204%208-4zM8%202.328l5.345%202.672-5.345%202.672-5.345-2.672%205.345-2.672zM14.398%207.199l1.602%200.801-8%204-8-4%201.602-0.801%206.398%203.199zM14.398%2010.199l1.602%200.801-8%204-8-4%201.602-0.801%206.398%203.199z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-tablet: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M12.5%200h-10c-0.825%200-1.5%200.675-1.5%201.5v13c0%200.825%200.675%201.5%201.5%201.5h10c0.825%200%201.5-0.675%201.5-1.5v-13c0-0.825-0.675-1.5-1.5-1.5zM7.5%2015.5c-0.276%200-0.5-0.224-0.5-0.5s0.224-0.5%200.5-0.5%200.5%200.224%200.5%200.5-0.224%200.5-0.5%200.5zM12%2014h-9v-12h9v12z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-user: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M9%2011.041v-0.825c1.102-0.621%202-2.168%202-3.716%200-2.485%200-4.5-3-4.5s-3%202.015-3%204.5c0%201.548%200.898%203.095%202%203.716v0.825c-3.392%200.277-6%201.944-6%203.959h14c0-2.015-2.608-3.682-6-3.959z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-void: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20viewBox%3D%220%200%20120%20120%22%3E%0A%20%20%3Cpath%0A%20%20%20%20d%3D%22M111.82%2C60.419c-26.177%2C4.938-46.869%2C25.364-52.226%2C51.388-4.951-26.164-25.377-46.844-51.414-52.201%2C26.177-4.951%2C46.869-25.377%2C52.214-51.414%2C4.938%2C26.177%2C25.39%2C46.882%2C51.427%2C52.226Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + --icon-upload: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M7%209h2v-4h3l-4-4-4%204h3zM10%206.75v1.542l4.579%201.708-6.579%202.453-6.579-2.453%204.579-1.708v-1.542l-6%202.25v4l8%203%208-3v-4z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-components: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M192%20288h-160c-17.688%200-32%2014.312-32%2032v160c0%2017.688%2014.312%2032%2032%2032h160c17.688%200%2032-14.312%2032-32v-160c0-17.688-14.312-32-32-32zM160%20448h-96v-96h96v96zM192%200h-160c-17.688%200-32%2014.312-32%2032v160c0%2017.688%2014.312%2032%2032%2032h160c17.688%200%2032-14.312%2032-32v-160c0-17.688-14.312-32-32-32zM160%20160h-96v-96h96v96zM480%20288h-160c-17.688%200-32%2014.312-32%2032v160c0%2017.688%2014.312%2032%2032%2032h160c17.688%200%2032-14.312%2032-32v-160c0-17.688-14.312-32-32-32zM448%20448h-96v-96h96v96zM480%200h-160c-17.688%200-32%2014.312-32%2032v160c0%2017.688%2014.312%2032%2032%2032h160c17.688%200%2032-14.312%2032-32v-160c0-17.688-14.312-32-32-32zM448%20160h-96v-96h96v96z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-users: url('data:image/svg+xml;utf8,%3C!--%20Generated%20by%20IcoMoon.io%20--%3E%0A%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22576%22%20height%3D%22512%22%20viewBox%3D%220%200%20576%20512%22%3E%0A%3Cg%20id%3D%22icomoon-ignore%22%3E%0A%3C%2Fg%3E%0A%3Cpath%20d%3D%22M384%20385.306v-26.39c35.249-19.864%2064-69.386%2064-118.916%200-79.529%200-144-96-144s-96%2064.471-96%20144c0%2049.53%2028.751%2099.052%2064%20118.916v26.39c-108.551%208.874-192%2062.21-192%20126.694h448c0-64.484-83.449-117.82-192-126.694z%22%3E%3C%2Fpath%3E%0A%3Cpath%20d%3D%22M163.598%20397.664c27.655-18.075%2062.040-31.818%2099.894-40.207-7.527-8.892-14.354-18.811-20.246-29.51-15.207-27.617-23.246-58.029-23.246-87.947%200-43.021%200-83.655%2015.3-116.881%2014.853-32.252%2041.564-52.248%2079.611-59.744-8.457-38.24-30.97-63.375-90.911-63.375-96%200-96%2064.471-96%20144%200%2049.53%2028.751%2099.052%2064%20118.916v26.39c-108.551%208.874-192%2062.21-192%20126.694h139.503c7.259-6.455%2015.298-12.586%2024.095-18.336z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-menu: url('data:image/svg+xml;utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%20viewBox%3D%220%200%20512%20512%22%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M85%2091h341v42h-341z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M85%20235h341v42h-341z%22%3E%3C%2Fpath%3E%0A%3Cpath%20fill%3D%22%23000%22%20d%3D%22M85%20379h341v42h-341z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A'); + --icon-stylecheat: url('data:image/svg+xml;utf8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Csvg%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20viewBox%3D%220%200%20128%20140%22%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2264%200%2084%2011%2064%2022%2044%2011%2064%200%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2286%2012%20106%2023%2086%2034%2066%2023%2086%2012%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%22108%2024%20128%2035%20108%2046%2088%2035%20108%2024%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2242%2012%2062%2023%2042%2034%2022%2023%2042%2012%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2264%2024%2084%2035%2064%2046%2044%2035%2064%2024%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2286%2036%20106%2047%2086%2058%2066%2047%2086%2036%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2220%2024%2040%2035%2020%2046%200%2035%2020%2024%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2242%2036%2062%2047%2042%2058%2022%2047%2042%2036%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%23918dc6%22%20points%3D%2264%2048%2084%2059%2064%2070%2044%2059%2064%2048%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%220%2035%2020%2046%2020%2068%200%2057%200%2035%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2222%2047%2042%2058%2042%2080%2022%2069%2022%2047%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2244%2059%2064%2070%2064%2092%2044%2081%2044%2059%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%220%2059%2020%2070%2020%2092%200%2081%200%2059%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2222%2071%2042%2082%2042%20104%2022%2093%2022%2071%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2244%2083%2064%2094%2064%20116%2044%20105%2044%2083%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%220%2083%2020%2094%2020%20116%200%20105%200%2083%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2222%2095%2042%20106%2042%20128%2022%20117%2022%2095%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%238888bc%22%20points%3D%2244%20107%2064%20118%2064%20140%2044%20129%2044%20107%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2264%2070%2084%2059%2084%2081%2064%2092%2064%2070%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2286%2058%20106%2047%20106%2069%2086%2080%2086%2058%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%22108%2046%20128%2035%20128%2057%20108%2068%20108%2046%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2264%2094%2084%2083%2084%20105%2064%20116%2064%2094%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2286%2082%20106%2071%20106%2093%2086%20104%2086%2082%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%22108%2070%20128%2059%20128%2081%20108%2092%20108%2070%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2264%20118%2084%20107%2084%20129%2064%20140%2064%20118%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%2286%20106%20106%2095%20106%20117%2086%20128%2086%20106%22%2F%3E%0A%20%20%3Cpolygon%20fill%3D%22%237676a3%22%20points%3D%22108%2094%20128%2083%20128%20105%20108%20116%20108%2094%22%2F%3E%0A%3C%2Fsvg%3E%0A'); + } + + icon, + .icon { + --icon: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20viewBox%3D%220%200%20120%20120%22%3E%0A%20%20%3Cpath%0A%20%20%20%20d%3D%22M111.82%2C60.419c-26.177%2C4.938-46.869%2C25.364-52.226%2C51.388-4.951-26.164-25.377-46.844-51.414-52.201%2C26.177-4.951%2C46.869-25.377%2C52.214-51.414%2C4.938%2C26.177%2C25.39%2C46.882%2C51.427%2C52.226Z%22%20%2F%3E%0A%3C%2Fsvg%3E'); + display: inline-block; + width: 1em; + height: 1em; + background-color: var(--color, currentColor); + mask-image: var(--icon); + mask-repeat: no-repeat; + mask-size: cover; + } + + icon[bell], + icon.bell { + --icon: var(--icon-bell); + width: 1em; + height: 1em; + } + + icon[book], + icon.book { + --icon: var(--icon-book); + width: 1em; + height: 1em; + } + + icon[bullhorn], + icon.bullhorn { + --icon: var(--icon-bullhorn); + width: 1em; + height: 1em; + } + + icon[checkmark], + icon.checkmark { + --icon: var(--icon-checkmark); + width: 1em; + height: 1em; + } + + icon[chevron-left], + icon.chevron-left { + --icon: var(--icon-chevron-left); + width: 1em; + height: 1em; + } + + icon[chevron-down], + icon.chevron-down { + --icon: var(--icon-chevron-down); + width: 1em; + height: 1em; + } + + icon[chevron-right], + icon.chevron-right { + --icon: var(--icon-chevron-right); + width: 1em; + height: 1em; + } + + icon[clock], + icon.clock { + --icon: var(--icon-clock); + width: 1em; + height: 1em; + } + + icon[chevron-up], + icon.chevron-up { + --icon: var(--icon-chevron-up); + width: 1em; + height: 1em; + } + + icon[cog], + icon.cog { + --icon: var(--icon-cog); + width: 1em; + height: 1em; + } + + icon[credit-card], + icon.credit-card { + --icon: var(--icon-credit-card); + width: 1em; + height: 1em; + } + + icon[cross], + icon.cross { + --icon: var(--icon-cross); + width: 1em; + height: 1em; + } + + icon[crow], + icon.crow { + --icon: var(--icon-crow); + width: 1.0105293945598128em; + height: 1em; + } + + icon[css-3], + icon.css-3 { + --icon: var(--icon-css-3); + width: 1em; + height: 1em; + } + + icon[dark], + icon.dark { + --icon: var(--icon-dark); + width: 1em; + height: 1em; + } + + icon[desktop], + icon.desktop { + --icon: var(--icon-desktop); + width: 1em; + height: 1em; + } + + icon[download], + icon.download { + --icon: var(--icon-download); + width: 1em; + height: 1em; + } + + icon[earth], + icon.earth { + --icon: var(--icon-earth); + width: 1em; + height: 1em; + } + + icon[embed], + icon.embed { + --icon: var(--icon-embed); + width: 1.25em; + height: 1em; + } + + icon[eye], + icon.eye { + --icon: var(--icon-eye); + width: 1em; + height: 1em; + } + + icon[folder], + icon.folder { + --icon: var(--icon-folder); + width: 1em; + height: 1em; + } + + icon[heart-broken], + icon.heart-broken { + --icon: var(--icon-heart-broken); + width: 1em; + height: 1em; + } + + icon[heart], + icon.heart { + --icon: var(--icon-heart); + width: 1em; + height: 1em; + } + + icon[home], + icon.home { + --icon: var(--icon-home); + width: 1em; + height: 1em; + } + + icon[html-5], + icon.html-5 { + --icon: var(--icon-html-5); + width: 1em; + height: 1em; + } + + icon[image], + icon.image { + --icon: var(--icon-image); + width: 1em; + height: 1em; + } + + icon[layout], + icon.layout { + --icon: var(--icon-layout); + width: 1em; + height: 1em; + } + + icon[images], + icon.images { + --icon: var(--icon-images); + width: 1.125em; + height: 1em; + } + + icon[light], + icon.light { + --icon: var(--icon-light); + width: 1em; + height: 1em; + } + + icon[lock-open], + icon.lock-open { + --icon: var(--icon-lock-open); + width: 1em; + height: 1em; + } + + icon[lock-closed], + icon.lock-closed { + --icon: var(--icon-lock-closed); + width: 1em; + height: 1em; + } + + icon[logo-apeegg-simple], + icon.logo-apeegg-simple { + --icon: var(--icon-logo-apeegg-simple); + width: 1em; + height: 1.3176470588235294em; + } + + icon[logo-apeegg], + icon.logo-apeegg { + --icon: var(--icon-logo-apeegg); + width: 1.734375em; + height: 1em; + } + + icon[logo-react], + icon.logo-react { + --icon: var(--icon-logo-react); + width: 1.1219512195121952em; + height: 1em; + } + + icon[logo-svelte], + icon.logo-svelte { + --icon: var(--icon-logo-svelte); + width: 0.8313559322033898em; + height: 1em; + } + + icon[logo-vibe], + icon.logo-vibe { + --icon: var(--icon-logo-vibe); + width: 1.0116731517509727em; + height: 1em; + } + + icon[logo-x], + icon.logo-x { + --icon: var(--icon-logo-x); + width: 1em; + height: 1em; + } + + icon[logo-github], + icon.logo-github { + --icon: var(--icon-logo-github); + width: 1em; + height: 1em; + } + + icon[quill], + icon.quill { + --icon: var(--icon-quill); + width: 1em; + height: 1em; + } + + icon[pencil], + icon.pencil { + --icon: var(--icon-pencil); + width: 1em; + height: 1em; + } + + icon[play-button], + icon.play-button { + --icon: var(--icon-play-button); + width: 1em; + height: 1em; + } + + icon[pin], + icon.pin { + --icon: var(--icon-pin); + width: 1em; + height: 1em; + } + + icon[search], + icon.search { + --icon: var(--icon-search); + width: 1em; + height: 1em; + } + + icon[spinner], + icon.spinner { + --icon: var(--icon-spinner); + width: 1em; + height: 1em; + } + + icon[smartphone], + icon.smartphone { + --icon: var(--icon-smartphone); + width: 1em; + height: 1em; + } + + icon[stack], + icon.stack { + --icon: var(--icon-stack); + width: 1em; + height: 1em; + } + + icon[tablet], + icon.tablet { + --icon: var(--icon-tablet); + width: 1em; + height: 1em; + } + + icon[user], + icon.user { + --icon: var(--icon-user); + width: 1em; + height: 1em; + } + + icon[void], + icon.void { + --icon: var(--icon-void); + width: 1em; + height: 1em; + } + + icon[upload], + icon.upload { + --icon: var(--icon-upload); + width: 1em; + height: 1em; + } + + icon[components], + icon.components { + --icon: var(--icon-components); + width: 1em; + height: 1em; + } + + icon[users], + icon.users { + --icon: var(--icon-users); + width: 1.125em; + height: 1em; + } + + icon[menu], + icon.menu { + --icon: var(--icon-menu); + width: 1em; + height: 1em; + } + + icon[stylecheat], + icon.stylecheat { + --icon: var(--icon-stylecheat); + width: 1em; + height: 1.09375em; + } + /* ---- Reset.css ---- */ + @layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + + button, + input, + select, + optgroup, + textarea, + ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + } + + html, + :host { + line-height: 1.5; + } + } + /* ---- Stylecheat.css ---- */ + .stylecheat, + [stylecheat] { + --unit: 4px; + --icon-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 448' fill='currentColor'%3E%3Cpath fill='black' d='m420.75 202-185.5 185.25a15.844 15.844 0 0 1-22.5 0L27.25 202c-6.25-6.25-6.25-16.5 0-22.75L68.75 138a15.844 15.844 0 0 1 22.5 0L224 270.75 356.75 138a15.844 15.844 0 0 1 22.5 0l41.5 41.25c6.25 6.25 6.25 16.5 0 22.75'/%3E%3C/svg%3E"); + --theme-sign: 1; + + --primary: oklch(0.62 0.14 260); + --blue: oklch(0.62 0.21 260); + --purple: oklch(0.63 0.26 304); + --green: oklch(0.72 0.22 142); + --orange: oklch(0.7 0.19 37); + --cyan: oklch(0.71 0.14 215); + --red: oklch(0.64 0.21 25); + --yellow: oklch(0.8 0.18 87); + --slate: oklch(0.55 0.05 264); + } + + .stylecheat.dark, + [stylecheat].dark, + .stylecheat[dark], + [stylecheat][dark] { + --icon-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 448' fill='currentColor'%3E%3Cpath fill='white' d='m420.75 202-185.5 185.25a15.844 15.844 0 0 1-22.5 0L27.25 202c-6.25-6.25-6.25-16.5 0-22.75L68.75 138a15.844 15.844 0 0 1 22.5 0L224 270.75 356.75 138a15.844 15.844 0 0 1 22.5 0l41.5 41.25c6.25 6.25 6.25 16.5 0 22.75'/%3E%3C/svg%3E"); + --theme-sign: -1; + + --primary: oklch(0.75 0.12 260); + --blue: oklch(0.71 0.17 255); + --purple: oklch(0.71 0.2 306); + --green: oklch(0.79 0.21 152); + --orange: oklch(0.75 0.18 48); + --cyan: oklch(0.79 0.15 211); + --red: oklch(0.7 0.19 22); + --yellow: oklch(0.85 0.2 92); + --slate: oklch(0.7 0.04 257); + } + /* ---- Theme.css ---- */ + .stylecheat, + [stylecheat] { + --background: oklch(0.9383 0.0042 236.4993); + --foreground: oklch(0.3211 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.3211 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.3211 0 0); + --primary: oklch(0.6397 0.172 36.4421); + --primary-foreground: oklch(1 0 0); + --secondary: oklch(0.967 0.0029 264.5419); + --secondary-foreground: oklch(0.4461 0.0263 256.8018); + --muted: oklch(0.9846 0.0017 247.8389); + --muted-foreground: oklch(0.551 0.0234 264.3637); + --accent: oklch(0.9119 0.0222 243.8174); + --accent-foreground: oklch(0.3791 0.1378 265.5222); + --destructive: oklch(0.6368 0.2078 25.3313); + --destructive-foreground: oklch(1 0 0); + --border: oklch(0.9022 0.0052 247.8822); + --input: oklch(0.97 0.0029 264.542); + --ring: oklch(0.6397 0.172 36.4421); + --chart-1: oklch(0.7156 0.0605 248.6845); + --chart-2: oklch(0.7875 0.0917 35.9616); + --chart-3: oklch(0.5778 0.0759 254.1573); + --chart-4: oklch(0.5016 0.0849 259.4902); + --chart-5: oklch(0.4241 0.0952 264.0306); + --sidebar: oklch(0.903 0.0046 258.3257); + --sidebar-foreground: oklch(0.3211 0 0); + --sidebar-primary: oklch(0.6397 0.172 36.4421); + --sidebar-primary-foreground: oklch(1 0 0); + --sidebar-accent: oklch(0.9119 0.0222 243.8174); + --sidebar-accent-foreground: oklch(0.3791 0.1378 265.5222); + --sidebar-border: oklch(0.9276 0.0058 264.5313); + --sidebar-ring: oklch(0.6397 0.172 36.4421); + --font-sans: Inter, sans-serif; + --font-serif: Source Serif 4, serif; + --font-mono: JetBrains Mono, monospace; + --radius: 0.75rem; + --shadow-x: 0px; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 2px 4px -1px hsl(0 0% 0% / 0.1); + --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 4px 6px -1px hsl(0 0% 0% / 0.1); + --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 8px 10px -1px hsl(0 0% 0% / 0.1); + --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25); + --tracking-normal: 0em; + --spacing: 0.25rem; + } + + .stylecheat.dark, + [stylecheat].dark, + .stylecheat[dark], + [stylecheat][dark] { + --background: oklch(0.2598 0.0306 262.6666); + --foreground: oklch(0.9219 0 0); + --card: oklch(0.3106 0.0301 268.6365); + --card-foreground: oklch(0.9219 0 0); + --popover: oklch(0.29 0.0249 268.3986); + --popover-foreground: oklch(0.9219 0 0); + --secondary: oklch(0.3095 0.0266 266.7132); + --secondary-foreground: oklch(0.9219 0 0); + --muted: oklch(0.3095 0.0266 266.7132); + --muted-foreground: oklch(0.7155 0 0); + --accent: oklch(0.338 0.0589 267.5867); + --accent-foreground: oklch(0.8823 0.0571 254.1284); + --border: oklch(0.3843 0.0301 269.7337); + --input: oklch(0.3843 0.0301 269.7337); + --chart-2: oklch(0.7693 0.0876 34.1875); + --sidebar: oklch(0.31 0.0283 267.7408); + --sidebar-foreground: oklch(0.9219 0 0); + --sidebar-accent: oklch(0.338 0.0589 267.5867); + --sidebar-accent-foreground: oklch(0.8823 0.0571 254.1284); + --sidebar-border: oklch(0.3843 0.0301 269.7337); + } + /* ---- Typography.css ---- */ + /* Typography - content flow with sibling-aware spacing */ + /* Visual styles apply globally, layout spacing requires [typography] or .typography wrapper */ + + /* Base text color */ + body { + color: var(--foreground); + } + + /* Headings - visual styles (sizes, colors, line-height, font-weight) */ + @layer base { + h1, + .h1, + h2, + .h2, + h3, + .h3, + h4, + .h4, + h5, + .h5, + h6, + .h6 { + margin: 0; + font-weight: 600; + color: var(--primary); + } + } + + h1, + .h1 { + font-size: calc(var(--unit) * 10); + line-height: calc(var(--unit) * 12); + } + h2, + .h2 { + font-size: calc(var(--unit) * 7); + line-height: calc(var(--unit) * 8); + } + h3, + .h3 { + font-size: calc(var(--unit) * 6); + line-height: calc(var(--unit) * 8); + } + h4, + .h4 { + font-size: calc(var(--unit) * 5); + line-height: calc(var(--unit) * 8); + } + h5, + .h5 { + font-size: calc(var(--unit) * 4); + line-height: calc(var(--unit) * 4); + } + h6, + .h6 { + font-size: calc(var(--unit) * 3.5); + line-height: calc(var(--unit) * 4); + } + + /* Paragraphs - visual styles */ + p { + margin: 0; + line-height: 1.6; + } + + /* Lists - visual styles */ + ul, + ol { + margin: 0; + padding-inline-start: calc(var(--unit) * 6); /* 24px */ + } + + li { + margin: 0; + line-height: 1.5; + } + li::marker { + color: oklch(from var(--foreground) calc(l + 0.05) c h); + } + + blockquote, + quote { + display: block; + margin: 0; + padding: calc(var(--unit) * 3) calc(var(--unit) * 4); + border-inline-start: calc(var(--unit) * 1) solid var(--primary); + border-radius: 0 calc(var(--radius) / 2) calc(var(--radius) / 2) 0; + background-color: oklch(from var(--primary) l c h / 0.06); + font-style: italic; + color: var(--muted-foreground); + } + + /* Inline elements - visual styles */ + strong, + b { + font-weight: 600; + color: oklch(from var(--foreground) calc(l + 0.05) c h); + } + em, + i { + font-style: italic; + } + small { + font-size: calc(var(--unit) * 3.5); + } /* 14px */ + mark { + background: oklch(from var(--primary) l c h / 0.1); + color: oklch(from var(--primary) calc(l + 0.2 * var(--theme-sign, 1)) c h); + padding: 0 calc(var(--unit) * 1.5); + border-radius: calc(var(--unit) * 0.5); + } + + /* --- Layout spacing (requires [typography] or .typography wrapper) --- */ + /* Uses wildcards for extensibility with custom elements */ + /* Order matters: later rules win when specificity is equal */ + + typography, + [typography], + .typography { + /* Fallback: direct siblings not explicitly covered */ + > * + * { + margin-top: calc(var(--unit) * 6); + } + + /* Nested lists - tighter */ + li > ul, + li > ol { + margin-top: calc(var(--unit) * 1); + } + + /* After headings - moderate space */ + h1 + *, + h2 + * { + margin-top: calc(var(--unit) * 3); + } + h3 + *, + h4 + *, + h5 + *, + h6 + * { + margin-top: calc(var(--unit) * 2); + } + + /* After paragraphs */ + p + * { + margin-top: calc(var(--unit) * 3); + } + + /* After lists */ + ul + *, + ol + * { + margin-top: calc(var(--unit) * 3); + } + + /* After blockquotes and pre */ + blockquote + *, + quote + *, + pre + *, + template + * { + margin-top: calc(var(--unit) * 4); + } + + /* Before headings - section break (last so they override above) */ + * + h1 { + margin-top: calc(var(--unit) * 8); + } + * + h2 { + margin-top: calc(var(--unit) * 7); + } + * + h3 { + margin-top: calc(var(--unit) * 6); + } + * + h4 { + margin-top: calc(var(--unit) * 5); + } + * + h5 { + margin-top: calc(var(--unit) * 4); + } + * + h6 { + margin-top: calc(var(--unit) * 4); + } + + /* HR spacing */ + hr + *, + * + hr { + margin-top: calc(var(--unit) * 6); + } + } +} +@layer elements { + @keyframes animate-spin { + to { + transform: rotate(360deg); + } + } + @keyframes animate-pulse { + 50% { + transform: scale(1.15); + } + } + @keyframes animate-ping { + 75%, + 100% { + transform: scale(2); + opacity: 0; + } + } + @keyframes animate-bounce { + 0%, + 100% { + transform: translateY(-25%); + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + } + 50% { + transform: translateY(0); + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + } + } + @keyframes animate-shake { + 10%, + 90% { + transform: translateX(-1px); + } + 20%, + 80% { + transform: translateX(2px); + } + 30%, + 50%, + 70% { + transform: translateX(-3px); + } + 40%, + 60% { + transform: translateX(3px); + } + } + @keyframes animate-shimmer { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } + } + @property --n { + syntax: ''; + inherits: true; + initial-value: 1; + } + @keyframes z-fade-scale { + 0% { + opacity: 0; + scale: 0.5; + } + + 50% { + opacity: 1; + scale: 1; + } + + 100% { + opacity: 0; + scale: 2; + } + } + @keyframes z-pointer { + 0%, + 100% { + pointer-events: none; + } + + 50% { + pointer-events: auto; + } + } + @keyframes grid-pan-y { + to { + background-position-y: + calc(var(--gy) - (var(--n) - 1) * round(nearest, 80cqh, var(--grid-size))), + calc(var(--gy) - (var(--n) - 1) * round(nearest, 80cqh, var(--grid-size))), + calc(var(--gy) - (var(--n) - 1) * round(nearest, 50cqh, calc(var(--grid-size) * 0.5))), + calc(var(--gy) - (var(--n) - 1) * round(nearest, 50cqh, calc(var(--grid-size) * 0.5))); + } + } + @keyframes grid-pan-x { + to { + background-position-x: + calc(var(--gx) - (var(--n) - 1) * round(nearest, 80cqw, var(--grid-size))), + calc(var(--gx) - (var(--n) - 1) * round(nearest, 80cqw, var(--grid-size))), + calc(var(--gx) - (var(--n) - 1) * round(nearest, 50cqw, calc(var(--grid-size) * 0.5))), + calc(var(--gx) - (var(--n) - 1) * round(nearest, 50cqw, calc(var(--grid-size) * 0.5))); + } + } + @keyframes grid-zoom-out { + 0% { + background-size: + var(--grid-size) var(--grid-size), + var(--grid-size) var(--grid-size), + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + opacity: 1; + background-position: + var(--gx) var(--gy), + var(--gx) var(--gy), + var(--gx) var(--gy), + var(--gx) var(--gy); + } + + 97% { + opacity: 0; + } + + 100% { + background-size: + calc(var(--grid-size) * 2) calc(var(--grid-size) * 2), + calc(var(--grid-size) * 2) calc(var(--grid-size) * 2), + var(--grid-size) var(--grid-size), + var(--grid-size) var(--grid-size); + opacity: 0; + background-position: + var(--zx) var(--zy), + var(--zx) var(--zy), + var(--zx-m) var(--zy-m), + var(--zx-m) var(--zy-m); + } + } + @keyframes grid-zoom-in { + 0% { + background-size: + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + calc(var(--grid-size) * 0.25) calc(var(--grid-size) * 0.25), + calc(var(--grid-size) * 0.25) calc(var(--grid-size) * 0.25); + opacity: 0; + background-position: + var(--gx) var(--gy), + var(--gx) var(--gy), + var(--gx) var(--gy), + var(--gx) var(--gy); + } + + 97% { + opacity: 1; + } + + 100% { + background-size: + var(--grid-size) var(--grid-size), + var(--grid-size) var(--grid-size), + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + opacity: 1; + background-position: + var(--zx) var(--zy), + var(--zx) var(--zy), + var(--zx-m) var(--zy-m), + var(--zx-m) var(--zy-m); + } + } + + .stylecheat, + [stylecheat] { + /* ---- A.css ---- */ + .a:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]), + a:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]) { + transition: all 100ms ease-in-out; + text-decoration: none; + + &.primary, + &[primary] { + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + + &:hover, + &:focus { + color: oklch(from var(--primary) calc(l - 0.1 * var(--theme-sign)) c h); + } + } + + &.secondary, + &[secondary] { + color: var(--secondary-foreground); + + &:hover, + &:focus { + color: oklch( + from var(--secondary-foreground) calc(l * (1 - 0.1 * var(--theme-sign))) c h + ); + } + } + + &.tertiary, + &[tertiary] { + /* Start - Button tertiary styles */ + display: flex; + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + padding: calc(var(--unit) * 2) calc(var(--unit) * 3); + line-height: calc(var(--unit) * 4); + outline-offset: 0; + > * { + margin-inline: calc(-1 * var(--unit)); + } + /* End - Button tertiary styles */ + + background-color: transparent; + color: var(--secondary-foreground); + box-shadow: none; + + &:hover { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + } + + &:focus-visible { + outline: 3px solid + oklch(from var(--primary) calc(l * (1 - 0.075 * var(--theme-sign))) c h); + } + } + + &:active { + transform: translateY(1px); + } + + &:focus-visible { + outline: 3px solid oklch(from var(--primary) calc(l/2 + 0.4) c h); + } + } + /* ---- Accordion.css ---- */ + .accordion, + accordion { + display: grid; + width: 100%; + grid-template-rows: 0fr; + transition: grid-template-rows 200ms ease-out; + } + + .accordion:is(.open), + accordion[open] { + grid-template-rows: 1fr; + } + + .accordion > .accordion-content, + accordion > accordion-content { + overflow: hidden; + } + /* ---- Animations.css ---- */ + .animate-spin, + [animate-spin] { + animation: animate-spin 1s linear infinite; + } + + .animate-pulse, + [animate-pulse] { + animation: animate-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + } + + .animate-ping, + [animate-ping] { + animation: animate-ping 1.2s cubic-bezier(0, 0, 0.2, 1) infinite; + } + + .animate-bounce, + [animate-bounce] { + animation: animate-bounce 1s infinite; + } + + .animate-shake, + [animate-shake] { + animation: animate-shake 0.8s cubic-bezier(0.36, 0.07, 0.19, 0.97) infinite; + } + + .animate-shimmer, + [animate-shimmer] { + background-color: transparent; + background-image: linear-gradient( + 90deg, + currentColor 0%, + oklch(from currentColor l c h / 0.3) 50%, + currentColor 100% + ); + background-size: 200% 100%; + animation: animate-shimmer 1.5s linear infinite; + } + + :is(.animate-fade-in, [animate-fade-in], .animate-fade-out, [animate-fade-out]) { + transition: opacity 200ms ease; + } + + :is(.animate-fade-in, [animate-fade-in]) { + opacity: 0; + } + + :is(.animate-fade-in, [animate-fade-in]):is(.toggled, [toggled]) { + opacity: 1; + } + + :is(.animate-fade-out, [animate-fade-out]):is(.toggled, [toggled]) { + opacity: 0; + } + + :is( + .animate-slide-in-left, + [animate-slide-in-left], + .animate-slide-in-right, + [animate-slide-in-right], + .animate-slide-in-up, + [animate-slide-in-up], + .animate-slide-in-down, + [animate-slide-in-down] + ) { + opacity: 0; + transition: + transform 250ms cubic-bezier(0.16, 1, 0.3, 1), + opacity 250ms cubic-bezier(0.16, 1, 0.3, 1); + } + :is(.animate-slide-in-left, [animate-slide-in-left]) { + transform: translateX(-100%); + } + :is(.animate-slide-in-right, [animate-slide-in-right]) { + transform: translateX(100%); + } + :is(.animate-slide-in-up, [animate-slide-in-up]) { + transform: translateY(-100%); + } + :is(.animate-slide-in-down, [animate-slide-in-down]) { + transform: translateY(100%); + } + + :is( + .animate-slide-in-left, + [animate-slide-in-left], + .animate-slide-in-right, + [animate-slide-in-right], + .animate-slide-in-up, + [animate-slide-in-up], + .animate-slide-in-down, + [animate-slide-in-down] + ):is(.toggled, [toggled]) { + transform: translate(0, 0); + opacity: 1; + } + + :is(.animate-bounce-in, [animate-bounce-in]) { + transform: scale(0); + opacity: 0; + transition: + transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1), + opacity 300ms cubic-bezier(0.34, 1.56, 0.64, 1); + } + :is(.animate-bounce-in, [animate-bounce-in]):is(.toggled, [toggled]) { + transform: scale(1); + opacity: 1; + } + + :is(.animate-bounce-out, [animate-bounce-out]) { + transition: + transform 250ms cubic-bezier(0.36, 0, 0.66, -0.56), + opacity 250ms cubic-bezier(0.36, 0, 0.66, -0.56); + } + :is(.animate-bounce-out, [animate-bounce-out]):is(.toggled, [toggled]) { + transform: scale(0); + opacity: 0; + } + + :is(.animate-x, [animate-x], .animate-y, [animate-y]) { + transition: transform 200ms ease; + } + + :is(.animate-x, [animate-x]):is(.toggled, [toggled]) { + transform: rotateY(180deg); + } + :is(.animate-y, [animate-y]):is(.toggled, [toggled]) { + transform: rotateX(180deg); + } + /* ---- Badge.css ---- */ + .badge, + badge { + display: inline-flex; + align-items: center; + justify-content: center; + gap: calc(var(--unit) * 1); + padding: calc(var(--unit) * 0.5) calc(var(--unit) * 2); + border-radius: 9999px; + font-family: var(--font-sans); + font-size: calc(var(--unit) * 3); + font-weight: 500; + white-space: nowrap; + width: fit-content; + overflow: hidden; + + background-color: var(--primary); + color: var(--primary-foreground); + } + + .badge.secondary, + .badge[secondary], + badge.secondary, + badge[secondary] { + background-color: var(--secondary); + color: var(--secondary-foreground); + } + + .badge.destructive, + .badge[destructive], + badge.destructive, + badge[destructive] { + background-color: var(--destructive); + color: white; + } + + .badge.outline, + .badge[outline], + badge.outline, + badge[outline] { + background-color: transparent; + color: var(--foreground); + box-shadow: inset 0 0 0 1px var(--border); + } + + .badge.ghost, + .badge[ghost], + badge.ghost, + badge[ghost] { + background-color: transparent; + color: var(--foreground); + } + /* ---- Breadcrumb.css ---- */ + .breadcrumb, + breadcrumb { + display: flex; + align-items: center; + gap: calc(var(--unit) * 1); + font-size: var(--unit-size, inherit); + color: var(--muted-foreground); + } + + .breadcrumb .current, + .breadcrumb [current], + breadcrumb .current, + breadcrumb [current] { + color: var(--foreground); + } + + .breadcrumb > * + *::before, + breadcrumb > * + *::before { + content: '/'; + margin-right: calc(var(--unit) * 1); + color: var(--muted-foreground); + } + /* ---- Button.css ---- */ + .button:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]), + button:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]) { + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + gap: calc(var(--unit) * 1); + font-size: var(--unit-size, inherit); + + background-color: transparent; + + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + padding: calc(var(--unit) * 2) calc(var(--unit) * 3); + line-height: 1em; + box-shadow: inset 0 0 0 1px transparent; + + cursor: pointer; + + > * { + margin-inline: calc(-1 * var(--unit)); + } + + &.primary, + &[primary] { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + box-shadow: inset 0 0 0 1px oklch(from var(--primary) l c h / 0.2); + + &:not(:disabled):hover { + background-color: oklch(from var(--primary) l c h / 0.2); + box-shadow: inset 0 0 0 1px oklch(from var(--primary) l c h / 0.3); + } + + &:focus-visible:not(:disabled) { + outline: 3px solid oklch(from var(--primary) l c h / 0.4); + } + } + + &.secondary, + &[secondary] { + background-color: var(--secondary); + color: var(--secondary-foreground); + box-shadow: inset 0 0 0 1px var(--border); + + &:not(:disabled):hover { + background-color: oklch( + from var(--secondary) calc(l * (1 - 0.035 * var(--theme-sign))) c h + ); + color: oklch( + from var(--secondary-foreground) calc(l * (1 - 0.035 * var(--theme-sign))) c h + ); + } + + &:focus-visible:not(:disabled) { + outline: 3px solid + oklch(from var(--secondary) calc(l * (1 - 0.075 * var(--theme-sign))) c h); + } + } + + &.tertiary, + &[tertiary] { + background-color: transparent; + color: var(--secondary-foreground); + box-shadow: none; + + &:not(:disabled):hover { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + box-shadow: none; + } + + &:focus-visible:not(:disabled) { + outline: 3px solid + oklch(from var(--secondary) calc(l * (1 - 0.075 * var(--theme-sign))) c h); + } + } + + &:not(:disabled):active { + transform: translateY(1px); + } + + &:disabled { + color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + } + } + /* ---- Card.css ---- */ + .card, + card { + display: flex; + flex-direction: column; + padding: calc(var(--unit) * 4); + box-shadow: inset 0 0 0 1px var(--border); + + background-color: var(--card); + color: var(--foreground); + font-size: var(--unit-size, inherit); + border-radius: calc(var(--radius) - (8px - var(--unit))); + } + /* ---- Carousel.css ---- */ + + slides > * { + --n: sibling-count(); + } + + carousel { + display: flex; + flex: 1; + container-type: size; + contain: paint; + width: 100%; + height: 100%; + } + + slides { + width: 100%; + height: 100%; + position: relative; + overflow-y: auto; + scrollbar-width: none; + } + + slides.scrollbar, + slides[scrollbar] { + scrollbar-width: auto; + } + + slides.x, + slides[x] { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + overflow-y: hidden; + overflow-x: scroll; + scroll-snap-type: x mandatory; + overscroll-behavior-x: none; + } + + slides.y, + slides[y], + slides.z, + slides[z] { + overflow-y: scroll; + overflow-x: hidden; + scroll-snap-type: y mandatory; + overscroll-behavior-y: none; + } + + slides.y, + slides[y], + slides.z, + slides[z] { + scroll-timeline: --slides-scroll block; + } + + slides.x, + slides[x] { + scroll-timeline: --slides-scroll-x inline; + } + + slides.x > *, + slides[x] > * { + height: 100%; + min-width: 100%; + scroll-snap-align: start; + scroll-snap-stop: always; + display: flex; + } + + slides.y > *, + slides[y] > * { + min-height: 100%; + width: 100%; + scroll-snap-align: start; + scroll-snap-stop: always; + display: flex; + } + + slides.z > *, + slides[z] > * { + min-height: 100%; + width: 100%; + scroll-snap-align: start; + } + + slide { + display: block; + } + + slides.x > * > *, + slides[x] > * > *, + slides.y > * > *, + slides[y] > * > * { + position: relative; + } + + slides.z > * > *, + slides[z] > * > * { + position: fixed; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + } + + slides.z > slide, + slides[z] > slide { + view-timeline: --slide-self block; + } + + slides.z > slide > *, + slides[z] > slide > * { + animation: z-fade-scale linear both; + animation-timeline: --slide-self; + } + + slides.z > slide > * > *, + slides[z] > slide > * > * { + pointer-events: none; + animation: z-pointer linear both; + animation-timeline: --slide-self; + } + + /* --- slides + square-grid: animated grid for y/x/z modes --- */ + + slides.square-grid.center, + slides.square-grid[center], + slides[square-grid].center, + slides[square-grid][center] { + --gx: 50cqw; + --gy: 50cqh; + } + + slides.square-grid:not(.locked):not([locked]).y:has(> :nth-child(2)), + slides.square-grid:not(.locked):not([locked])[y]:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked]).y:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked])[y]:has(> :nth-child(2)), + slides.square-grid:not(.locked):not([locked]).z:has(> :nth-child(2)), + slides.square-grid:not(.locked):not([locked])[z]:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked]).z:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked])[z]:has(> :nth-child(2)) { + background-image: none; + } + + slides.square-grid:not(.locked):not([locked]).y:has(> :nth-child(2)) > :first-child::before, + slides.square-grid:not(.locked):not([locked])[y]:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked]).y:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked])[y]:has(> :nth-child(2)) > :first-child::before { + content: ''; + position: fixed; + inset: 0; + pointer-events: none; + background: + linear-gradient(to right, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to right, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + animation: grid-pan-y linear both; + animation-timeline: --slides-scroll; + } + + slides.square-grid:not(.locked):not([locked]).x:has(> :nth-child(2)), + slides.square-grid:not(.locked):not([locked])[x]:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked]).x:has(> :nth-child(2)), + slides[square-grid]:not(.locked):not([locked])[x]:has(> :nth-child(2)) { + background-image: none; + } + + slides.square-grid:not(.locked):not([locked]).x:has(> :nth-child(2)) > :first-child::before, + slides.square-grid:not(.locked):not([locked])[x]:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked]).x:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked])[x]:has(> :nth-child(2)) > :first-child::before { + content: ''; + position: fixed; + inset: 0; + pointer-events: none; + background: + linear-gradient(to right, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to right, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + animation: grid-pan-x linear both; + animation-timeline: --slides-scroll-x; + } + + slides.square-grid:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::before, + slides.square-grid:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::after, + slides.square-grid:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::before, + slides.square-grid:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::after, + slides[square-grid]:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::after, + slides[square-grid]:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::after { + content: ''; + position: fixed; + inset: 0; + pointer-events: none; + --cx: calc(var(--gx) + round(nearest, 50cqw - var(--gx), var(--grid-size))); + --cy: calc(var(--gy) + round(nearest, 50cqh - var(--gy), var(--grid-size))); + --zx: calc(2 * var(--gx) - var(--cx)); + --zy: calc(2 * var(--gy) - var(--cy)); + --zx-m: calc(2 * var(--gx) - var(--cx)); + --zy-m: calc(2 * var(--gy) - var(--cy)); + background-position: var(--gx) var(--gy); + background-image: + linear-gradient(to right, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px), + linear-gradient(to right, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px); + animation-timeline: --slides-scroll; + animation-timing-function: linear; + animation-fill-mode: both; + animation-iteration-count: calc(var(--n) - 1); + } + + slides.square-grid:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::before, + slides.square-grid:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::before, + slides[square-grid]:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::before { + animation-name: grid-zoom-out; + } + + slides.square-grid:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::after, + slides.square-grid:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::after, + slides[square-grid]:not(.locked):not([locked]).z:has(> :nth-child(2)) > :first-child::after, + slides[square-grid]:not(.locked):not([locked])[z]:has(> :nth-child(2)) > :first-child::after { + animation-name: grid-zoom-in; + } + + /* ---- Checkbox.css ---- */ + .checkbox, + .switch, + input[type='checkbox'] { + appearance: none; + + background-color: var(--input); + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + + width: calc(var(--unit) * 6); + height: calc(var(--unit) * 6); + padding: calc(var(--unit) * 1); + + vertical-align: top; + + &:before { + content: ''; + display: block; + aspect-ratio: 1; + height: 100%; + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + background-color: oklch( + from var(--primary) calc(l + (1 - (var(--theme-sign) + 1) / 2)) + calc(c * (1 * (var(--theme-sign) + 1) / 2)) h + ); + transform: scale(0); + } + + &:checked:before { + transition: transform 100ms cubic-bezier(0.25, 0.1, 0.25, 1); + transform: scale(1); + } + } + /* ---- Circle.css ---- */ + circle, + .circle, + [circle] { + display: flex; + width: 100%; + aspect-ratio: 1; + border-radius: 100%; + } + /* ---- Code.css ---- */ + code { + font-family: var(--font-mono, monospace); + font-size: calc(var(--unit-size, 1em) * 0.85); + background: oklch(from var(--slate) l c h / 0.1); + color: var(--slate); + border: 1px solid oklch(from var(--slate) l c h / 0.2); + border-radius: calc(var(--unit) * 1); + padding: calc(var(--unit) * 0.5) calc(var(--unit) * 1.5); + } + + :where(.dark, [dark]) code { + background: oklch(0.3 0.03 260); + color: oklch(0.7 0.05 260); + border-color: oklch(0.35 0.03 260); + } + /* ---- Collective.css ---- */ + .input, + .checkbox, + .radio, + .select, + .textarea, + .button:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]), + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']), + input[type='file'], + input[type='checkbox'], + input[type='radio'], + select, + textarea, + button:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]) { + box-shadow: inset 0 0 0 1px var(--border); + + transition-property: box-shadow, background-color, color; + transition-duration: 100ms; + transition-timing-function: ease-in-out; + + &::placeholder { + font-weight: 400; + } + + &:disabled { + background-color: oklch(from var(--background) calc(l * (1 - 0.1 * var(--theme-sign))) c h); + color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + box-shadow: none; + cursor: not-allowed; + } + } + + .input, + .textarea, + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']), + textarea { + &:disabled { + /* This is needed for Input & Textarea, to actually respect the color in chrome */ + -webkit-text-fill-color: oklch( + from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h + ); + } + } + + .input, + .select, + textarea, + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']), + input[type='checkbox'], + input[type='radio'], + select, + textarea { + /* &:focus:enabled:not(:checked), */ + &:active:enabled:not(:checked), + &:focus-visible:enabled { + outline: 3px solid oklch(from var(--input) calc(l/2 + 0.4) c h); + outline-offset: 0; + } + } + /* ---- Container.css ---- */ + container, + .container, + [container] { + display: flex; + width: 100%; + max-width: 1280px; + margin-inline: auto; + } + /* ---- Crow.css ---- */ + crow:not(:has(> crow)) > crow, + .crow:not(:has(> .crow)) > .crow { + flex: 1; + } + + crow, + .crow { + display: flex; + align-items: center; + justify-content: center; + font-size: var(--unit-size, inherit); + } + .up, + [up], + .down, + [down] { + height: 100%; + } + .up, + [up] { + align-items: flex-start; + } + .down, + [down] { + align-items: flex-end; + } + .left, + [left] { + justify-content: flex-start; + } + .right, + [right] { + justify-content: flex-end; + } + .vertical, + [vertical] { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + .vertical > .up, + [vertical] > [up], + .vertical > .down, + [vertical] > [down] { + height: auto; + } + .vertical.up, + [vertical][up] { + justify-content: flex-start; + } + .vertical.down, + [vertical][down] { + justify-content: flex-end; + } + .crow.vertical.left, + crow[vertical][left], + .crow.vertical > .left, + crow[vertical] > [left], + .crow.vertical.right, + crow[vertical][right], + .crow.vertical > .right, + crow[vertical] > [right] { + width: 100%; + } + .vertical.left, + [vertical][left] { + align-items: flex-start; + } + .vertical.right, + [vertical][right] { + align-items: flex-end; + } + .vertical > .left, + [vertical] > [left], + .vertical > .right, + [vertical] > [right] { + display: flex; + } + /* ---- Hr.css ---- */ + hr, + .hr { + border: none; + width: 100%; + height: 1px; + background: linear-gradient(to right, transparent, var(--border), transparent); + } + /* ---- Label.css ---- */ + .label:has(input[type='checkbox'], input[type='radio']), + label:has(input[type='checkbox'], input[type='radio']) { + display: flex; + gap: calc(var(--unit) * 2); + font-size: var(--unit-size, inherit); + align-items: center; + } + + .label:has(select, input:not([type='checkbox'], [type='radio'], [type='range'], [type='file'])), + label:has(select, input:not([type='checkbox'], [type='radio'], [type='range'], [type='file'])) { + display: grid; + } + + .label > .select, + .label > .input, + label > select, + label > input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']) { + grid-area: 1/1; + padding-inline-end: calc(var(--unit) * 8); /* 32px */ + } + + .label:has(:disabled), + label:has(:disabled) { + color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + cursor: not-allowed; + } + + .label:has( + .select, + .input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']) + ):after, + label:has( + select, + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']) + ):after { + content: ''; + pointer-events: none; + grid-area: 1/1; + mask-position: calc(100% - calc(var(--unit) * 2)) center; + mask-size: calc(var(--unit) * 3.5) auto; + mask-repeat: no-repeat; + background-color: var(--popover-foreground); + } + + .label:has( + .input:not( + [type='checkbox'], + [type='radio'], + [type='range'], + [type='file'] + ):placeholder-shown + ):after, + label:has( + input:not( + [type='checkbox'], + [type='radio'], + [type='range'], + [type='file'] + ):placeholder-shown + ):after { + background-color: oklch(from var(--background) calc(l/2 + 0.3 - 0.1 * var(--theme-sign)) c h); + } + + .label:has( + .select:disabled, + .input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']):disabled + ):after, + label:has( + select:disabled, + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']):disabled + ):after { + background-color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + } + + .label:has(.select):after, + label:has(select):after { + mask-image: var(--icon, var(--icon-chevron-down)); + } + + .label:has(.input:not([type='checkbox'], [type='radio'], [type='range'], [type='file'])):after, + label:has(input:not([type='checkbox'], [type='radio'], [type='range'], [type='file'])):after { + transition: background-color 150ms ease-in-out; + mask-image: var(--icon, var(--icon-search)); + } + /* ---- Progress.css ---- */ + .progress, + progress { + appearance: none; + display: flex; + min-width: calc(var(--unit) * 59); + height: calc(var(--unit) * 1.5); + border: 0; + + background-color: var(--input); + border-radius: calc(var(--unit) * 3); + box-shadow: inset 0 0 0 1px var(--border); + + &::-webkit-progress-bar { + background-color: transparent; + border-radius: calc(var(--unit) * 3); + } + + &::-webkit-progress-value { + background-color: oklch( + from var(--primary) calc(l + (1 - (var(--theme-sign) + 1) / 2)) + calc(c * (1 * (var(--theme-sign) + 1) / 2)) h + ); + border-radius: calc(var(--unit) * 3); + box-shadow: 0 0 0 1px var(--border); + } + } + /* ---- Radio.css ---- */ + .radio, + input[type='radio'] { + appearance: none; + + background-color: var(--input); + border-radius: 50%; + + width: calc(var(--unit) * 6); + height: calc(var(--unit) * 6); /* aspect-ratio: 1; doesn't seem to work for safari iphone */ + padding: calc(var(--unit) * 1); + + vertical-align: top; + + &:before { + content: ''; + display: block; + aspect-ratio: 1; + height: 100%; + border-radius: 50%; + background-color: oklch( + from var(--primary) calc(l + (1 - (var(--theme-sign) + 1) / 2)) + calc(c * (1 * (var(--theme-sign) + 1) / 2)) h + ); + transform: scale(0); + } + + &:checked:before { + transition: transform 100ms cubic-bezier(0.25, 0.1, 0.25, 1); + transform: scale(1); + } + } + /* ---- Range.css ---- */ + .range, + input[type='range'] { + display: flex; + appearance: none; + min-width: calc(var(--unit) * 59); + outline: 0; + + background-color: var(--input); + border-radius: calc(var(--unit) * 3); + height: calc(var(--unit) * 1.5); + box-shadow: inset 0 0 0 1px var(--border); + + &::-webkit-slider-thumb { + appearance: none; + outline: 0px inset transparent; + outline-offset: 0; + transition: outline 50ms ease-in-out; + transition: outline 50ms ease-in-out; + + width: calc(var(--unit) * 6); + aspect-ratio: 1; + background-color: oklch( + from var(--primary) calc(l + (1 - (var(--theme-sign) + 1) / 2)) + calc(c * (1 * (var(--theme-sign) + 1) / 2)) h + ); + border-radius: 50%; + + border: calc(var(--unit) * 1) solid var(--input); + outline: 1px solid var(--border); + } + + &:disabled { + cursor: not-allowed; + + &::-webkit-slider-thumb { + border-color: oklch(from var(--background) calc(l * (1 - 0.1 * var(--theme-sign))) c h); + background-color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + outline-color: transparent; + } + } + + &:focus:enabled:not(:active) { + outline: 0; + + &::-webkit-slider-thumb { + outline: 3px solid oklch(from var(--input) calc(l/2 + 0.4) c h); + } + } + } + /* ---- Select.css ---- */ + .select, + select { + min-width: calc(var(--unit) * 59); + appearance: none; + + background-color: var(--input); + color: var(--popover-foreground); + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + font-size: var(--unit-size, inherit); + + padding: calc(var(--unit) * 1.5) calc(var(--unit) * 2); + + &:invalid { + color: oklch(from var(--background) calc(l/2 + 0.3 - 0.1 * var(--theme-sign)) c h); + } + } + /* ---- Sidebar.css ---- */ + sidebar { + position: sticky; + top: 0; + flex-shrink: 0; + display: flex; + flex-direction: column; + order: -1; + } + + sidebar-content { + width: calc(var(--unit) * 56); + display: flex; + flex-direction: column; + flex: 1; + padding: calc(var(--unit) * 4); + justify-content: space-between; + } + + input#sidebar-toggle { + position: absolute; + opacity: 0; + } + + @media (width <= 768px) { + sidebar { + position: fixed; + inset: 0; + height: 100%; + width: 100%; + pointer-events: none; + } + + sidebar:has(input#sidebar-toggle:checked) input#sidebar-toggle { + inset: 0; + width: 100%; + height: 100%; + } + + sidebar:has(input#sidebar-toggle:checked) { + pointer-events: auto; + transform: translateX(0); + background: oklch(from black l c h / 0.5); + transition: background-color 300ms ease; + } + + sidebar-content { + background-color: var(--sidebar); + border-right: 1px solid var(--sidebar-border); + color: var(--sidebar-foreground); + transform: translateX(-100%); + transition: transform 300ms ease; + pointer-events: auto; + } + + sidebar:has(input#sidebar-toggle:checked) sidebar-content { + transform: translateX(0); + } + } + /* ---- SquareGrid.css ---- */ + .square-grid, + square-grid { + --grid-size: calc(var(--grid-unit, var(--unit)) * 12); + --gx: 0px; + --gy: 0px; + /* background-attachment: fixed; */ + } + + .square-grid.center, + .square-grid[center], + square-grid.center, + square-grid[center] { + --gx: calc(50% - var(--grid-size) / 2); + --gy: calc(50% - var(--grid-size) / 2); + } + + .square-grid.locked, + .square-grid[locked], + square-grid.locked, + square-grid[locked] { + background: + linear-gradient(to right, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to right, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + background-attachment: fixed; + } + + .square-grid:not(.locked):not([locked]), + square-grid:not(.locked):not([locked]) { + background: + linear-gradient(to right, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.22) 0 1px, transparent 1px) var(--gx) + var(--gy) / var(--grid-size) var(--grid-size), + linear-gradient(to right, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5), + linear-gradient(to bottom, oklch(0.55 0.02 260 / 0.08) 0 1px, transparent 1px) var(--gx) + var(--gy) / calc(var(--grid-size) * 0.5) calc(var(--grid-size) * 0.5); + } + /* ---- Stack.css ---- */ + stack { + display: grid; + place-items: center; + } + + stack > * { + grid-area: 1/1; + } + /* ---- Sticky.css ---- */ + .sticky, + sticky { + display: flex; + position: sticky; + flex-direction: column; + top: 0; + order: -1; + container-type: scroll-state; + } + + .sticky.auto-shadow::after, + .sticky[auto-shadow]::after, + sticky.auto-shadow::after, + sticky[auto-shadow]::after { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; + transition: box-shadow 150ms; + } + + @container scroll-state(stuck: top) { + .sticky.auto-shadow::after, + .sticky[auto-shadow]::after, + sticky.auto-shadow::after, + sticky[auto-shadow]::after { + box-shadow: + inset 0 1px 0 oklch(from var(--background) calc(l + 0.04) c h), + inset 0 -1px 0 oklch(from var(--shadow-color) l c h / 0.2), + 0 calc(var(--unit) * 0.5) calc(var(--unit) * 1.5) calc(var(--unit) * -0.5) + oklch(from var(--shadow-color) l c h / 0.45); + } + } + + @container scroll-state(stuck: bottom) { + .sticky.auto-shadow::after, + .sticky[auto-shadow]::after, + sticky.auto-shadow::after, + sticky[auto-shadow]::after { + box-shadow: + inset 0 -1px 0 oklch(from var(--background) calc(l + 0.04) c h), + inset 0 1px 0 oklch(from var(--shadow-color) l c h / 0.2), + 0 calc(var(--unit) * -0.5) calc(var(--unit) * 1.5) calc(var(--unit) * -0.5) + oklch(from var(--shadow-color) l c h / 0.45); + } + } + + .sticky.reverse, + .sticky[reverse], + sticky.reverse, + sticky[reverse] { + order: 0; + top: auto; + bottom: 0; + } + + @media (width <= 768px) { + .sticky.sm\:reverse, + .sticky[sm\:reverse], + sticky.sm\:reverse, + sticky[sm\:reverse] { + order: 0; + top: auto; + bottom: 0; + } + } + + @media (768px < width <= 1024px) { + .sticky.md\:reverse, + .sticky[md\:reverse], + sticky.md\:reverse, + sticky[md\:reverse] { + order: 0; + top: auto; + bottom: 0; + } + } + + @media (width > 1024px) { + .sticky.lg\:reverse, + .sticky[lg\:reverse], + sticky.lg\:reverse, + sticky[lg\:reverse] { + order: 0; + top: auto; + bottom: 0; + } + } + /* ---- Switch.css ---- */ + .switch, + input[type='checkbox'][role='switch'] { + width: calc(var(--unit) * 12); + + background-color: var(--input); + border-radius: calc(var(--unit) * 3); + + &:before { + transition: all 150ms ease-in-out; + content: ''; + color: var(--primary-foreground); + border-radius: calc(var(--unit) * 2.5); + transform: scale(1); + } + + &:disabled:before { + background-color: oklch(from var(--popover) calc(l * (1 - 0.5 * var(--theme-sign))) c h); + } + + &:checked { + background-color: var(--primary); + box-shadow: inset 0 0 0 1px + oklch(from var(--primary) calc(l * (1 + 0.075 * var(--theme-sign))) c h); + + &:active:enabled, + &:focus-visible:enabled { + outline-color: oklch(from var(--primary) calc(l * (1 + 0.075 * var(--theme-sign))) c h); + } + + &:before { + background-color: var(--primary-foreground); + } + } + + &:checked:before { + margin-inline-start: calc(var(--unit) * 6); + } + + &:active:enabled, + &:focus-visible:enabled { + outline: 3px solid oklch(from var(--input) calc(l/2 + 0.4) c h); + outline-offset: 0; + } + } + /* ---- Table.css ---- */ + .table, + table { + width: 100%; + border-collapse: collapse; + color: var(--foreground); + font-size: var(--unit-size, inherit); + font-family: var(--font-sans); + } + + .table td, + table td { + padding: calc(var(--unit) * 3) calc(var(--unit) * 4); + text-align: left; + vertical-align: middle; + border-bottom: 1px solid var(--border); + } + + .table tr:first-child td, + table tr:first-child td { + font-size: calc(var(--unit) * 3); + font-weight: 500; + letter-spacing: 0.06em; + text-transform: uppercase; + } + + .table tr:not(:first-child) td, + table tr:not(:first-child) td { + color: var(--muted-foreground); + } + + .table tr:last-child td, + table tr:last-child td { + border-bottom: none; + } + + .table tr:not(:first-child):hover td, + table tr:not(:first-child):hover td { + background-color: oklch(from var(--foreground) l c h / 0.04); + } + /* ---- Tabs.css ---- */ + .tabs:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]), + tabs:is(.primary, .secondary, .tertiary, [primary], [secondary], [tertiary]) { + display: flex; + align-items: flex-end; + gap: calc(var(--unit) * 1); + border-bottom: 1px solid var(--border); + + > .tab, + > tab { + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + gap: calc(var(--unit) * 1); + font-size: var(--unit-size, inherit); + line-height: 1em; + padding: calc(var(--unit) * 2) calc(var(--unit) * 3); + border: 1px solid transparent; + border-bottom: 0; + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)) + min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)) 0 0; + background-color: transparent; + color: var(--foreground); + cursor: pointer; + + > * { + margin-inline: calc(-1 * var(--unit)); + } + } + + &.primary > .tab:not(.active, [active]), + &[primary] > tab:not(.active, [active]) { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + border-color: oklch(from var(--primary) l c h / 0.2); + + &:hover { + background-color: oklch(from var(--primary) l c h / 0.2); + border-color: oklch(from var(--primary) l c h / 0.3); + } + } + + &.primary > .tab:is(.active, [active]), + &[primary] > tab:is(.active, [active]) { + border-color: oklch(from var(--primary) l c h / 0.2); + box-shadow: 0 1px 0 0 var(--tab-surface, var(--background)); + } + + &.secondary > .tab:not(.active, [active]), + &[secondary] > tab:not(.active, [active]) { + background-color: var(--secondary); + color: var(--secondary-foreground); + border-color: var(--border); + + &:hover { + background-color: oklch( + from var(--secondary) calc(l * (1 - 0.035 * var(--theme-sign))) c h + ); + } + } + + &.secondary > .tab:is(.active, [active]), + &[secondary] > tab:is(.active, [active]) { + border-color: var(--border); + box-shadow: 0 1px 0 0 var(--tab-surface, var(--background)); + } + + &.tertiary > .tab:not(.active, [active]), + &[tertiary] > tab:not(.active, [active]) { + color: var(--secondary-foreground); + + &:hover { + background-color: oklch(from var(--primary) l c h / 0.12); + color: oklch(from var(--primary) calc(l - 0.2 * var(--theme-sign)) c h); + } + } + + &.tertiary > .tab:is(.active, [active]), + &[tertiary] > tab:is(.active, [active]) { + border-color: var(--border); + box-shadow: 0 1px 0 0 var(--tab-surface, var(--background)); + } + } + /* ---- TextArea.css ---- */ + .textarea, + textarea { + min-width: calc(var(--unit) * 59); + + background-color: var(--input); + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + color: oklch(calc((1 - var(--theme-sign)) * 0.5) 0 0); + padding: calc(var(--unit) * 1.5) calc(var(--unit) * 2); + font-size: var(--unit-size, inherit); + + &:not(:disabled)::placeholder { + color: oklch(from var(--background) calc(l/2 + 0.3 - 0.1 * var(--theme-sign)) c h); + } + } + /* ---- TextInput.css ---- */ + .input, + input:not([type='checkbox'], [type='radio'], [type='range'], [type='file']) { + min-width: calc(var(--unit) * 59); + + background-color: var(--input); + border-radius: min(calc(var(--radius) - calc(var(--unit) * 1)), calc(var(--unit) * 1)); + color: var(--popover-foreground); + padding: calc(var(--unit) * 1.5) calc(var(--unit) * 2); + font-size: var(--unit-size, inherit); + + &:not(:disabled)::placeholder { + color: oklch(from var(--background) calc(l/2 + 0.3 - 0.1 * var(--theme-sign)) c h); + } + } + } +} +@layer modifiers { + .stylecheat, + [stylecheat] { + /* ---- Modifiers.css ---- */ + .sm, + [sm] { + --unit: 3px; + --unit-size: 12px; + font-size: var(--unit-size, inherit); + } + .md, + [md] { + --unit: 4px; + --unit-size: 16px; + font-size: var(--unit-size, inherit); + } + .lg, + [lg] { + --unit: 5px; + --unit-size: 18px; + font-size: var(--unit-size, inherit); + } + + .overflow-hidden, + [overflow-hidden] { + overflow: hidden; + } + .hide, + [hide] { + display: none; + } + .flex, + [flex] { + display: flex; + } + .block, + [block] { + display: block; + } + .inline-block, + [inline-block] { + display: inline-block; + } + + .f-0, + [f-0] { + flex: none; + } + .f-1, + [f-1] { + flex: 1; + } + .f-2, + [f-2] { + flex: 2; + } + .f-3, + [f-3] { + flex: 3; + } + .f-4, + [f-4] { + flex: 4; + } + .f-5, + [f-5] { + flex: 5; + } + .f-6, + [f-6] { + flex: 6; + } + .f-7, + [f-7] { + flex: 7; + } + .f-8, + [f-8] { + flex: 8; + } + + .justify-between, + [justify-between] { + justify-content: space-between; + } + + .w-full, + [w-full] { + width: 100%; + } + .h-full, + [h-full] { + height: 100%; + } + .mw-full, + [mw-full] { + min-width: 100%; + } + .mh-full, + [mh-full] { + min-height: 100%; + } + + /* Gap utilities */ + .g-0, + [g-0] { + gap: 0; + } + .g-1, + [g-1] { + gap: calc(var(--unit) * 1); + } + .g-2, + [g-2] { + gap: calc(var(--unit) * 2); + } + .g-3, + [g-3] { + gap: calc(var(--unit) * 3); + } + .g-4, + [g-4] { + gap: calc(var(--unit) * 4); + } + .g-5, + [g-5] { + gap: calc(var(--unit) * 5); + } + .g-6, + [g-6] { + gap: calc(var(--unit) * 6); + } + .g-7, + [g-7] { + gap: calc(var(--unit) * 7); + } + .g-8, + [g-8] { + gap: calc(var(--unit) * 8); + } + + /* Margin utilities */ + .mt-auto, + [mt-auto] { + margin-top: auto; + } + .mt-0, + [mt-0] { + margin-top: 0; + } + .mt-1, + [mt-1] { + margin-top: calc(var(--unit) * 1); + } + .mt-2, + [mt-2] { + margin-top: calc(var(--unit) * 2); + } + .mt-3, + [mt-3] { + margin-top: calc(var(--unit) * 3); + } + .mt-4, + [mt-4] { + margin-top: calc(var(--unit) * 4); + } + .mt-5, + [mt-5] { + margin-top: calc(var(--unit) * 5); + } + .mt-6, + [mt-6] { + margin-top: calc(var(--unit) * 6); + } + .mt-7, + [mt-7] { + margin-top: calc(var(--unit) * 7); + } + .mt-8, + [mt-8] { + margin-top: calc(var(--unit) * 8); + } + + .mb-auto, + [mb-auto] { + margin-bottom: auto; + } + .mb-0, + [mb-0] { + margin-bottom: 0; + } + .mb-1, + [mb-1] { + margin-bottom: calc(var(--unit) * 1); + } + .mb-2, + [mb-2] { + margin-bottom: calc(var(--unit) * 2); + } + .mb-3, + [mb-3] { + margin-bottom: calc(var(--unit) * 3); + } + .mb-4, + [mb-4] { + margin-bottom: calc(var(--unit) * 4); + } + .mb-5, + [mb-5] { + margin-bottom: calc(var(--unit) * 5); + } + .mb-6, + [mb-6] { + margin-bottom: calc(var(--unit) * 6); + } + .mb-7, + [mb-7] { + margin-bottom: calc(var(--unit) * 7); + } + .mb-8, + [mb-8] { + margin-bottom: calc(var(--unit) * 8); + } + + .ml-auto, + [ml-auto] { + margin-left: auto; + } + .ml-0, + [ml-0] { + margin-left: 0; + } + .ml-1, + [ml-1] { + margin-left: calc(var(--unit) * 1); + } + .ml-2, + [ml-2] { + margin-left: calc(var(--unit) * 2); + } + .ml-3, + [ml-3] { + margin-left: calc(var(--unit) * 3); + } + .ml-4, + [ml-4] { + margin-left: calc(var(--unit) * 4); + } + .ml-5, + [ml-5] { + margin-left: calc(var(--unit) * 5); + } + .ml-6, + [ml-6] { + margin-left: calc(var(--unit) * 6); + } + .ml-7, + [ml-7] { + margin-left: calc(var(--unit) * 7); + } + .ml-8, + [ml-8] { + margin-left: calc(var(--unit) * 8); + } + + .mr-auto, + [mr-auto] { + margin-right: auto; + } + .mr-0, + [mr-0] { + margin-right: 0; + } + .mr-1, + [mr-1] { + margin-right: calc(var(--unit) * 1); + } + .mr-2, + [mr-2] { + margin-right: calc(var(--unit) * 2); + } + .mr-3, + [mr-3] { + margin-right: calc(var(--unit) * 3); + } + .mr-4, + [mr-4] { + margin-right: calc(var(--unit) * 4); + } + .mr-5, + [mr-5] { + margin-right: calc(var(--unit) * 5); + } + .mr-6, + [mr-6] { + margin-right: calc(var(--unit) * 6); + } + .mr-7, + [mr-7] { + margin-right: calc(var(--unit) * 7); + } + .mr-8, + [mr-8] { + margin-right: calc(var(--unit) * 8); + } + + .mx-auto, + [mx-auto] { + margin-inline: auto; + } + .mx-0, + [mx-0] { + margin-inline: 0; + } + .mx-1, + [mx-1] { + margin-inline: calc(var(--unit) * 1); + } + .mx-2, + [mx-2] { + margin-inline: calc(var(--unit) * 2); + } + .mx-3, + [mx-3] { + margin-inline: calc(var(--unit) * 3); + } + .mx-4, + [mx-4] { + margin-inline: calc(var(--unit) * 4); + } + .mx-5, + [mx-5] { + margin-inline: calc(var(--unit) * 5); + } + .mx-6, + [mx-6] { + margin-inline: calc(var(--unit) * 6); + } + .mx-7, + [mx-7] { + margin-inline: calc(var(--unit) * 7); + } + .mx-8, + [mx-8] { + margin-inline: calc(var(--unit) * 8); + } + + .my-auto, + [my-auto] { + margin-block: auto; + } + .my-0, + [my-0] { + margin-block: 0; + } + .my-1, + [my-1] { + margin-block: calc(var(--unit) * 1); + } + .my-2, + [my-2] { + margin-block: calc(var(--unit) * 2); + } + .my-3, + [my-3] { + margin-block: calc(var(--unit) * 3); + } + .my-4, + [my-4] { + margin-block: calc(var(--unit) * 4); + } + .my-5, + [my-5] { + margin-block: calc(var(--unit) * 5); + } + .my-6, + [my-6] { + margin-block: calc(var(--unit) * 6); + } + .my-7, + [my-7] { + margin-block: calc(var(--unit) * 7); + } + .my-8, + [my-8] { + margin-block: calc(var(--unit) * 8); + } + + .m-auto, + [m-auto] { + margin: auto; + } + .m-0, + [m-0] { + margin: 0; + } + .m-1, + [m-1] { + margin: calc(var(--unit) * 1); + } + .m-2, + [m-2] { + margin: calc(var(--unit) * 2); + } + .m-3, + [m-3] { + margin: calc(var(--unit) * 3); + } + .m-4, + [m-4] { + margin: calc(var(--unit) * 4); + } + .m-5, + [m-5] { + margin: calc(var(--unit) * 5); + } + .m-6, + [m-6] { + margin: calc(var(--unit) * 6); + } + .m-7, + [m-7] { + margin: calc(var(--unit) * 7); + } + .m-8, + [m-8] { + margin: calc(var(--unit) * 8); + } + + /* Padding utilities */ + .pt-0, + [pt-0] { + padding-top: 0; + } + .pt-1, + [pt-1] { + padding-top: calc(var(--unit) * 1); + } + .pt-2, + [pt-2] { + padding-top: calc(var(--unit) * 2); + } + .pt-3, + [pt-3] { + padding-top: calc(var(--unit) * 3); + } + .pt-4, + [pt-4] { + padding-top: calc(var(--unit) * 4); + } + .pt-5, + [pt-5] { + padding-top: calc(var(--unit) * 5); + } + .pt-6, + [pt-6] { + padding-top: calc(var(--unit) * 6); + } + .pt-7, + [pt-7] { + padding-top: calc(var(--unit) * 7); + } + .pt-8, + [pt-8] { + padding-top: calc(var(--unit) * 8); + } + + .pb-0, + [pb-0] { + padding-bottom: 0; + } + .pb-1, + [pb-1] { + padding-bottom: calc(var(--unit) * 1); + } + .pb-2, + [pb-2] { + padding-bottom: calc(var(--unit) * 2); + } + .pb-3, + [pb-3] { + padding-bottom: calc(var(--unit) * 3); + } + .pb-4, + [pb-4] { + padding-bottom: calc(var(--unit) * 4); + } + .pb-5, + [pb-5] { + padding-bottom: calc(var(--unit) * 5); + } + .pb-6, + [pb-6] { + padding-bottom: calc(var(--unit) * 6); + } + .pb-7, + [pb-7] { + padding-bottom: calc(var(--unit) * 7); + } + .pb-8, + [pb-8] { + padding-bottom: calc(var(--unit) * 8); + } + + .pl-0, + [pl-0] { + padding-left: 0; + } + .pl-1, + [pl-1] { + padding-left: calc(var(--unit) * 1); + } + .pl-2, + [pl-2] { + padding-left: calc(var(--unit) * 2); + } + .pl-3, + [pl-3] { + padding-left: calc(var(--unit) * 3); + } + .pl-4, + [pl-4] { + padding-left: calc(var(--unit) * 4); + } + .pl-5, + [pl-5] { + padding-left: calc(var(--unit) * 5); + } + .pl-6, + [pl-6] { + padding-left: calc(var(--unit) * 6); + } + .pl-7, + [pl-7] { + padding-left: calc(var(--unit) * 7); + } + .pl-8, + [pl-8] { + padding-left: calc(var(--unit) * 8); + } + + .pr-0, + [pr-0] { + padding-right: 0; + } + .pr-1, + [pr-1] { + padding-right: calc(var(--unit) * 1); + } + .pr-2, + [pr-2] { + padding-right: calc(var(--unit) * 2); + } + .pr-3, + [pr-3] { + padding-right: calc(var(--unit) * 3); + } + .pr-4, + [pr-4] { + padding-right: calc(var(--unit) * 4); + } + .pr-5, + [pr-5] { + padding-right: calc(var(--unit) * 5); + } + .pr-6, + [pr-6] { + padding-right: calc(var(--unit) * 6); + } + .pr-7, + [pr-7] { + padding-right: calc(var(--unit) * 7); + } + .pr-8, + [pr-8] { + padding-right: calc(var(--unit) * 8); + } + + .px-0, + [px-0] { + padding-inline: 0; + } + .px-1, + [px-1] { + padding-inline: calc(var(--unit) * 1); + } + .px-2, + [px-2] { + padding-inline: calc(var(--unit) * 2); + } + .px-3, + [px-3] { + padding-inline: calc(var(--unit) * 3); + } + .px-4, + [px-4] { + padding-inline: calc(var(--unit) * 4); + } + .px-5, + [px-5] { + padding-inline: calc(var(--unit) * 5); + } + .px-6, + [px-6] { + padding-inline: calc(var(--unit) * 6); + } + .px-7, + [px-7] { + padding-inline: calc(var(--unit) * 7); + } + .px-8, + [px-8] { + padding-inline: calc(var(--unit) * 8); + } + + .py-0, + [py-0] { + padding-block: 0; + } + .py-1, + [py-1] { + padding-block: calc(var(--unit) * 1); + } + .py-2, + [py-2] { + padding-block: calc(var(--unit) * 2); + } + .py-3, + [py-3] { + padding-block: calc(var(--unit) * 3); + } + .py-4, + [py-4] { + padding-block: calc(var(--unit) * 4); + } + .py-5, + [py-5] { + padding-block: calc(var(--unit) * 5); + } + .py-6, + [py-6] { + padding-block: calc(var(--unit) * 6); + } + .py-7, + [py-7] { + padding-block: calc(var(--unit) * 7); + } + .py-8, + [py-8] { + padding-block: calc(var(--unit) * 8); + } + + .p-0, + [p-0] { + padding: 0; + } + .p-1, + [p-1] { + padding: calc(var(--unit) * 1); + } + .p-2, + [p-2] { + padding: calc(var(--unit) * 2); + } + .p-3, + [p-3] { + padding: calc(var(--unit) * 3); + } + .p-4, + [p-4] { + padding: calc(var(--unit) * 4); + } + .p-5, + [p-5] { + padding: calc(var(--unit) * 5); + } + .p-6, + [p-6] { + padding: calc(var(--unit) * 6); + } + .p-7, + [p-7] { + padding: calc(var(--unit) * 7); + } + .p-8, + [p-8] { + padding: calc(var(--unit) * 8); + } + + /* Position utilities */ + [position='static'] { + position: static; + } + [position='relative'] { + position: relative; + } + [position='absolute'] { + position: absolute; + } + [position='fixed'] { + position: fixed; + } + [position='sticky'] { + position: sticky; + } + + /* Contain utilities */ + [contain='none'] { + contain: none; + } + [contain='strict'] { + contain: strict; + } + [contain='content'] { + contain: content; + } + [contain='size'] { + contain: size; + } + [contain='inline-size'] { + contain: inline-size; + } + [contain='layout'] { + contain: layout; + } + [contain='style'] { + contain: style; + } + [contain='paint'] { + contain: paint; + } + + /* Inset utilities (top, right, bottom, left) */ + .t-auto, + [t-auto] { + top: auto; + } + .t-0, + [t-0] { + top: 0; + } + .t-1, + [t-1] { + top: calc(var(--unit) * 1); + } + .t-2, + [t-2] { + top: calc(var(--unit) * 2); + } + .t-3, + [t-3] { + top: calc(var(--unit) * 3); + } + .t-4, + [t-4] { + top: calc(var(--unit) * 4); + } + .t-5, + [t-5] { + top: calc(var(--unit) * 5); + } + .t-6, + [t-6] { + top: calc(var(--unit) * 6); + } + .t-7, + [t-7] { + top: calc(var(--unit) * 7); + } + .t-8, + [t-8] { + top: calc(var(--unit) * 8); + } + + .r-auto, + [r-auto] { + right: auto; + } + .r-0, + [r-0] { + right: 0; + } + .r-1, + [r-1] { + right: calc(var(--unit) * 1); + } + .r-2, + [r-2] { + right: calc(var(--unit) * 2); + } + .r-3, + [r-3] { + right: calc(var(--unit) * 3); + } + .r-4, + [r-4] { + right: calc(var(--unit) * 4); + } + .r-5, + [r-5] { + right: calc(var(--unit) * 5); + } + .r-6, + [r-6] { + right: calc(var(--unit) * 6); + } + .r-7, + [r-7] { + right: calc(var(--unit) * 7); + } + .r-8, + [r-8] { + right: calc(var(--unit) * 8); + } + + .b-auto, + [b-auto] { + bottom: auto; + } + .b-0, + [b-0] { + bottom: 0; + } + .b-1, + [b-1] { + bottom: calc(var(--unit) * 1); + } + .b-2, + [b-2] { + bottom: calc(var(--unit) * 2); + } + .b-3, + [b-3] { + bottom: calc(var(--unit) * 3); + } + .b-4, + [b-4] { + bottom: calc(var(--unit) * 4); + } + .b-5, + [b-5] { + bottom: calc(var(--unit) * 5); + } + .b-6, + [b-6] { + bottom: calc(var(--unit) * 6); + } + .b-7, + [b-7] { + bottom: calc(var(--unit) * 7); + } + .b-8, + [b-8] { + bottom: calc(var(--unit) * 8); + } + + .l-auto, + [l-auto] { + left: auto; + } + .l-0, + [l-0] { + left: 0; + } + .l-1, + [l-1] { + left: calc(var(--unit) * 1); + } + .l-2, + [l-2] { + left: calc(var(--unit) * 2); + } + .l-3, + [l-3] { + left: calc(var(--unit) * 3); + } + .l-4, + [l-4] { + left: calc(var(--unit) * 4); + } + .l-5, + [l-5] { + left: calc(var(--unit) * 5); + } + .l-6, + [l-6] { + left: calc(var(--unit) * 6); + } + .l-7, + [l-7] { + left: calc(var(--unit) * 7); + } + .l-8, + [l-8] { + left: calc(var(--unit) * 8); + } + + /* Order */ + .order-first, + [order-first] { + order: -1; + } + + .text-blue, + [text-blue] { + color: var(--blue); + } + .text-purple, + [text-purple] { + color: var(--purple); + } + .text-green, + [text-green] { + color: var(--green); + } + .text-orange, + [text-orange] { + color: var(--orange); + } + .text-cyan, + [text-cyan] { + color: var(--cyan); + } + .text-red, + [text-red] { + color: var(--red); + } + .text-yellow, + [text-yellow] { + color: var(--yellow); + } + .text-slate, + [text-slate] { + color: var(--slate); + } + + .bg-blue, + [bg-blue] { + background-color: oklch(from var(--blue) l c h / 0.2); + } + .bg-purple, + [bg-purple] { + background-color: oklch(from var(--purple) l c h / 0.2); + } + .bg-green, + [bg-green] { + background-color: oklch(from var(--green) l c h / 0.2); + } + .bg-orange, + [bg-orange] { + background-color: oklch(from var(--orange) l c h / 0.2); + } + .bg-cyan, + [bg-cyan] { + background-color: oklch(from var(--cyan) l c h / 0.2); + } + .bg-red, + [bg-red] { + background-color: oklch(from var(--red) l c h / 0.2); + } + .bg-yellow, + [bg-yellow] { + background-color: oklch(from var(--yellow) l c h / 0.2); + } + .bg-slate, + [bg-slate] { + background-color: oklch(from var(--slate) l c h / 0.2); + } + + @media (width <= 768px) { + .sm\:sm, + [sm\:sm] { + --unit: 2px; + --unit-size: 12px; + font-size: var(--unit-size, inherit); + } + .sm\:md, + [sm\:md] { + --unit: 4px; + --unit-size: 16px; + font-size: var(--unit-size, inherit); + } + .sm\:lg, + [sm\:lg] { + --unit: 8px; + --unit-size: 24px; + font-size: var(--unit-size, inherit); + } + .sm\:hide, + [sm\:hide] { + display: none; + } + .sm\:flex, + [sm\:flex] { + display: flex; + } + .sm\:block, + [sm\:block] { + display: block; + } + .sm\:vertical, + [sm\:vertical] { + flex-direction: column; + } + .sm\:order-first, + [sm\:order-first] { + order: -1; + } + } + + @media (768px < width <= 1024px) { + .md\:sm, + [md\:sm] { + --unit: 2px; + --unit-size: 12px; + font-size: var(--unit-size, inherit); + } + .md\:md, + [md\:md] { + --unit: 4px; + --unit-size: 16px; + font-size: var(--unit-size, inherit); + } + .md\:lg, + [md\:lg] { + --unit: 8px; + --unit-size: 24px; + font-size: var(--unit-size, inherit); + } + .md\:hide, + [md\:hide] { + display: none; + } + .md\:flex, + [md\:flex] { + display: flex; + } + .md\:block, + [md\:block] { + display: block; + } + .md\:vertical, + [md\:vertical] { + flex-direction: column; + } + .md\:order-first, + [md\:order-first] { + order: -1; + } + } + + @media (width > 1024px) { + .lg\:sm, + [lg\:sm] { + --unit: 2px; + --unit-size: 12px; + font-size: var(--unit-size, inherit); + } + .lg\:md, + [lg\:md] { + --unit: 4px; + --unit-size: 16px; + font-size: var(--unit-size, inherit); + } + .lg\:lg, + [lg\:lg] { + --unit: 8px; + --unit-size: 24px; + font-size: var(--unit-size, inherit); + } + .lg\:hide, + [lg\:hide] { + display: none; + } + .lg\:flex, + [lg\:flex] { + display: flex; + } + .lg\:block, + [lg\:block] { + display: block; + } + .lg\:vertical, + [lg\:vertical] { + flex-direction: column; + } + .lg\:order-first, + [lg\:order-first] { + order: -1; + } + } + /* ---- ChromeOnlyModifiers.css ---- */ + /* EXPERIMENTAL: typed attr() is, as of Apr 2026, Chrome 133+ only (not Safari/Firefox yet). + Once supported in all major browsers, these replace the fixed-value + modifiers (g-0..8, mt-0..8, w-full, t-0..8, etc.) in Modifiers.css. + Usage:
instead of
+ Dimensional attrs take two forms: a bare number scales with --unit + (w="50" → 50 * --unit), while a raw CSS length/percentage passes through + untouched (w="calc(100% - 40px)" or w="320px" → used as-is). + The length form is read into a temp var first; when the value is a plain + number that var is invalid, so var()'s fallback applies the unit calc. + (Nesting attr() inside an attr() fallback doesn't resolve in Chrome yet — + the var() indirection is what makes the two paradigms coexist.) */ + + /* Gap */ + [g] { + --_g: attr(g type()); + gap: var(--_g, calc(attr(g type()) * var(--unit))); + } + + /* Margin */ + [m] { + --_m: attr(m type()); + margin: var(--_m, calc(attr(m type()) * var(--unit))); + } + [m='auto'] { + margin: auto; + } + [mt] { + --_mt: attr(mt type()); + margin-top: var(--_mt, calc(attr(mt type()) * var(--unit))); + } + [mt='auto'] { + margin-top: auto; + } + [mb] { + --_mb: attr(mb type()); + margin-bottom: var(--_mb, calc(attr(mb type()) * var(--unit))); + } + [mb='auto'] { + margin-bottom: auto; + } + [ml] { + --_ml: attr(ml type()); + margin-left: var(--_ml, calc(attr(ml type()) * var(--unit))); + } + [ml='auto'] { + margin-left: auto; + } + [mr] { + --_mr: attr(mr type()); + margin-right: var(--_mr, calc(attr(mr type()) * var(--unit))); + } + [mr='auto'] { + margin-right: auto; + } + [mx] { + --_mx: attr(mx type()); + margin-inline: var(--_mx, calc(attr(mx type()) * var(--unit))); + } + [mx='auto'] { + margin-inline: auto; + } + [my] { + --_my: attr(my type()); + margin-block: var(--_my, calc(attr(my type()) * var(--unit))); + } + [my='auto'] { + margin-block: auto; + } + + /* Padding */ + [p] { + --_p: attr(p type()); + padding: var(--_p, calc(attr(p type()) * var(--unit))); + } + [pt] { + --_pt: attr(pt type()); + padding-top: var(--_pt, calc(attr(pt type()) * var(--unit))); + } + [pb] { + --_pb: attr(pb type()); + padding-bottom: var(--_pb, calc(attr(pb type()) * var(--unit))); + } + [pl] { + --_pl: attr(pl type()); + padding-left: var(--_pl, calc(attr(pl type()) * var(--unit))); + } + [pr] { + --_pr: attr(pr type()); + padding-right: var(--_pr, calc(attr(pr type()) * var(--unit))); + } + [px] { + --_px: attr(px type()); + padding-inline: var(--_px, calc(attr(px type()) * var(--unit))); + } + [py] { + --_py: attr(py type()); + padding-block: var(--_py, calc(attr(py type()) * var(--unit))); + } + + /* Sizing */ + [w] { + --_w: attr(w type()); + width: var(--_w, calc(attr(w type()) * var(--unit))); + } + [w='full'] { + width: 100%; + } + [h] { + --_h: attr(h type()); + height: var(--_h, calc(attr(h type()) * var(--unit))); + } + [h='full'] { + height: 100%; + } + + /* Inset (top, right, bottom, left) */ + [t] { + --_t: attr(t type()); + top: var(--_t, calc(attr(t type()) * var(--unit))); + } + [t='auto'] { + top: auto; + } + [r] { + --_r: attr(r type()); + right: var(--_r, calc(attr(r type()) * var(--unit))); + } + [r='auto'] { + right: auto; + } + [b] { + --_b: attr(b type()); + bottom: var(--_b, calc(attr(b type()) * var(--unit))); + } + [b='auto'] { + bottom: auto; + } + [l] { + --_l: attr(l type()); + left: var(--_l, calc(attr(l type()) * var(--unit))); + } + [l='auto'] { + left: auto; + } + + /* Flex */ + [f] { + flex: attr(f type()); + } + [f='none'] { + flex: none; + } + + /* Colors */ + [bg] { + background-color: attr(bg type()); + } + [text] { + color: attr(text type()); + } + [border] { + border-color: attr(border type()); + } + + /* Rotate */ + [rotate] { + rotate: calc(attr(rotate type()) * 1deg); + } + + /* Responsive: sm */ + @media (width <= 768px) { + [sm\:g] { + --_sm-g: attr(sm\:g type()); + gap: var(--_sm-g, calc(attr(sm\:g type()) * var(--unit))); + } + [sm\:m] { + --_sm-m: attr(sm\:m type()); + margin: var(--_sm-m, calc(attr(sm\:m type()) * var(--unit))); + } + [sm\:m='auto'] { + margin: auto; + } + [sm\:mt] { + --_sm-mt: attr(sm\:mt type()); + margin-top: var(--_sm-mt, calc(attr(sm\:mt type()) * var(--unit))); + } + [sm\:mt='auto'] { + margin-top: auto; + } + [sm\:mb] { + --_sm-mb: attr(sm\:mb type()); + margin-bottom: var(--_sm-mb, calc(attr(sm\:mb type()) * var(--unit))); + } + [sm\:mb='auto'] { + margin-bottom: auto; + } + [sm\:ml] { + --_sm-ml: attr(sm\:ml type()); + margin-left: var(--_sm-ml, calc(attr(sm\:ml type()) * var(--unit))); + } + [sm\:ml='auto'] { + margin-left: auto; + } + [sm\:mr] { + --_sm-mr: attr(sm\:mr type()); + margin-right: var(--_sm-mr, calc(attr(sm\:mr type()) * var(--unit))); + } + [sm\:mr='auto'] { + margin-right: auto; + } + [sm\:mx] { + --_sm-mx: attr(sm\:mx type()); + margin-inline: var(--_sm-mx, calc(attr(sm\:mx type()) * var(--unit))); + } + [sm\:mx='auto'] { + margin-inline: auto; + } + [sm\:my] { + --_sm-my: attr(sm\:my type()); + margin-block: var(--_sm-my, calc(attr(sm\:my type()) * var(--unit))); + } + [sm\:my='auto'] { + margin-block: auto; + } + [sm\:p] { + --_sm-p: attr(sm\:p type()); + padding: var(--_sm-p, calc(attr(sm\:p type()) * var(--unit))); + } + [sm\:pt] { + --_sm-pt: attr(sm\:pt type()); + padding-top: var(--_sm-pt, calc(attr(sm\:pt type()) * var(--unit))); + } + [sm\:pb] { + --_sm-pb: attr(sm\:pb type()); + padding-bottom: var(--_sm-pb, calc(attr(sm\:pb type()) * var(--unit))); + } + [sm\:pl] { + --_sm-pl: attr(sm\:pl type()); + padding-left: var(--_sm-pl, calc(attr(sm\:pl type()) * var(--unit))); + } + [sm\:pr] { + --_sm-pr: attr(sm\:pr type()); + padding-right: var(--_sm-pr, calc(attr(sm\:pr type()) * var(--unit))); + } + [sm\:px] { + --_sm-px: attr(sm\:px type()); + padding-inline: var(--_sm-px, calc(attr(sm\:px type()) * var(--unit))); + } + [sm\:py] { + --_sm-py: attr(sm\:py type()); + padding-block: var(--_sm-py, calc(attr(sm\:py type()) * var(--unit))); + } + [sm\:w] { + --_sm-w: attr(sm\:w type()); + width: var(--_sm-w, calc(attr(sm\:w type()) * var(--unit))); + } + [sm\:w='full'] { + width: 100%; + } + [sm\:h] { + --_sm-h: attr(sm\:h type()); + height: var(--_sm-h, calc(attr(sm\:h type()) * var(--unit))); + } + [sm\:h='full'] { + height: 100%; + } + [sm\:t] { + --_sm-t: attr(sm\:t type()); + top: var(--_sm-t, calc(attr(sm\:t type()) * var(--unit))); + } + [sm\:t='auto'] { + top: auto; + } + [sm\:r] { + --_sm-r: attr(sm\:r type()); + right: var(--_sm-r, calc(attr(sm\:r type()) * var(--unit))); + } + [sm\:r='auto'] { + right: auto; + } + [sm\:b] { + --_sm-b: attr(sm\:b type()); + bottom: var(--_sm-b, calc(attr(sm\:b type()) * var(--unit))); + } + [sm\:b='auto'] { + bottom: auto; + } + [sm\:l] { + --_sm-l: attr(sm\:l type()); + left: var(--_sm-l, calc(attr(sm\:l type()) * var(--unit))); + } + [sm\:l='auto'] { + left: auto; + } + [sm\:f] { + flex: attr(sm\:f type()); + } + [sm\:f='none'] { + flex: none; + } + [sm\:bg] { + background-color: attr(sm\:bg type()); + } + [sm\:text] { + color: attr(sm\:text type()); + } + [sm\:border] { + border-color: attr(sm\:border type()); + } + } + + /* Responsive: md */ + @media (768px < width <= 1024px) { + [md\:g] { + --_md-g: attr(md\:g type()); + gap: var(--_md-g, calc(attr(md\:g type()) * var(--unit))); + } + [md\:m] { + --_md-m: attr(md\:m type()); + margin: var(--_md-m, calc(attr(md\:m type()) * var(--unit))); + } + [md\:m='auto'] { + margin: auto; + } + [md\:mt] { + --_md-mt: attr(md\:mt type()); + margin-top: var(--_md-mt, calc(attr(md\:mt type()) * var(--unit))); + } + [md\:mt='auto'] { + margin-top: auto; + } + [md\:mb] { + --_md-mb: attr(md\:mb type()); + margin-bottom: var(--_md-mb, calc(attr(md\:mb type()) * var(--unit))); + } + [md\:mb='auto'] { + margin-bottom: auto; + } + [md\:ml] { + --_md-ml: attr(md\:ml type()); + margin-left: var(--_md-ml, calc(attr(md\:ml type()) * var(--unit))); + } + [md\:ml='auto'] { + margin-left: auto; + } + [md\:mr] { + --_md-mr: attr(md\:mr type()); + margin-right: var(--_md-mr, calc(attr(md\:mr type()) * var(--unit))); + } + [md\:mr='auto'] { + margin-right: auto; + } + [md\:mx] { + --_md-mx: attr(md\:mx type()); + margin-inline: var(--_md-mx, calc(attr(md\:mx type()) * var(--unit))); + } + [md\:mx='auto'] { + margin-inline: auto; + } + [md\:my] { + --_md-my: attr(md\:my type()); + margin-block: var(--_md-my, calc(attr(md\:my type()) * var(--unit))); + } + [md\:my='auto'] { + margin-block: auto; + } + [md\:p] { + --_md-p: attr(md\:p type()); + padding: var(--_md-p, calc(attr(md\:p type()) * var(--unit))); + } + [md\:pt] { + --_md-pt: attr(md\:pt type()); + padding-top: var(--_md-pt, calc(attr(md\:pt type()) * var(--unit))); + } + [md\:pb] { + --_md-pb: attr(md\:pb type()); + padding-bottom: var(--_md-pb, calc(attr(md\:pb type()) * var(--unit))); + } + [md\:pl] { + --_md-pl: attr(md\:pl type()); + padding-left: var(--_md-pl, calc(attr(md\:pl type()) * var(--unit))); + } + [md\:pr] { + --_md-pr: attr(md\:pr type()); + padding-right: var(--_md-pr, calc(attr(md\:pr type()) * var(--unit))); + } + [md\:px] { + --_md-px: attr(md\:px type()); + padding-inline: var(--_md-px, calc(attr(md\:px type()) * var(--unit))); + } + [md\:py] { + --_md-py: attr(md\:py type()); + padding-block: var(--_md-py, calc(attr(md\:py type()) * var(--unit))); + } + [md\:w] { + --_md-w: attr(md\:w type()); + width: var(--_md-w, calc(attr(md\:w type()) * var(--unit))); + } + [md\:w='full'] { + width: 100%; + } + [md\:h] { + --_md-h: attr(md\:h type()); + height: var(--_md-h, calc(attr(md\:h type()) * var(--unit))); + } + [md\:h='full'] { + height: 100%; + } + [md\:t] { + --_md-t: attr(md\:t type()); + top: var(--_md-t, calc(attr(md\:t type()) * var(--unit))); + } + [md\:t='auto'] { + top: auto; + } + [md\:r] { + --_md-r: attr(md\:r type()); + right: var(--_md-r, calc(attr(md\:r type()) * var(--unit))); + } + [md\:r='auto'] { + right: auto; + } + [md\:b] { + --_md-b: attr(md\:b type()); + bottom: var(--_md-b, calc(attr(md\:b type()) * var(--unit))); + } + [md\:b='auto'] { + bottom: auto; + } + [md\:l] { + --_md-l: attr(md\:l type()); + left: var(--_md-l, calc(attr(md\:l type()) * var(--unit))); + } + [md\:l='auto'] { + left: auto; + } + [md\:f] { + flex: attr(md\:f type()); + } + [md\:f='none'] { + flex: none; + } + [md\:bg] { + background-color: attr(md\:bg type()); + } + [md\:text] { + color: attr(md\:text type()); + } + [md\:border] { + border-color: attr(md\:border type()); + } + } + + /* Responsive: lg */ + @media (width > 1024px) { + [lg\:g] { + --_lg-g: attr(lg\:g type()); + gap: var(--_lg-g, calc(attr(lg\:g type()) * var(--unit))); + } + [lg\:m] { + --_lg-m: attr(lg\:m type()); + margin: var(--_lg-m, calc(attr(lg\:m type()) * var(--unit))); + } + [lg\:m='auto'] { + margin: auto; + } + [lg\:mt] { + --_lg-mt: attr(lg\:mt type()); + margin-top: var(--_lg-mt, calc(attr(lg\:mt type()) * var(--unit))); + } + [lg\:mt='auto'] { + margin-top: auto; + } + [lg\:mb] { + --_lg-mb: attr(lg\:mb type()); + margin-bottom: var(--_lg-mb, calc(attr(lg\:mb type()) * var(--unit))); + } + [lg\:mb='auto'] { + margin-bottom: auto; + } + [lg\:ml] { + --_lg-ml: attr(lg\:ml type()); + margin-left: var(--_lg-ml, calc(attr(lg\:ml type()) * var(--unit))); + } + [lg\:ml='auto'] { + margin-left: auto; + } + [lg\:mr] { + --_lg-mr: attr(lg\:mr type()); + margin-right: var(--_lg-mr, calc(attr(lg\:mr type()) * var(--unit))); + } + [lg\:mr='auto'] { + margin-right: auto; + } + [lg\:mx] { + --_lg-mx: attr(lg\:mx type()); + margin-inline: var(--_lg-mx, calc(attr(lg\:mx type()) * var(--unit))); + } + [lg\:mx='auto'] { + margin-inline: auto; + } + [lg\:my] { + --_lg-my: attr(lg\:my type()); + margin-block: var(--_lg-my, calc(attr(lg\:my type()) * var(--unit))); + } + [lg\:my='auto'] { + margin-block: auto; + } + [lg\:p] { + --_lg-p: attr(lg\:p type()); + padding: var(--_lg-p, calc(attr(lg\:p type()) * var(--unit))); + } + [lg\:pt] { + --_lg-pt: attr(lg\:pt type()); + padding-top: var(--_lg-pt, calc(attr(lg\:pt type()) * var(--unit))); + } + [lg\:pb] { + --_lg-pb: attr(lg\:pb type()); + padding-bottom: var(--_lg-pb, calc(attr(lg\:pb type()) * var(--unit))); + } + [lg\:pl] { + --_lg-pl: attr(lg\:pl type()); + padding-left: var(--_lg-pl, calc(attr(lg\:pl type()) * var(--unit))); + } + [lg\:pr] { + --_lg-pr: attr(lg\:pr type()); + padding-right: var(--_lg-pr, calc(attr(lg\:pr type()) * var(--unit))); + } + [lg\:px] { + --_lg-px: attr(lg\:px type()); + padding-inline: var(--_lg-px, calc(attr(lg\:px type()) * var(--unit))); + } + [lg\:py] { + --_lg-py: attr(lg\:py type()); + padding-block: var(--_lg-py, calc(attr(lg\:py type()) * var(--unit))); + } + [lg\:w] { + --_lg-w: attr(lg\:w type()); + width: var(--_lg-w, calc(attr(lg\:w type()) * var(--unit))); + } + [lg\:w='full'] { + width: 100%; + } + [lg\:h] { + --_lg-h: attr(lg\:h type()); + height: var(--_lg-h, calc(attr(lg\:h type()) * var(--unit))); + } + [lg\:h='full'] { + height: 100%; + } + [lg\:t] { + --_lg-t: attr(lg\:t type()); + top: var(--_lg-t, calc(attr(lg\:t type()) * var(--unit))); + } + [lg\:t='auto'] { + top: auto; + } + [lg\:r] { + --_lg-r: attr(lg\:r type()); + right: var(--_lg-r, calc(attr(lg\:r type()) * var(--unit))); + } + [lg\:r='auto'] { + right: auto; + } + [lg\:b] { + --_lg-b: attr(lg\:b type()); + bottom: var(--_lg-b, calc(attr(lg\:b type()) * var(--unit))); + } + [lg\:b='auto'] { + bottom: auto; + } + [lg\:l] { + --_lg-l: attr(lg\:l type()); + left: var(--_lg-l, calc(attr(lg\:l type()) * var(--unit))); + } + [lg\:l='auto'] { + left: auto; + } + [lg\:f] { + flex: attr(lg\:f type()); + } + [lg\:f='none'] { + flex: none; + } + [lg\:bg] { + background-color: attr(lg\:bg type()); + } + [lg\:text] { + color: attr(lg\:text type()); + } + [lg\:border] { + border-color: attr(lg\:border type()); + } + } + } +} diff --git a/docs/color-doctrine.md b/docs/color-doctrine.md new file mode 100644 index 00000000..9ea2f8e9 --- /dev/null +++ b/docs/color-doctrine.md @@ -0,0 +1,92 @@ +# Color Doctrine + +How Battleborn Brawlers spends color. Color is the loudest, scarcest channel we +have — the eye reliably separates only ~6 categorical colors, and that's _per +system_. We already run several color systems (rarity, element, race, stats & +status). Without rules they collide and cancel each other out. This is the rule. + +## The problem, stated once + +A colored mark only means something if you first know **which system** it belongs +to. With four systems on one screen, a green mark could be uncommon, nature, +"good stat," or a heal. Two failure modes follow: + +- **Ambiguity** — which system is this color speaking for? +- **Attention competition** — if everything is colored, nothing leads the eye. + +## This is already happening + +Every system pulls from one shared `--hue-*` base palette, so single hues carry +multiple meanings _today_: + +| Hue | Rarity | Element | Status | Floater | +| -------------- | -------- | ------- | ---------- | ------- | +| `--hue-green` | uncommon | nature | poisoned | heal | +| `--hue-red` | exotic | fire | bleeding | damage | +| `--hue-blue` | rare | — | vulnerable | — | +| `--hue-purple` | epic | — | stunned | — | + +Uncommon rarity and nature element are the _exact same green_; exotic and fire are +the _exact same red_. Race dots currently read `--element-color` too, so race +borrows element's hue. That's the muddle, in the tokens. + +## Four moves that fix it + +1. **One system owns hue per surface.** The systems rarely peak in the same place + — rarity in loot/inventory, element in combat/abilities, race in the roster, + stats in tooltips. Let exactly one _own_ color on each surface; **demote the + rest to non-hue channels** there (glyph, shape, mono pip, border-not-fill, + position, label). +2. **Shape grammar lets hue repeat safely.** Give each system a signature mark, so + a green circle and a green hexagon never get confused — the shape says which + alphabet you're reading. This is the escape hatch from "non-overlapping + palettes," which is impossible with four systems. +3. **Ordinal vs categorical, kept apart.** Rarity and stat-direction are _ladders_ + (a value ramp: low→high). Element and race are _identities_ (no ranking). + Identity is carried by glyph/shape, never by a ramp — a ramp invites the brain + to rank things that have no rank. +4. **Neutral by default; color is the exception.** Most of the UI is ink / + parchment / slate, so that when color appears it _means_ something. Four systems + painting everything leaves the canvas no rest and color stops being a signal. + +## The allocation (the constitution) + +| System | Owns | Mark | Notes | +| ----------------- | ---------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Rarity / tier** | **Color** (the ramp) | hexagon / pill fill | The one system whose whole job is an ordered ladder, and it's culturally expected (gray→green→blue→purple→orange→red). Protect that ramp; don't reuse its exact hues as flat fills elsewhere. Until "rarity" exists as a concept, drive the ramp off **item level/tier** — rarity is just the named bucketing of tiers. | +| **Element** | **Glyph** (symbol) | white icon in a cap | Identity. Color only where combat-reading speed demands it, and then as a tinted _icon_, not a block. | +| **Race** | **Smallest mark** | tiny icon / initial | Low-stakes identity — the first thing to demote off hue. Stop coloring race dots from `--element-color`. | +| **Stats** | **Mostly neutral** | number + delta | Color only the _deltas_ (green +, red −) and group headers, never every value. Stat panels are where over-coloring hurts most. | +| **Status** | **Its own muted band** | chip + icon | Already desaturated vs the base hues (`calc(c * 0.6)`), which is right — keep status visibly _dimmer_ than rarity/element so it never competes for "rank." | + +## When several collide on one card + +Establish a focal order so each stays decodable. Example — item tooltip: + +> **rarity** = the frame / dominant color · **element** = a glyph · **stats** = +> neutral text with colored deltas only. + +One thing is loud, the rest are quiet. Never two loud systems on the same card. + +## Token policy + +- `--hue-*` is a **private base palette.** Components never read `--hue-*` + directly — only semantic tokens (`--rarity-*`, `--element-*`, `--status-*`, + future `--tier-*` / `--stat-*`). +- Aliasing semantic tokens onto shared hues is **fine _only_ when the two systems + never appear with the same mark on the same surface** (shape grammar saves them). + Where they _would_ collide as the same shape — e.g. a rarity pill next to an + element pill — break the alias or change one system's mark. +- Race gets its own non-hue treatment; remove its dependency on `--element-color`. + +## Open decisions (yours to make) + +1. **Rarity ramp source** — confirm we drive it off level/tier now, with "rarity" + as a later renaming of tiers. How many tiers, and the level breakpoints? +2. **Element in combat** — does fast combat reading justify element _color_ (not + just glyph) on that one surface? If yes, it's the surface where element owns hue + and rarity steps back. +3. **Race** — icon, initial, or keep a dot but on a deliberately _different_ + (desaturated / non-rarity) palette? +4. **Break the green/red aliases?** — decide per the token policy above: distinct + marks, or distinct hues. diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index d670a334..00000000 --- a/eslint.config.js +++ /dev/null @@ -1,38 +0,0 @@ -import js from '@eslint/js'; -import ts from 'typescript-eslint'; -import svelte from 'eslint-plugin-svelte'; -import prettier from 'eslint-config-prettier'; -import globals from 'globals'; - -/** @type {import('eslint').Linter.Config[]} */ -export default [ - js.configs.recommended, - ...ts.configs.recommended, - ...svelte.configs['flat/recommended'], - prettier, - ...svelte.configs['flat/prettier'], - { - languageOptions: { - globals: { - ...globals.browser, - ...globals.node - } - } - }, - { - files: ['**/*.svelte'], - languageOptions: { - parserOptions: { - parser: ts.parser - } - } - }, - { - ignores: ['build/', '.svelte-kit/', 'dist/'], - rules: { - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-require-imports': 'off', - '@typescript-eslint/no-unused-vars': 'warn' - } - } -]; diff --git a/first-compilation-19-june-2026.md b/first-compilation-19-june-2026.md new file mode 100644 index 00000000..98b75bb6 --- /dev/null +++ b/first-compilation-19-june-2026.md @@ -0,0 +1,95 @@ +# First Compilation — 19 June 2026 + +> The day Battleborn Brawlers stopped hydrating and started _arriving_ pre-rendered. + +Today marks a milestone for both **Vibe** and **Battleborn Brawlers**: the first time the +game was shipped to production through the **Vibe compiler (hyperspeed)** rather than the +runtime hydration path — and the first time we could measure, side by side, what that buys us. + +Two identical deployments were put head to head: + +- **Runtime** — `https://battlebornbrawlers.com` — the Vite production bundle running in + Vibe's runtime mode: a tiny HTML shell, one big `boot.js`, then client-side template + fetches (`/components/*.html`) and hydration. +- **Compiled** — `https://compiled.battlebornbrawlers.com` — the same app, pre-rendered by + the Vibe compiler: real content baked into the HTML, no template fetches, no hydration parse. + +## The measurement + +Cold loads, identical method, captured via Chrome DevTools (Resource Timing + a performance +trace) on the login/landing page. + +| Metric | 🟢 Compiled | 🔵 Runtime | Difference | +| ------------------------ | ----------- | ---------- | ---------------------------- | +| First Contentful Paint | 248 ms | 596 ms | 2.4× faster | +| Largest Contentful Paint | 255 ms | 504 ms | ~2× faster | +| LCP render delay | 159 ms | 491 ms | 3× less (the hydration cost) | +| DOMContentLoaded | 438 ms | 539 ms | ~1.2× faster | +| Full load event | 438 ms | 1337 ms | 3× faster | +| HTML doc (decoded) | 61.7 KB | 15.2 KB | compiled ships real content | +| JS (decoded) | 558 KB | 291 KB | compiled ships ~2× more JS | +| Total transfer | 733 KB | 673 KB | ~equal | + +## What it means + +The compiled win is a **latency and paint win, not a bytes win** — and that is exactly the +right trade. + +The runtime path ships almost nothing up front, then spends its time on the client: +download `boot.js`, fetch ~10 component templates over the wire, parse them, hydrate. That +round-trip-then-hydrate chain is the **491 ms of render delay** and the **1.3 s full load**. + +The compiled path inverts it. The content is already in the 62 KB HTML document, so the +browser paints almost immediately (**FCP 248 ms**). It pays with ~2× the JavaScript bytes and +more requests — but those load in parallel, _off the critical path_, so they never delay the +pixels. We trade idle bytes for visible speed. + +**Net: ~2.4× faster first paint, ~3× faster to fully loaded — on the lightest page in the +game.** The gap is expected to widen on content-heavy authenticated pages (the arena, the +roster), where the runtime version has far more components to fetch and hydrate. + +## Why this matters for Vibe + +Vibe was built runtime-first: author reactive markup, hydrate at runtime, iterate fast. That +philosophy is what makes it pleasant. But "runtime-first" was never meant to be +"runtime-only." The compiler is the proof that the _same source_ — the same `@[…]` bindings, +the same `` / `` directives, the same components — can be lowered into +pre-rendered HTML with no author-visible changes. You write the convenient thing; the +compiler ships the fast thing. + +For a runtime-first framework to grow up, this was the load-bearing feature. Today it carried +its first real production payload. + +## Why this matters for Battleborn Brawlers + +> The world's websites are overengineered. It doesn't have to be that way. + +Battleborn Brawlers is the primary dogfood for Vibe and Stylecheat. Every quirk we hit, we +fixed upstream instead of working around it — the manifest resolution, the dynamic-route +fallbacks, the compiled-mode `this.`-in-conditionals handling, the minify/whitespace edges. +That discipline is what made today possible: the game didn't bend to the compiler; the +compiler grew to fit the game. + +The result is a strategy auto-battler that now _arrives_ rendered instead of assembling itself +in front of the player. + +## Honest caveats + +- Single sample per page; TTFB varied with edge-cache warmth (noise). The render-delay gap + (159 ms vs 491 ms) is **architectural and robust**, not measurement noise. +- A `/@vibe-hmr` request was observed on the **production runtime** deployment — the HMR + client may be leaking into the prod build. Worth removing; it shouldn't ship to production. + +## Known next wins (not blockers — just the next mile) + +- **`parchment-2080x1170.jpg` is 481 KB** and the single largest resource on _both_ sites. + WebP/AVIF + right-sizing should cut it by ~75%. Biggest easy win in the whole game. +- **Compiled CSS isn't bundled/minified** the way the Vite build is — `Iconice.css` decodes + to 204 KB, `stylecheat.css` to 146 KB, served as separate raw files. Bundle + minify, and + subset the icon font. +- **The hyperspeed manifest is 250 KB decoded** per page. Worth auditing whether all of it is + load-bearing per route. + +--- + +_Recorded 19 June 2026 — the first compilation._ diff --git a/image-optimization-20-june-2026.md b/image-optimization-20-june-2026.md new file mode 100644 index 00000000..e3150ebd --- /dev/null +++ b/image-optimization-20-june-2026.md @@ -0,0 +1,104 @@ +# Image Optimization — 20 June 2026 + +> The day the brawlers stopped weighing 18 megabytes. + +The day after the [first compilation](first-compilation-19-june-2026.md), Battleborn Brawlers +got its single biggest real-world performance win — and it had nothing to do with the +framework. The game was shipping its character art as full-resolution PNGs: ~1500×3000px +masters, 1.5–2.5 MB **each**, rendered into ~100px-wide cards. Pure waste, paid by every +player on every visit. + +The fix: a build/dev pipeline that keeps PNG/JPG **masters** in a non-deployed `/images` +folder and emits right-sized, committed `.webp` into `static/images` — automatically, with +no manual step. Source art stays untouched; the wire gets the lean version. + +Two live deployments were put head to head: + +- **Optimized** — `https://battlebornbrawlers.com` — the compiled build serving `.webp`. +- **Original** — `https://runtime.battlebornbrawlers.com` — the previous build serving the + raw `.png`/`.jpg` masters. + +## The measurement + +Real bytes over the wire (`fetch`, cache bypassed), images only, identical pages. + +### The Brawlers roster — the same 12 character images + +| Metric | 🟢 Optimized (webp) | 🔵 Original (png/jpg) | Difference | +| ------------------ | ------------------- | --------------------- | ------------------------ | +| Total image weight | **536 KB** | 18,939 KB (18.5 MB) | **35× smaller (−97.2%)** | +| Average per image | **45 KB** | 1,578 KB | 35× smaller | +| Format | webp | png | — | + +### Per-image highlights + +| Character art | 🟢 webp | 🔵 png | Saved | +| --------------- | ------- | -------- | ----- | +| `troll/male-01` | 44 KB | 2,521 KB | 98.3% | +| `human/male-01` | 76 KB | 2,145 KB | 96.5% | +| `elf/male-01` | 53 KB | 2,043 KB | 97.4% | +| `elf/female-01` | 39 KB | 2,036 KB | 98.1% | +| `dwarf/male-01` | 47 KB | 1,872 KB | 97.5% | + +### The login / landing page (no login required) + +| Metric | 🟢 Optimized | 🔵 Original | Difference | +| -------------------- | ------------ | ----------- | ----------------- | +| Parchment background | **157 KB** | 482 KB | 3× smaller (−67%) | +| Total page images | **160 KB** | 484 KB | 3× smaller | + +## What it means + +This is the win that actually changes how the game _feels_ — especially on mobile and on a +cold cache. The roster alone dropped from **18.5 MB to 0.5 MB**: a 35× cut, the same 12 +images, no visible quality loss at display size. A player opening the Brawlers page used to +pull down nearly twenty megabytes of art; now it's half a megabyte. + +Two levers did the work, both applied automatically: + +1. **Format** — PNG → WebP (lossy, with alpha). WebP carries the same cut-out character art + at a fraction of PNG's size. +2. **Right-sizing** — the masters were ~15× larger in each dimension than they're ever + displayed. The pipeline caps art to a sane bounding box (`races` → fit 600×900) before + encoding, so the browser stops downloading 3000px art to paint a 190px card. + +Backgrounds got the same treatment (parchment 482 → 157 KB), and the deploy as a whole +shed the ~190 MB of masters entirely — they live in `/images`, git-committed but +`.vercelignore`'d, never shipped. + +## How it works (and stays hands-off) + +`static/images` is a _generated_ folder; the URL space is always `.webp`. Whatever you drop +into `/images` (png/jpg) is converted on demand: + +- **Dev** — a Vite middleware transcodes on first request and serves it. +- **Commit** — a `pre-commit` hook regenerates and stages any changed art, so the committed + webp is always current even if you never opened the page. +- **Build** — a safety-net pass; on Vercel it no-ops (masters absent) and ships the committed + webp. + +You keep adding art however you like and reference it as `.webp`. The lean version takes care +of itself. + +## Honest caveats + +- Sizes are real transferred bytes (cache bypassed), but a single sample per image; the gap + is so large (35×) that sampling noise is irrelevant. +- WebP is a _delivery_ format. The lossless PNG masters are kept as the source of truth, so + quality can always be re-derived (e.g. if display sizes or quality targets change). +- The route to here was bumpy: a bare `images` pattern in both the compiler's `skipFiles` and + `.vercelignore` matched `static/images` too, and the sync's orphan-prune briefly deleted the + committed webp on Vercel (where the masters dir is empty). All fixed — and the prune now + refuses to run when zero masters are present. + +## Known next wins + +- **AVIF** for another ~20–30% on top of WebP, via `` with a WebP fallback — worth it + if the art ever feels heavy on slow links. +- **Per-context sizes** (`srcset`) — the roster card needs far less than the detail hero; + a small card variant could shave the roster further. +- **The icon set** — `static/icons` ships ~500 SVGs; worth auditing whether all load per page. + +--- + +_Recorded 20 June 2026 — the day the roster went from 18.5 MB to 0.5 MB._ diff --git a/images/bg/arena-combat-4096x2304.jpg b/images/bg/arena-combat-4096x2304.jpg new file mode 100644 index 00000000..d7532a05 Binary files /dev/null and b/images/bg/arena-combat-4096x2304.jpg differ diff --git a/images/bg/arena-combat-sandy-4096x2304.png b/images/bg/arena-combat-sandy-4096x2304.png new file mode 100644 index 00000000..b3558842 Binary files /dev/null and b/images/bg/arena-combat-sandy-4096x2304.png differ diff --git a/static/images/arena-cut.png b/images/bg/arena-cut-3000x1552.png similarity index 100% rename from static/images/arena-cut.png rename to images/bg/arena-cut-3000x1552.png diff --git a/images/bg/login-4096x2304.jpg b/images/bg/login-4096x2304.jpg new file mode 100644 index 00000000..073afa34 Binary files /dev/null and b/images/bg/login-4096x2304.jpg differ diff --git a/images/bg/parchment-2080x1170.jpg b/images/bg/parchment-2080x1170.jpg new file mode 100644 index 00000000..b953264e Binary files /dev/null and b/images/bg/parchment-2080x1170.jpg differ diff --git a/images/bg/parchment-4096x2304.jpg b/images/bg/parchment-4096x2304.jpg new file mode 100644 index 00000000..c4dd5b3d Binary files /dev/null and b/images/bg/parchment-4096x2304.jpg differ diff --git a/images/bg/the-wild-2250x1500.png b/images/bg/the-wild-2250x1500.png new file mode 100644 index 00000000..c3f83fef Binary files /dev/null and b/images/bg/the-wild-2250x1500.png differ diff --git a/images/bg/the-wild-4096x2304.png b/images/bg/the-wild-4096x2304.png new file mode 100644 index 00000000..b03dccb1 Binary files /dev/null and b/images/bg/the-wild-4096x2304.png differ diff --git a/images/bg/the-wild-grassland-2250x1500.png b/images/bg/the-wild-grassland-2250x1500.png new file mode 100644 index 00000000..eff0a147 Binary files /dev/null and b/images/bg/the-wild-grassland-2250x1500.png differ diff --git a/images/bg/the-wild-grassland-dark-4096x2304.png b/images/bg/the-wild-grassland-dark-4096x2304.png new file mode 100644 index 00000000..6ce7f77b Binary files /dev/null and b/images/bg/the-wild-grassland-dark-4096x2304.png differ diff --git a/images/elements/earth-621x619.png b/images/elements/earth-621x619.png new file mode 100644 index 00000000..797edc18 Binary files /dev/null and b/images/elements/earth-621x619.png differ diff --git a/images/elements/fire-477x730.png b/images/elements/fire-477x730.png new file mode 100644 index 00000000..d46d522c Binary files /dev/null and b/images/elements/fire-477x730.png differ diff --git a/images/elements/frost-452x622.png b/images/elements/frost-452x622.png new file mode 100644 index 00000000..852b0d9d Binary files /dev/null and b/images/elements/frost-452x622.png differ diff --git a/images/elements/lightning-422x586.png b/images/elements/lightning-422x586.png new file mode 100644 index 00000000..8472a2a4 Binary files /dev/null and b/images/elements/lightning-422x586.png differ diff --git a/images/elements/nature-425x704.png b/images/elements/nature-425x704.png new file mode 100644 index 00000000..e74c2bc3 Binary files /dev/null and b/images/elements/nature-425x704.png differ diff --git a/static/images/equipment/axe.png b/images/equipment/axe.png similarity index 100% rename from static/images/equipment/axe.png rename to images/equipment/axe.png diff --git a/static/images/equipment/bow.png b/images/equipment/bow.png similarity index 100% rename from static/images/equipment/bow.png rename to images/equipment/bow.png diff --git a/static/images/equipment/cloth-robe.png b/images/equipment/cloth-robe.png similarity index 100% rename from static/images/equipment/cloth-robe.png rename to images/equipment/cloth-robe.png diff --git a/static/images/equipment/dagger.png b/images/equipment/dagger.png similarity index 100% rename from static/images/equipment/dagger.png rename to images/equipment/dagger.png diff --git a/static/images/equipment/leather-harness.png b/images/equipment/leather-harness.png similarity index 100% rename from static/images/equipment/leather-harness.png rename to images/equipment/leather-harness.png diff --git a/static/images/equipment/mace.png b/images/equipment/mace.png similarity index 100% rename from static/images/equipment/mace.png rename to images/equipment/mace.png diff --git a/static/images/equipment/ring.png b/images/equipment/ring.png similarity index 100% rename from static/images/equipment/ring.png rename to images/equipment/ring.png diff --git a/static/images/equipment/shield.png b/images/equipment/shield.png similarity index 100% rename from static/images/equipment/shield.png rename to images/equipment/shield.png diff --git a/static/images/equipment/steel-cuirass.png b/images/equipment/steel-cuirass.png similarity index 100% rename from static/images/equipment/steel-cuirass.png rename to images/equipment/steel-cuirass.png diff --git a/static/images/equipment/sword.png b/images/equipment/sword.png similarity index 100% rename from static/images/equipment/sword.png rename to images/equipment/sword.png diff --git a/static/images/equipment/two-handed-axe.png b/images/equipment/two-handed-axe.png similarity index 100% rename from static/images/equipment/two-handed-axe.png rename to images/equipment/two-handed-axe.png diff --git a/static/images/equipment/wooden-ring.png b/images/equipment/wooden-ring.png similarity index 100% rename from static/images/equipment/wooden-ring.png rename to images/equipment/wooden-ring.png diff --git a/images/generated/.gitkeep b/images/generated/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/images/generated/1781618073402.png b/images/generated/1781618073402.png new file mode 100644 index 00000000..8448cb66 Binary files /dev/null and b/images/generated/1781618073402.png differ diff --git a/images/generated/1781618456529.png b/images/generated/1781618456529.png new file mode 100644 index 00000000..24aacf05 Binary files /dev/null and b/images/generated/1781618456529.png differ diff --git a/images/generated/1781618456537.png b/images/generated/1781618456537.png new file mode 100644 index 00000000..c83f5d3e Binary files /dev/null and b/images/generated/1781618456537.png differ diff --git a/images/generated/1782575871706.png b/images/generated/1782575871706.png new file mode 100644 index 00000000..fa8aefc2 Binary files /dev/null and b/images/generated/1782575871706.png differ diff --git a/images/materials/cloth.png b/images/materials/cloth.png new file mode 100755 index 00000000..c4d00676 Binary files /dev/null and b/images/materials/cloth.png differ diff --git a/images/materials/essence-of-earth.png b/images/materials/essence-of-earth.png new file mode 100644 index 00000000..bb39a7c0 Binary files /dev/null and b/images/materials/essence-of-earth.png differ diff --git a/images/materials/essence-of-fire.png b/images/materials/essence-of-fire.png new file mode 100644 index 00000000..8ab33024 Binary files /dev/null and b/images/materials/essence-of-fire.png differ diff --git a/images/materials/essence-of-frost.png b/images/materials/essence-of-frost.png new file mode 100644 index 00000000..f8e2f263 Binary files /dev/null and b/images/materials/essence-of-frost.png differ diff --git a/images/materials/essence-of-lightning.png b/images/materials/essence-of-lightning.png new file mode 100644 index 00000000..f7e0f418 Binary files /dev/null and b/images/materials/essence-of-lightning.png differ diff --git a/images/materials/essence-of-nature.png b/images/materials/essence-of-nature.png new file mode 100644 index 00000000..edfa6fc5 Binary files /dev/null and b/images/materials/essence-of-nature.png differ diff --git a/images/materials/leather.png b/images/materials/leather.png new file mode 100755 index 00000000..30533b73 Binary files /dev/null and b/images/materials/leather.png differ diff --git a/images/materials/steel.png b/images/materials/steel.png new file mode 100755 index 00000000..e8924b06 Binary files /dev/null and b/images/materials/steel.png differ diff --git a/images/materials/wood.png b/images/materials/wood.png new file mode 100755 index 00000000..25d1a702 Binary files /dev/null and b/images/materials/wood.png differ diff --git a/images/races/creature/basher-goblin.png b/images/races/creature/basher-goblin.png new file mode 100644 index 00000000..7c7582a5 Binary files /dev/null and b/images/races/creature/basher-goblin.png differ diff --git a/images/races/creature/beastmaster.png b/images/races/creature/beastmaster.png new file mode 100644 index 00000000..558e3c35 Binary files /dev/null and b/images/races/creature/beastmaster.png differ diff --git a/images/races/creature/blind-swordsman.png b/images/races/creature/blind-swordsman.png new file mode 100644 index 00000000..6cea3f98 Binary files /dev/null and b/images/races/creature/blind-swordsman.png differ diff --git a/images/races/creature/boar.png b/images/races/creature/boar.png new file mode 100644 index 00000000..f64d079d Binary files /dev/null and b/images/races/creature/boar.png differ diff --git a/images/races/creature/cannon.png b/images/races/creature/cannon.png new file mode 100644 index 00000000..f29c9f17 Binary files /dev/null and b/images/races/creature/cannon.png differ diff --git a/images/races/creature/crazy-old-man.png b/images/races/creature/crazy-old-man.png new file mode 100644 index 00000000..658cd1de Binary files /dev/null and b/images/races/creature/crazy-old-man.png differ diff --git a/images/races/creature/dimachaerus.png b/images/races/creature/dimachaerus.png new file mode 100644 index 00000000..df014207 Binary files /dev/null and b/images/races/creature/dimachaerus.png differ diff --git a/images/races/creature/dragon-egg.png b/images/races/creature/dragon-egg.png new file mode 100644 index 00000000..29938919 Binary files /dev/null and b/images/races/creature/dragon-egg.png differ diff --git a/images/races/creature/earth/armorillo.png b/images/races/creature/earth/armorillo.png new file mode 100644 index 00000000..2689b734 Binary files /dev/null and b/images/races/creature/earth/armorillo.png differ diff --git a/images/races/creature/earth/elise-goddess-of-earth.png b/images/races/creature/earth/elise-goddess-of-earth.png new file mode 100644 index 00000000..67f601cd Binary files /dev/null and b/images/races/creature/earth/elise-goddess-of-earth.png differ diff --git a/images/races/creature/earth/giant.png b/images/races/creature/earth/giant.png new file mode 100644 index 00000000..bf761698 Binary files /dev/null and b/images/races/creature/earth/giant.png differ diff --git a/images/races/creature/earth/vita-deserto.png b/images/races/creature/earth/vita-deserto.png new file mode 100644 index 00000000..8e5ac0d0 Binary files /dev/null and b/images/races/creature/earth/vita-deserto.png differ diff --git a/images/races/creature/executioner.png b/images/races/creature/executioner.png new file mode 100644 index 00000000..ff3c1df6 Binary files /dev/null and b/images/races/creature/executioner.png differ diff --git a/images/races/creature/fire/bullrock.png b/images/races/creature/fire/bullrock.png new file mode 100644 index 00000000..d45d0437 Binary files /dev/null and b/images/races/creature/fire/bullrock.png differ diff --git a/images/races/creature/fire/cerberus.png b/images/races/creature/fire/cerberus.png new file mode 100644 index 00000000..b7b84aa0 Binary files /dev/null and b/images/races/creature/fire/cerberus.png differ diff --git a/images/races/creature/fire/giant.png b/images/races/creature/fire/giant.png new file mode 100755 index 00000000..d3fde799 Binary files /dev/null and b/images/races/creature/fire/giant.png differ diff --git a/images/races/creature/fire/ignius.png b/images/races/creature/fire/ignius.png new file mode 100644 index 00000000..d51a741f Binary files /dev/null and b/images/races/creature/fire/ignius.png differ diff --git a/images/races/creature/fire/ragnar-god-of-fire.png b/images/races/creature/fire/ragnar-god-of-fire.png new file mode 100644 index 00000000..46d30f5e Binary files /dev/null and b/images/races/creature/fire/ragnar-god-of-fire.png differ diff --git a/images/races/creature/frost/breff.png b/images/races/creature/frost/breff.png new file mode 100644 index 00000000..d1c7bffe Binary files /dev/null and b/images/races/creature/frost/breff.png differ diff --git a/images/races/creature/frost/frigus-mortis.png b/images/races/creature/frost/frigus-mortis.png new file mode 100644 index 00000000..cbf8c3fd Binary files /dev/null and b/images/races/creature/frost/frigus-mortis.png differ diff --git a/images/races/creature/frost/giant.png b/images/races/creature/frost/giant.png new file mode 100755 index 00000000..cf873bf4 Binary files /dev/null and b/images/races/creature/frost/giant.png differ diff --git a/images/races/creature/frost/kyl-god-of-frost.png b/images/races/creature/frost/kyl-god-of-frost.png new file mode 100644 index 00000000..f0c34fed Binary files /dev/null and b/images/races/creature/frost/kyl-god-of-frost.png differ diff --git a/images/races/creature/frost/mammoth.png b/images/races/creature/frost/mammoth.png new file mode 100644 index 00000000..db0a9bb4 Binary files /dev/null and b/images/races/creature/frost/mammoth.png differ diff --git a/images/races/creature/frost/warrus.png b/images/races/creature/frost/warrus.png new file mode 100644 index 00000000..07921b69 Binary files /dev/null and b/images/races/creature/frost/warrus.png differ diff --git a/images/races/creature/frost/yeti.png b/images/races/creature/frost/yeti.png new file mode 100644 index 00000000..91a7db62 Binary files /dev/null and b/images/races/creature/frost/yeti.png differ diff --git a/images/races/creature/giant-scorpion.png b/images/races/creature/giant-scorpion.png new file mode 100644 index 00000000..637fc381 Binary files /dev/null and b/images/races/creature/giant-scorpion.png differ diff --git a/images/races/creature/golem.png b/images/races/creature/golem.png new file mode 100644 index 00000000..4eba3186 Binary files /dev/null and b/images/races/creature/golem.png differ diff --git a/images/races/creature/grizzly-bear.png b/images/races/creature/grizzly-bear.png new file mode 100644 index 00000000..a5fc31c3 Binary files /dev/null and b/images/races/creature/grizzly-bear.png differ diff --git a/images/races/creature/horn-goblin.png b/images/races/creature/horn-goblin.png new file mode 100644 index 00000000..4ee6db5d Binary files /dev/null and b/images/races/creature/horn-goblin.png differ diff --git a/images/races/creature/hyena.png b/images/races/creature/hyena.png new file mode 100644 index 00000000..794e73d4 Binary files /dev/null and b/images/races/creature/hyena.png differ diff --git a/images/races/creature/jester.png b/images/races/creature/jester.png new file mode 100644 index 00000000..7869dcb1 Binary files /dev/null and b/images/races/creature/jester.png differ diff --git a/images/races/creature/lightning/giant.png b/images/races/creature/lightning/giant.png new file mode 100644 index 00000000..8ade2c66 Binary files /dev/null and b/images/races/creature/lightning/giant.png differ diff --git a/images/races/creature/lightning/herald.png b/images/races/creature/lightning/herald.png new file mode 100644 index 00000000..d98dea61 Binary files /dev/null and b/images/races/creature/lightning/herald.png differ diff --git a/images/races/creature/lightning/onkh.png b/images/races/creature/lightning/onkh.png new file mode 100644 index 00000000..cffb1cf7 Binary files /dev/null and b/images/races/creature/lightning/onkh.png differ diff --git a/images/races/creature/lightning/oskar-god-of-lightning.png b/images/races/creature/lightning/oskar-god-of-lightning.png new file mode 100644 index 00000000..3c4cda8b Binary files /dev/null and b/images/races/creature/lightning/oskar-god-of-lightning.png differ diff --git a/images/races/creature/lightning/ulwar.png b/images/races/creature/lightning/ulwar.png new file mode 100644 index 00000000..e4a41562 Binary files /dev/null and b/images/races/creature/lightning/ulwar.png differ diff --git a/images/races/creature/lightning/vento-mico.png b/images/races/creature/lightning/vento-mico.png new file mode 100644 index 00000000..b3fe321d Binary files /dev/null and b/images/races/creature/lightning/vento-mico.png differ diff --git a/images/races/creature/lightning/wyvern.png b/images/races/creature/lightning/wyvern.png new file mode 100644 index 00000000..ebdc1f7d Binary files /dev/null and b/images/races/creature/lightning/wyvern.png differ diff --git a/images/races/creature/lost-civilian.png b/images/races/creature/lost-civilian.png new file mode 100644 index 00000000..0493a915 Binary files /dev/null and b/images/races/creature/lost-civilian.png differ diff --git a/images/races/creature/nature/.png b/images/races/creature/nature/.png new file mode 100644 index 00000000..3fd8c192 Binary files /dev/null and b/images/races/creature/nature/.png differ diff --git a/images/races/creature/nature/alora-goddess-of-nature.png b/images/races/creature/nature/alora-goddess-of-nature.png new file mode 100644 index 00000000..cf44597e Binary files /dev/null and b/images/races/creature/nature/alora-goddess-of-nature.png differ diff --git a/images/races/creature/nature/erat-herba.png b/images/races/creature/nature/erat-herba.png new file mode 100644 index 00000000..062b7cd6 Binary files /dev/null and b/images/races/creature/nature/erat-herba.png differ diff --git a/images/races/creature/nature/giant.png b/images/races/creature/nature/giant.png new file mode 100755 index 00000000..d79687c0 Binary files /dev/null and b/images/races/creature/nature/giant.png differ diff --git a/images/races/creature/nature/owlbear.png b/images/races/creature/nature/owlbear.png new file mode 100644 index 00000000..6b10916a Binary files /dev/null and b/images/races/creature/nature/owlbear.png differ diff --git a/images/races/creature/nature/rune-stag.png b/images/races/creature/nature/rune-stag.png new file mode 100644 index 00000000..724f7187 Binary files /dev/null and b/images/races/creature/nature/rune-stag.png differ diff --git a/images/races/creature/netter-goblin.png b/images/races/creature/netter-goblin.png new file mode 100644 index 00000000..f505553d Binary files /dev/null and b/images/races/creature/netter-goblin.png differ diff --git a/images/races/creature/nomad.png b/images/races/creature/nomad.png new file mode 100644 index 00000000..6a26bd32 Binary files /dev/null and b/images/races/creature/nomad.png differ diff --git a/images/races/creature/older-brother.png b/images/races/creature/older-brother.png new file mode 100644 index 00000000..1dd66b27 Binary files /dev/null and b/images/races/creature/older-brother.png differ diff --git a/images/races/creature/pitchfork-patrick.png b/images/races/creature/pitchfork-patrick.png new file mode 100644 index 00000000..61ee7c57 Binary files /dev/null and b/images/races/creature/pitchfork-patrick.png differ diff --git a/images/races/creature/plague-doctor.png b/images/races/creature/plague-doctor.png new file mode 100644 index 00000000..ef46a1d5 Binary files /dev/null and b/images/races/creature/plague-doctor.png differ diff --git a/images/races/creature/poorest-knight-in-town.png b/images/races/creature/poorest-knight-in-town.png new file mode 100644 index 00000000..80750167 Binary files /dev/null and b/images/races/creature/poorest-knight-in-town.png differ diff --git a/images/races/creature/queen-arachnae.png b/images/races/creature/queen-arachnae.png new file mode 100644 index 00000000..487c2b35 Binary files /dev/null and b/images/races/creature/queen-arachnae.png differ diff --git a/images/races/creature/rat.png b/images/races/creature/rat.png new file mode 100644 index 00000000..3e8a903f Binary files /dev/null and b/images/races/creature/rat.png differ diff --git a/images/races/creature/regular-sized-combatant.png b/images/races/creature/regular-sized-combatant.png new file mode 100644 index 00000000..f0288639 Binary files /dev/null and b/images/races/creature/regular-sized-combatant.png differ diff --git a/images/races/creature/rhino.png b/images/races/creature/rhino.png new file mode 100644 index 00000000..35c85284 Binary files /dev/null and b/images/races/creature/rhino.png differ diff --git a/images/races/creature/sabertooth-tiger.png b/images/races/creature/sabertooth-tiger.png new file mode 100644 index 00000000..13abaceb Binary files /dev/null and b/images/races/creature/sabertooth-tiger.png differ diff --git a/images/races/creature/scorch-ling.png b/images/races/creature/scorch-ling.png new file mode 100644 index 00000000..e1b7d86a Binary files /dev/null and b/images/races/creature/scorch-ling.png differ diff --git a/images/races/creature/secutor.png b/images/races/creature/secutor.png new file mode 100644 index 00000000..d41307cf Binary files /dev/null and b/images/races/creature/secutor.png differ diff --git a/images/races/creature/slinger-goblin.png b/images/races/creature/slinger-goblin.png new file mode 100644 index 00000000..abc5ea1e Binary files /dev/null and b/images/races/creature/slinger-goblin.png differ diff --git a/images/races/creature/spiderling.png b/images/races/creature/spiderling.png new file mode 100644 index 00000000..e6e5eb81 Binary files /dev/null and b/images/races/creature/spiderling.png differ diff --git a/images/races/creature/stabber-goblin.png b/images/races/creature/stabber-goblin.png new file mode 100644 index 00000000..e3cfc823 Binary files /dev/null and b/images/races/creature/stabber-goblin.png differ diff --git a/images/races/creature/succubus.png b/images/races/creature/succubus.png new file mode 100644 index 00000000..4c8adfe5 Binary files /dev/null and b/images/races/creature/succubus.png differ diff --git a/images/races/creature/the-emperor.png b/images/races/creature/the-emperor.png new file mode 100644 index 00000000..09b034e6 Binary files /dev/null and b/images/races/creature/the-emperor.png differ diff --git a/images/races/creature/the-engineer.png b/images/races/creature/the-engineer.png new file mode 100644 index 00000000..4580e42e Binary files /dev/null and b/images/races/creature/the-engineer.png differ diff --git a/images/races/creature/the-grand-champion.png b/images/races/creature/the-grand-champion.png new file mode 100644 index 00000000..70d9d65c Binary files /dev/null and b/images/races/creature/the-grand-champion.png differ diff --git a/images/races/creature/training-dummy.png b/images/races/creature/training-dummy.png new file mode 100644 index 00000000..5f9c9e2a Binary files /dev/null and b/images/races/creature/training-dummy.png differ diff --git a/images/races/creature/war-elephant.png b/images/races/creature/war-elephant.png new file mode 100644 index 00000000..1993a9bd Binary files /dev/null and b/images/races/creature/war-elephant.png differ diff --git a/images/races/creature/wolf.png b/images/races/creature/wolf.png new file mode 100644 index 00000000..ee12a18b Binary files /dev/null and b/images/races/creature/wolf.png differ diff --git a/images/races/creature/younger-brother.png b/images/races/creature/younger-brother.png new file mode 100644 index 00000000..71d9fb36 Binary files /dev/null and b/images/races/creature/younger-brother.png differ diff --git a/images/races/dwarf/female-01.png b/images/races/dwarf/female-01.png new file mode 100644 index 00000000..22e04da8 Binary files /dev/null and b/images/races/dwarf/female-01.png differ diff --git a/images/races/dwarf/male-01.png b/images/races/dwarf/male-01.png new file mode 100644 index 00000000..f16f1875 Binary files /dev/null and b/images/races/dwarf/male-01.png differ diff --git a/images/races/elf/female-01.png b/images/races/elf/female-01.png new file mode 100644 index 00000000..d8dda859 Binary files /dev/null and b/images/races/elf/female-01.png differ diff --git a/images/races/elf/male-01.png b/images/races/elf/male-01.png new file mode 100644 index 00000000..2e52acf4 Binary files /dev/null and b/images/races/elf/male-01.png differ diff --git a/images/races/goblin/female-01.png b/images/races/goblin/female-01.png new file mode 100644 index 00000000..c707901d Binary files /dev/null and b/images/races/goblin/female-01.png differ diff --git a/images/races/goblin/male-01.png b/images/races/goblin/male-01.png new file mode 100644 index 00000000..88b7f476 Binary files /dev/null and b/images/races/goblin/male-01.png differ diff --git a/images/races/human/female-01.png b/images/races/human/female-01.png new file mode 100644 index 00000000..a64c44b9 Binary files /dev/null and b/images/races/human/female-01.png differ diff --git a/images/races/human/male-01.png b/images/races/human/male-01.png new file mode 100644 index 00000000..bf6e775b Binary files /dev/null and b/images/races/human/male-01.png differ diff --git a/images/races/npc/brog.png b/images/races/npc/brog.png new file mode 100644 index 00000000..74d8c914 Binary files /dev/null and b/images/races/npc/brog.png differ diff --git a/images/races/npc/doctore-varro.png b/images/races/npc/doctore-varro.png new file mode 100644 index 00000000..f514e0d0 Binary files /dev/null and b/images/races/npc/doctore-varro.png differ diff --git a/images/races/npc/grukk.png b/images/races/npc/grukk.png new file mode 100644 index 00000000..c3fa0774 Binary files /dev/null and b/images/races/npc/grukk.png differ diff --git a/images/races/npc/mira.png b/images/races/npc/mira.png new file mode 100644 index 00000000..0f0c6d06 Binary files /dev/null and b/images/races/npc/mira.png differ diff --git a/images/races/npc/mother-alora.png b/images/races/npc/mother-alora.png new file mode 100644 index 00000000..53ff6897 Binary files /dev/null and b/images/races/npc/mother-alora.png differ diff --git a/images/races/npc/nibsy.png b/images/races/npc/nibsy.png new file mode 100644 index 00000000..d9c7c1c3 Binary files /dev/null and b/images/races/npc/nibsy.png differ diff --git a/images/races/npc/oswald.png b/images/races/npc/oswald.png new file mode 100644 index 00000000..3fbb238f Binary files /dev/null and b/images/races/npc/oswald.png differ diff --git a/images/races/troll/__female-01.png b/images/races/troll/__female-01.png new file mode 100644 index 00000000..8d7d2d23 Binary files /dev/null and b/images/races/troll/__female-01.png differ diff --git a/images/races/troll/__male-01.png b/images/races/troll/__male-01.png new file mode 100644 index 00000000..9956e9b5 Binary files /dev/null and b/images/races/troll/__male-01.png differ diff --git a/images/races/troll/female-01.png b/images/races/troll/female-01.png new file mode 100644 index 00000000..b45cda3a Binary files /dev/null and b/images/races/troll/female-01.png differ diff --git a/images/races/troll/male-01.png b/images/races/troll/male-01.png new file mode 100644 index 00000000..6dca1d56 Binary files /dev/null and b/images/races/troll/male-01.png differ diff --git a/images/races/troll/troll-male-alt-1.png b/images/races/troll/troll-male-alt-1.png new file mode 100644 index 00000000..f29c0b02 Binary files /dev/null and b/images/races/troll/troll-male-alt-1.png differ diff --git a/images/races/troll/troll-male-alt-2.png b/images/races/troll/troll-male-alt-2.png new file mode 100644 index 00000000..729ec196 Binary files /dev/null and b/images/races/troll/troll-male-alt-2.png differ diff --git a/static/images/shield.png b/images/shield-1455x2329.png similarity index 100% rename from static/images/shield.png rename to images/shield-1455x2329.png diff --git a/images/ui/battleborn-logo-3405x2231.png b/images/ui/battleborn-logo-3405x2231.png new file mode 100644 index 00000000..7d086eb0 Binary files /dev/null and b/images/ui/battleborn-logo-3405x2231.png differ diff --git a/static/images/ui/button/center.jpg b/images/ui/button/center.jpg similarity index 100% rename from static/images/ui/button/center.jpg rename to images/ui/button/center.jpg diff --git a/static/images/ui/button/left.jpg b/images/ui/button/left.jpg similarity index 100% rename from static/images/ui/button/left.jpg rename to images/ui/button/left.jpg diff --git a/static/images/ui/button/right.jpg b/images/ui/button/right.jpg similarity index 100% rename from static/images/ui/button/right.jpg rename to images/ui/button/right.jpg diff --git a/static/images/ui/frame-header.jpg b/images/ui/frame-header.jpg similarity index 100% rename from static/images/ui/frame-header.jpg rename to images/ui/frame-header.jpg diff --git a/static/images/ui/frame.png b/images/ui/frame.png similarity index 100% rename from static/images/ui/frame.png rename to images/ui/frame.png diff --git a/js/_internal-tools/entitySource.js b/js/_internal-tools/entitySource.js new file mode 100644 index 00000000..f8dbe639 --- /dev/null +++ b/js/_internal-tools/entitySource.js @@ -0,0 +1,10 @@ +export const saveEntity = async (source, id, changes) => { + const response = await fetch(`/__source/${source}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id, changes }), + }); + const data = await response.json(); + if (!response.ok) throw new Error(data.error || `save failed (${response.status})`); + return data; +}; diff --git a/js/ambient.js b/js/ambient.js new file mode 100644 index 00000000..9d7f4326 --- /dev/null +++ b/js/ambient.js @@ -0,0 +1,81 @@ +let currentTrack = null; +let tracks = null; + +const getVolume = () => ($.settings?.volume?.master ?? 0.5) * ($.settings?.volume?.ambient ?? 0.25); + +const crossfade = (next) => { + if (!next || currentTrack === next) return; + + const volume = getVolume(); + const prev = currentTrack; + + next.play(); + next.fade(0, volume, 2000); + + if (prev) { + prev.fade(prev.volume(), 0, 2000); + const handleFade = () => { + if (prev.volume() <= 0.001) { + prev.stop(); + prev.off('fade', handleFade); + } + }; + prev.on('fade', handleFade); + } + + currentTrack = next; +}; + +export const init = () => { + if (!window.Howl || !window.AUDIO) return; + + tracks = { + arena: new window.Howl({ + src: [window.AUDIO['Pure Desert Wind']], + volume: 0, + loop: true, + preload: false, + }), + theWild: new window.Howl({ + src: [window.AUDIO['Summer Day In Nature']], + volume: 0, + loop: true, + preload: false, + }), + }; + + $.on('afterUpdate', (current, prev) => { + if (!tracks) return; + + // Update volume when settings change + if (currentTrack && current.settings?.volume !== prev.settings?.volume) { + currentTrack.volume(getVolume()); + } + + // Switch tracks based on game state + const inCombat = current.combat?.duration > 0; + const inTheWild = current.bossHighscore >= 15; + + // Pause ambient during combat (combat has its own SFX) + if (inCombat && currentTrack) { + currentTrack.fade(currentTrack.volume(), 0, 1000); + return; + } + + // Resume/switch ambient after combat + if (!inCombat && prev.combat?.duration > 0) { + const target = inTheWild ? tracks.theWild : tracks.arena; + crossfade(target); + return; + } + + // Initial play or the-wild transition + if (!currentTrack && current.token) { + crossfade(inTheWild ? tracks.theWild : tracks.arena); + } else if (inTheWild && currentTrack === tracks.arena) { + crossfade(tracks.theWild); + } else if (!inTheWild && currentTrack === tracks.theWild) { + crossfade(tracks.arena); + } + }); +}; diff --git a/js/app.js b/js/app.js new file mode 100644 index 00000000..b5cd78d3 --- /dev/null +++ b/js/app.js @@ -0,0 +1,135 @@ +import VERSION from '/js/version.js'; +import config from '/js/config.js'; +import { releaseNotesPageData } from '/js/constants/RELEASE_NOTES.js'; +import { DEFAULT_GAME_STATE } from '/js/constants/DEFAULT_GAME_STATE.js'; + +const loadLocalStorage = (props) => + Object.entries(props).reduce( + (a, [key, value]) => ({ + ...a, + [key]: window.localStorage.getItem(key) + ? JSON.parse(window.localStorage.getItem(key)) + : value, + }), + {}, + ); + +const SETTINGS_DEFAULT_VOLUME = { + master: 0.5, + ambient: 0.25, + sfx: 0.5, + combat: 1, +}; + +const INITIAL_COMBAT = { + teamsStartState: [], + teamsEndState: [], + events: [], + duration: 0, + winningTeam: undefined, + fightId: undefined, + audio: [], + showTeamLabels: false, + perspectiveEnabled: true, +}; + +export default { + // ── Persisted game state — the ONLY keys written to the DB. Defined once in + // /js/constants/DEFAULT_GAME_STATE.js (shared by buildSavePayload and seed-bots). ── + ...DEFAULT_GAME_STATE, + + // ── Runtime-only — NOT persisted via the game-state save. Account caches are loaded + // from the account doc on auth (read-only here; the server writes them). The rest + // is transport, plus ephemeral combat / clock / UI / session state. ── + version: VERSION, + worktree: config.WORKTREE, + combat: INITIAL_COMBAT, + liveTeams: [], + combatCards: [], + combatProjectiles: [], + combatLoot: [], // drops rolled on victory (rollLoot), shown on the reward card and granted on claim. + elapsedMilliseconds: 0, + clock: { + server: 0, // server-trusted wall-clock anchor in ms. Set by the server on auth (and re-anchored on heal). + client: 0, // client `performance.now()` reading at the same instant as `server`. Together they form the sync pair. + now: 0, // derived current server time, recomputed every 250ms as `server + (performance.now() - client)`. Read this for "what time is it on the server right now". + devOffset: 0, // tester-only ms offset folded into the anchor to jump between seasons; sent to the server so storage routing follows. + }, + season: 0, // current season number, derived from clock.now. + devSeasonOptions: [], // tester dropdown: 12 months from the real current season (set after clock sync). + premiumUntil: 0, // account-level Season Pass expiry (ms, server time). Loaded on auth; written by the purchase-pass event, not the game-state save. + isPremiumNow: false, // reactive mirror of "premium active right now" — kept fresh by the clock loop so markup can bind it. + accountStatistics: {}, // { : statsTree } — every season's mirrored stats, loaded on auth so account (lifetime) thresholds read true totals. Read-only cache. + accountAchievements: {}, // { : { : { earnedAt } } } — every season's earned achievements. Powers lifetime counts, prior-season detection, Recent. Read-only cache. + achievementReveals: [], // queue of { id, at } awaiting the center-screen reveal pop-up. + achTab: 'recent', // /achievements selected sidebar tab: 'recent' or ':'. + achReveal: null, // /achievements id pinned to the top of its category list. + achFlip: null, // /achievements id to play the locked→earned flip on (deep-link arrival only). + gameStateLoaded: false, + socket: undefined, + token: undefined, + email: '', + canTest: false, + selectedBrawlers: [], + selectPress: false, + swordTwoIn: false, + // Tester-only: an explicit combat seed typed into the fight bar; empty = random. + testerSeed: '', + maxBrawlers: 0, + tooltip: { visible: false, x: 0, y: 0, props: {} }, + keys: { alt: false }, + notifications: [], + notifyUp: true, + notifyDown: false, + notifyLeft: false, + notifyRight: true, + overlay: {}, + inventoryOpen: false, + accountId: null, + accountName: null, + pvp: { + teamplay: { + active: null, + viewed: null, + list: [], + selecting: [], + cards: [], + canJoin: false, + bpa: 1, + roomStatus: null, + controls: null, + chatOpen: false, + }, + }, + releaseNotes: releaseNotesPageData(0), + cutscene: null, + forMyLevel: true, + sheetDialog: { + heading: '', + groups: { base: [], lucky: [], modifiers: [], resistances: [], tolerance: [], other: [] }, + slots: [], + }, + settings: loadLocalStorage({ + volume: SETTINGS_DEFAULT_VOLUME, + debugOpen: false, + devbarOpen: false, + isTester: false, + showDetailedCharacterView: false, + darkMode: false, + codeOfConduct: false, + rememberMe: false, + savedEmail: '', + savedPassword: '', + // Last-used Create Teamplay selections, restored on the next open. + teamplaySettings: { + randomizedTeams: true, + brawlersPerAccount: 1, + amountOfTeams: 2, + brawlersPerTeam: 2, + levelOffset: 1, + }, + }), + page: { name: 'home', params: {} }, +}; + +export { SETTINGS_DEFAULT_VOLUME, INITIAL_COMBAT }; diff --git a/js/audio.js b/js/audio.js new file mode 100644 index 00000000..f4ad7156 --- /dev/null +++ b/js/audio.js @@ -0,0 +1,117 @@ +const audioFiles = [ + '/static/audio/Fire & Shimmer.wav', + '/static/audio/Fire Themed GUI - Hammer Of Fire.wav', + '/static/audio/Special Lootbox 13.wav', + '/static/audio/Stinger - Ominous Timpani.wav', + '/static/audio/Victory Stinger 1.wav', + '/static/audio/abilities/boom/Fire and Wood.wav', + '/static/audio/abilities/cheesyTactics/Food Use - Buff Style 1.wav', + '/static/audio/abilities/cheesyTactics/Food Use - Buff Style 2.wav', + '/static/audio/abilities/demoralizingShout/Fantasy Game Buff (1).wav', + '/static/audio/abilities/doublePersona/Magic Transition.wav', + '/static/audio/abilities/emberStrike/Fire Impact 10.wav', + '/static/audio/abilities/emberStrike/Fire Impact 2.wav', + '/static/audio/abilities/emberStrike/Fire Impact 20.wav', + '/static/audio/abilities/emberStrike/Fire Impact 8.wav', + '/static/audio/abilities/lacerate/SOW1 - Combo - Double Slash 1.wav', + '/static/audio/abilities/mindsnap/DeBuff 1.wav', + '/static/audio/abilities/mindsnap/DeBuff 2.wav', + '/static/audio/abilities/powerReady/Power Ready (14).wav', + '/static/audio/abilities/powerReady/Power Ready (17).wav', + '/static/audio/abilities/stomp/Unspecified Impact Layer (1).wav', + '/static/audio/abilities/stomp/Unspecified Impact Layer (2).wav', + '/static/audio/abilities/stomp/Unspecified Impact Layer (3).wav', + '/static/audio/abilities/warcry/Fire Themed GUI - Warrior Shout (2).wav', + '/static/audio/ambient/Pure Desert Wind.wav', + '/static/audio/ambient/Summer Day In Nature.wav', + '/static/audio/armor/Armor Layer (1).wav', + '/static/audio/armor/Armor Layer (2).wav', + '/static/audio/armor/Armor Layer (3).wav', + '/static/audio/armor/Armor Layer (4).wav', + '/static/audio/armor/Armor Layer (5).wav', + '/static/audio/armor/Armor Layer (6).wav', + '/static/audio/block/Axe Chop 1.wav', + '/static/audio/block/Axe Chop 2.wav', + '/static/audio/block/Axe Chop 3.wav', + '/static/audio/block/Axe Chop 4.wav', + '/static/audio/block/Axe Chop 5.wav', + '/static/audio/block/Axe Chop 6.wav', + '/static/audio/bow/Target Impact - Default (1).wav', + '/static/audio/dodge/Swing Whoosh (1).wav', + '/static/audio/dodge/Swing Whoosh (10).wav', + '/static/audio/dodge/Swing Whoosh (2).wav', + '/static/audio/dodge/Swing Whoosh (3).wav', + '/static/audio/dodge/Swing Whoosh (4).wav', + '/static/audio/dodge/Swing Whoosh (5).wav', + '/static/audio/dodge/Swing Whoosh (6).wav', + '/static/audio/dodge/Swing Whoosh (7).wav', + '/static/audio/dodge/Swing Whoosh (8).wav', + '/static/audio/dodge/Swing Whoosh (9).wav', + '/static/audio/potion/Drink Potion.wav', + '/static/audio/slam/Hammer Maul 1.wav', + '/static/audio/slam/Hammer Maul 2.wav', + '/static/audio/slam/Hammer Maul 3.wav', + '/static/audio/slam/Hammer Maul 4.wav', + '/static/audio/slam/Slap Style Layer (1).wav', + '/static/audio/slam/Slap Style Layer (2).wav', + '/static/audio/slam/Slap Style Layer (3).wav', + '/static/audio/slash/Simple Cut 1.wav', + '/static/audio/slash/Simple Cut 2.wav', + '/static/audio/slash/Simple Cut 3.wav', + '/static/audio/stab/Spear Stab 1.wav', + '/static/audio/stab/Spear Stab 2.wav', + '/static/audio/stab/Spear Stab 3.wav', + '/static/audio/sword/Metallic Weapon Swing (1).wav', + '/static/audio/sword/Metallic Weapon Swing (2).wav', + '/static/audio/sword/Metallic Weapon Swing (3).wav', + '/static/audio/sword/Metallic Weapon Swing (4).wav', + '/static/audio/sword/Metallic Weapon Swing (5).wav', + '/static/audio/sword/swoosh.mp3', +]; + +export const AUDIO = {}; + +audioFiles.forEach((path) => { + const filename = path + .split('/') + .pop() + .replace(/\.(wav|mp3)$/, ''); + AUDIO[filename] = path; +}); + +// Play a fractional slice [start, end] (0–1) of a clip, auto-stopping at the +// end. Howler stops a sprite once its duration elapses, so we register the +// requested range as a sprite and play it — no manual timers. Howls are cached +// per clip and segment requests queued until the audio metadata has loaded. +const segmentHowls = {}; + +export const playSoundSegment = (name, start = 0, end = 1) => { + const { Howl } = window; + const src = AUDIO[name]; + if (!Howl || !src) return; + + let entry = segmentHowls[name]; + if (!entry) { + entry = segmentHowls[name] = { howl: new Howl({ src: [src] }), loaded: false, queue: [] }; + entry.howl.once('load', () => { + entry.loaded = true; + entry.queue.splice(0).forEach((range) => playRange(entry.howl, range)); + }); + } + + entry.loaded ? playRange(entry.howl, { start, end }) : entry.queue.push({ start, end }); +}; + +const sfxVolume = () => ($.settings?.volume?.sfx ?? 0.5) * ($.settings?.volume?.master ?? 0.5); + +const playRange = (howl, { start, end }) => { + const durationMs = howl.duration() * 1000; + const from = Math.min(Math.max(start, 0), 1) * durationMs; + const length = (Math.min(Math.max(end, 0), 1) - Math.min(Math.max(start, 0), 1)) * durationMs; + if (length <= 0) return; + const sprite = `${from}-${length}`; + howl._sprite[sprite] = [from, length]; + howl.volume(sfxVolume(), howl.play(sprite)); +}; + +export default AUDIO; diff --git a/js/boot.js b/js/boot.js new file mode 100644 index 00000000..8d7239d2 --- /dev/null +++ b/js/boot.js @@ -0,0 +1,975 @@ +import vibe from '@ape-egg/vibe'; +import { boot as vibeBoot } from '@ape-egg/vibe/boot'; +import { Howl } from 'howler'; + +import appState, { INITIAL_COMBAT } from '/js/app.js'; +import config, { isTesterEmail } from '/js/config.js'; +import VERSION from '/js/version.js'; +import { getCookie, formatReleaseDate, onKeyPress, deepMerge } from '/js/helpers.js'; +import { releaseNotesPageData } from '/js/constants/RELEASE_NOTES.js'; +import { init as initCombatLoop } from '/js/combat-loop.js'; +import { init as initSocket, saveNow } from '/js/connectSocket.js'; +import { fetchMyActiveTeamplay } from '/js/teamplay.js'; +import { init as initAmbient } from '/js/ambient.js'; +import { initInputMode } from '/js/inputMode.js'; +import { seasonArena } from '/js/seasonArena.js'; +import CHARACTERS from '/js/constants/CHARACTERS.js'; +import ABILITIES from '/js/constants/ABILITIES.js'; +import EQUIPMENT from '/js/constants/EQUIPMENT.js'; +import { calculateCombatStatsByCharacter, incStat, mergeStats } from '/js/utils.js'; +import { ALL_ACHIEVEMENTS, ACHIEVEMENTS_BY_ID, achProgress } from '/js/constants/ACHIEVEMENTS.js'; +import { + getLevelByExperience, + getExperienceByLevel, + getCurrentExperienceAtLevel, + getExperienceForNextLevel, + allowedNumberOfBrawlers, + allowedNumberOfPotions, + isAccountPremium, + getExperienceReward, + MAX_LEVEL, +} from '/js/level.js'; +import AUDIO, { playSoundSegment } from '/js/audio.js'; +import { correctHealth } from '/js/equipment.js'; +import { + equipmentTooltipProps, + abilityTooltipProps, + combatStatsToList, + statusTooltipProps, +} from '/js/tooltip.js'; +import { STAT_DESCRIPTIONS } from '/js/constants/STATS.js'; +import { + seasonNumber, + seasonName, + seasonMeta, + seasonLabel, + seasonStart, + seasonEnd, + seasonProgress, + downtimeStart, + msUntilNextSeason, + msUntilDowntime, + isDowntime, + passDiscount, + passPrice, + formatEUR, + PASS_PRICE, +} from '/js/seasons.js'; +import '/js/loadout.js'; + +// Twelve seasons starting at the REAL current season (offset stripped) — so the +// tester can jump forward and back, but never before the true current season. +const buildSeasonOptions = (server) => { + const base = seasonNumber(server - ($.clock.devOffset || 0)); + return Array.from({ length: 12 }, (_, i) => { + const n = base + i; + const month = new Date(seasonStart(n)).toLocaleString('en-US', { + month: 'short', + year: 'numeric', + timeZone: 'UTC', + }); + return { number: n, label: `S${n} — ${month}` }; + }); +}; + +// Move the synced clock so clock.now lands on `target`, persist the offset, and +// reload — auth then re-routes storage to that season and the whole UI follows. +const applyDevClock = (target) => { + const realNow = ($.clock.now || Date.now()) - ($.clock.devOffset || 0); + window.localStorage.setItem('devClockOffset', String(target - realNow)); + window.location.reload(); +}; + +// The Heirloom is the level-1 Battle Pass reward, so only pass owners get it. +// New accounts start past the level-1 claim (accountRewards = 1), so grant it on +// load (and on pass purchase) instead — once per season, idempotent. +const grantHeirloom = () => { + if (!$.isPremiumNow) return; + if ($.seasonPass.heirloom || $.inventory.some((i) => i.id === 'heirloom')) return; + $.inventory = [...$.inventory, EQUIPMENT('heirloom')]; + $.seasonPass = { ...$.seasonPass, heirloom: true }; + const heirloom = EQUIPMENT('heirloom', true); + window.notify?.success?.('acquired!', { + equipment: { name: heirloom.name, element: heirloom.element }, + }); +}; + +const loadGameState = async (token) => { + try { + const { + gameState, + serverTimestampSnapshot, + accountId, + email, + accountName, + season, + premiumUntil, + accountStatistics, + accountAchievements, + } = await $.socket.sendAsync('user/authenticate', { + token, + clientVersion: VERSION, + isDev: config.IS_DEV, + timeOffset: $.clock.devOffset || 0, + }); + $.accountStatistics = accountStatistics || {}; + $.accountAchievements = accountAchievements || {}; + if (gameState) { + if (gameState.characters) $.characters = gameState.characters; + if (gameState.inventory) $.inventory = gameState.inventory; + if (gameState.materials) $.materials = gameState.materials; + if (gameState.statistics) $.statistics = gameState.statistics; + if (gameState.achievements) $.achievements = gameState.achievements; + if (gameState.experience) $.experience = gameState.experience; + if (gameState.coins !== undefined) $.coins = gameState.coins; + if (gameState.accountRewards) $.accountRewards = gameState.accountRewards; + if (gameState.potions !== undefined) $.potions = gameState.potions; + if (gameState.bossHighscore !== undefined) $.bossHighscore = gameState.bossHighscore; + // Merge onto the default skeleton, never replace: buildings' children are saved + // independently via diff dot-paths, so a never-yet-touched building (e.g. palaestra + // before its first assignment) is simply absent from the persisted doc. + if (gameState.buildings) + $.buildings = deepMerge(JSON.parse(JSON.stringify($.buildings)), gameState.buildings); + if (gameState.seasonPass) + $.seasonPass = deepMerge(JSON.parse(JSON.stringify($.seasonPass)), gameState.seasonPass); + } + if (accountId) $.accountId = accountId; + if (email) $.email = email; + $.accountName = accountName || null; + $.canTest = config.IS_DEV || isTesterEmail(email); + $.premiumUntil = premiumUntil || 0; + if (season) $.season = season; + if (serverTimestampSnapshot) { + const server = serverTimestampSnapshot + ($.clock.devOffset || 0); + $.clock = { ...$.clock, server, client: performance.now(), now: server }; + $.season = seasonNumber(server); + $.isPremiumNow = $.premiumUntil > 0 && server < $.premiumUntil; + $.devSeasonOptions = buildSeasonOptions(server); + } + grantHeirloom(); + $.gameStateLoaded = true; + fetchMyActiveTeamplay(); + } catch ({ error }) { + window.notify?.(error); + $.token = undefined; + document.cookie = 'token=; Max-Age=0; path=/'; + } +}; + +// window.__ROUTE__ is injected per dynamic page by vite.config (transformIndexHtml). +const parseRoute = () => { + const path = window.location.pathname; + const template = window.__ROUTE__; + if (!template) return { route: path, routeParams: {} }; + const pathSegments = path.split('/'); + const routeParams = {}; + template.split('/').forEach((segment, i) => { + if (segment.startsWith(':')) routeParams[segment.slice(1)] = pathSegments[i]; + }); + return { route: template, routeParams }; +}; + +export default () => { + const { route, routeParams } = parseRoute(); + const pageName = + route + .replace(/^\/|\/$/g, '') + .replace(/:(\w+)/g, '$1') + .replace(/\//g, '-') || 'home'; + + // Window globals for components and services + window.config = config; + window.Howl = Howl; + window.AUDIO = AUDIO; + window.playSoundSegment = playSoundSegment; + window.CHARACTERS = CHARACTERS; + window.ABILITIES_FN = ABILITIES; + window.EQUIPMENT_FN = EQUIPMENT; + window.EQUIPMENT = EQUIPMENT; + window.equipmentTooltipProps = equipmentTooltipProps; + window.abilityTooltipProps = abilityTooltipProps; + + // Season helpers for markup bindings — all derive from clock.now so they react + // as the clock ticks (and as the tester dev clock jumps). + window.seasonNumber = seasonNumber; + window.seasonName = seasonName; + window.seasonMeta = seasonMeta; + window.seasonLabel = seasonLabel; + window.seasonProgress = seasonProgress; + window.isDowntime = isDowntime; + window.passDiscount = passDiscount; + window.passPrice = passPrice; + window.formatEUR = formatEUR; + window.PASS_PRICE = PASS_PRICE; + window.isPremium = () => $.premiumUntil > 0 && ($.clock.now || 0) < $.premiumUntil; + window.grantHeirloom = grantHeirloom; + // "Days left of current season" = playable days until downtime begins (the + // season's end), not until the next season starts. + window.daysLeftInSeason = () => + Math.max(0, Math.ceil(msUntilDowntime($.clock.now || 0) / 86_400_000)); + window.msUntilNextSeason = msUntilNextSeason; + window.formatDuration = (ms) => { + const total = Math.max(0, Math.ceil((ms || 0) / 1000)); + const pad = (n) => String(n).padStart(2, '0'); + const d = Math.floor(total / 86_400); + const h = Math.floor((total % 86_400) / 3600); + const m = Math.floor((total % 3600) / 60); + const s = total % 60; + return d > 0 ? `${d}d ${pad(h)}:${pad(m)}:${pad(s)}` : `${pad(h)}:${pad(m)}:${pad(s)}`; + }; + + // Season Pass purchase — covers the current season. Payment is faked until + // Steam/Stripe; the notification shows the (discounted) amount for the record. + window.purchasePass = async () => { + if (window.isPremium()) return; + const price = passPrice($.clock.now || 0); + try { + const potionsBefore = allowedNumberOfPotions(); + const { premiumUntil } = await $.socket.sendAsync('user/purchase-pass', { + token: $.token, + timeOffset: $.clock.devOffset || 0, + }); + $.premiumUntil = premiumUntil || 0; + $.isPremiumNow = window.isPremium(); + grantHeirloom(); + // Retroactively fill the premium potion slots earned on levels already climbed. + const potionSlotsGained = allowedNumberOfPotions() - potionsBefore; + if (potionSlotsGained > 0) + $.potions = Math.min($.potions + potionSlotsGained, allowedNumberOfPotions()); + window.notify?.success?.('Season Pass unlocked for this season!'); + window.notify?.info?.(`${formatEUR(price)} paid`); + if (potionSlotsGained > 0) + window.notify?.info?.( + `+${potionSlotsGained} Potion slot${potionSlotsGained > 1 ? 's' : ''} unlocked`, + { icon: 'potion' }, + ); + } catch (e) { + window.notify?.(e?.error || 'Purchase failed'); + } + }; + // Tester premium toggle — persists to the account both ways so removal sticks + // across reloads (clear-pass drops it, purchase-pass grants the current season). + window.devTogglePremium = async () => { + const event = window.isPremium() ? 'user/clear-pass' : 'user/purchase-pass'; + try { + const { premiumUntil } = await $.socket.sendAsync(event, { + token: $.token, + timeOffset: $.clock.devOffset || 0, + }); + $.premiumUntil = premiumUntil || 0; + $.isPremiumNow = window.isPremium(); + grantHeirloom(); + } catch (e) { + window.notify?.(e?.error || 'Could not toggle premium'); + } + }; + window.seasonSchedule = () => { + const n = seasonNumber($.clock.now || 0); + return { + number: n, + name: seasonName(n), + start: seasonStart(n), + end: downtimeStart(n), + nextStart: seasonEnd(n), + msUntilNext: msUntilNextSeason($.clock.now || 0), + }; + }; + + // Tester clock control. Jump to the start of a season (offset months from now) + // or into the current season's downtime; persist the offset and reload so auth + // re-routes storage to that season (fresh start) and the UI follows. + window.devJumpToSeason = (targetSeason) => { + const target = seasonStart(targetSeason) + 60 * 1000; + applyDevClock(target); + }; + window.devJumpToDowntime = () => { + const n = seasonNumber($.clock.now || 0); + applyDevClock(downtimeStart(n) + 60 * 1000); + }; + window.devResetClock = () => { + window.localStorage.removeItem('devClockOffset'); + window.location.reload(); + }; + + // Takes `characters` explicitly so a binding that passes $.characters tracks it + // as a dependency — Vibe doesn't track $ reads made inside a called function, so + // the array must be referenced in the binding expression for healing to re-enable. + window.brawlerKnockedOut = (uuid, characters = $.characters) => { + const ref = characters.find((c) => c.uuid === uuid); + if (!ref) return false; + try { + return CHARACTERS(ref, true).combatStats.currentHealth <= 0; + } catch { + return false; + } + }; + + window.anySelectedBrawlerKnockedOut = (characters = $.characters) => + $.selectedBrawlers.some((uuid) => brawlerKnockedOut(uuid, characters)); + + window.fightDisabledReason = (allowed) => { + if (!$.selectedBrawlers.length) { + return allowed > 1 + ? `Select up to ${allowed} brawlers to fight` + : 'Select a brawler to fight'; + } + if (window.anySelectedBrawlerKnockedOut()) { + return 'One or more of your brawlers attending is at 0 or lower life'; + } + return null; + }; + + window.showFightTooltip = (el) => { + if (window.teamplayElsewhere?.() === 'completed') return; + const reason = window.fightDisabledReason($.currentFight?.maxBrawlers || 1); + if (reason) { + window.showTooltip({ description: reason, plain: true }, el, { direction: 'up', lock: true }); + } + }; + + window.showAbilityTooltip = (el, ability) => { + const charRef = $.characters[0]; + const char = charRef ? CHARACTERS(charRef, true) : null; + const stats = char ? calculateCombatStatsByCharacter(char) : null; + window.showTooltip(abilityTooltipProps(ability, stats), el, { direction: 'up', lock: true }); + }; + + window.showStatusTooltip = (el, status) => { + window.showTooltip(statusTooltipProps(status), el, { direction: 'up', lock: true }); + }; + + window.showStatTooltip = (el, key) => { + const stat = STAT_DESCRIPTIONS[key]; + if (!stat) return; + window.showTooltip(stat, el, { direction: 'up', lock: true }); + }; + + window.iconCellTooltip = (el, tip) => { + if (!tip) return; + if (tip.crystal) return window.showCrystalTooltip(el); + if (tip.reward) return window.showRewardTooltip(el, tip.reward); + if (tip.stat) return window.showStatTooltip(el, tip.stat); + if (tip.info) return window.showTooltip(tip.info, el, { direction: 'up', lock: true }); + }; + + // A hybrid (multi-element) ability paints its element colours as a spectrum + // rather than a single hue. Builds a CSS gradient from whatever elements are + // present (canonical order), in the tone the surface needs: 'face' (light tile + // background), 'glyph' (mid-tone icon fill), 'fill' (vivid progress fill), + // 'wash' (translucent tooltip base), 'icon' (the all-elements heading star — + // a conic sweep matching --element-rainbow, identical to the Heirloom's for + // the full set). Returns '' for <2 elements so single-element abilities keep + // their existing single-colour rendering untouched. + const ELEMENT_ORDER = ['fire', 'lightning', 'nature', 'frost', 'earth']; + window.elementSpectrum = (elements = [], mode = 'face') => { + const els = ELEMENT_ORDER.filter((e) => elements?.includes(e)); + if (els.length < 2) return ''; + if (mode === 'icon') { + const ring = [...els, els[0]].map((e) => `var(--element-${e})`).join(', '); + return `conic-gradient(from 90deg, ${ring})`; + } + const stop = { + face: (e) => `oklch(from var(--element-${e}) 0.95 0.045 h)`, + glyph: (e) => `oklch(from var(--element-${e}) 0.6 0.095 h)`, + fill: (e) => `oklch(from var(--element-${e}) 0.48 0.08 h)`, + wash: (e) => `oklch(from var(--element-${e}) l c h / 0.16)`, + }[mode]; + return `linear-gradient(${mode === 'wash' ? 90 : 105}deg, ${els.map(stop).join(', ')})`; + }; + + window.showSignatureTooltip = (el) => + window.showTooltip( + { + name: "Can't be removed", + description: + 'This ability is a signature ability provided by one of your equipped weapons. It cannot be removed from your ability sequence.

It is possible to move it to change the order of your abilities.', + }, + el, + { direction: 'up', lock: true }, + ); + + window.showCrystalTooltip = (el) => + window.showTooltip( + { name: 'Crystal', description: 'The main currency of Battleborn Brawlers.' }, + el, + { direction: 'up', lock: true }, + ); + + window.showEquipmentTooltip = (el, eq) => { + const { id, level } = eq; + const item = EQUIPMENT(id, true, level ? { overrides: { level } } : undefined); + window.showTooltip(equipmentTooltipProps(item), el.querySelector('eq-link') || el, { + direction: 'up', + lock: true, + }); + }; + + window.showCharacterScalingTooltip = (el, charId, ch, charScaling, equipScaling, isEnemy) => { + const charLevel = charScaling ? ch.level : 1; + const equipLevel = equipScaling ? ch.level : 0; + const ref = CHARACTERS(charId, false, { + overrides: { + npc: isEnemy, + level: charLevel, + equipment: { + mainHand: { overrides: { level: equipLevel } }, + offHand: { overrides: { level: equipLevel } }, + armor: { overrides: { level: equipLevel } }, + }, + }, + }); + const char = CHARACTERS(ref, true); + window.showTooltip( + { + name: char.name, + level: char.level || 0, + stats: combatStatsToList(calculateCombatStatsByCharacter(char)), + basicAbilities: [], + specialAbilities: [], + }, + el.querySelector('eq-link') || el, + { direction: 'up', lock: true }, + ); + }; + // ── Achievements ────────────────────────────────────────────────────────── + // Lifetime stats = every prior season's mirrored tree folded together, then the + // live current-season tree on top, so account (cross-season) thresholds read true + // running totals and can fire mid-game. + window.lifetimeStats = () => { + const current = seasonLabel($.season); + const prior = Object.entries($.accountStatistics || {}) + .filter(([label]) => label !== current) + .reduce((acc, [, tree]) => mergeStats(acc, tree), {}); + return mergeStats(prior, $.statistics || {}); + }; + + window.achById = (id) => ACHIEVEMENTS_BY_ID[id]; + window.achEarnedThisSeason = (id) => !!$.achievements?.[id]; + window.achEarnedInPriorSeason = (id) => { + const current = seasonLabel($.season); + return Object.entries($.accountAchievements || {}).some( + ([label, map]) => label !== current && map?.[id], + ); + }; + window.achEarnedEver = (id) => + window.achEarnedThisSeason(id) || window.achEarnedInPriorSeason(id); + // Seasonal counts as earned only when earned THIS season (it re-arms each season); + // account counts as earned once it's been earned in any season ever. + window.achEarned = (ach) => + ach.scope === 'seasonal' ? window.achEarnedThisSeason(ach.id) : window.achEarnedEver(ach.id); + window.achProgressLive = (ach) => + achProgress(ach, ach.scope === 'seasonal' ? $.statistics : window.lifetimeStats()); + + // Titles unlocked = the reward title of every achievement earned (ever) — derived, + // never stored separately. + window.unlockedTitles = () => + ALL_ACHIEVEMENTS.filter((a) => a.reward?.title && window.achEarnedEver(a.id)).map( + (a) => a.reward.title, + ); + + window.showAchievementTooltip = (el, ach) => { + const { value, threshold, met } = window.achProgressLive(ach); + const fmt = (n) => Number(n).toLocaleString(); + const status = met + ? 'Completed' + : `Progress — ${fmt(Math.floor(value))} / ${fmt(threshold)}`; + window.showTooltip( + { name: ach.title, description: `${ach.description}

${status}` }, + el, + { + direction: 'up', + lock: true, + }, + ); + }; + + const playReveal = (sound) => { + try { + new Howl({ + src: [AUDIO[sound]], + volume: ($.settings?.volume?.sfx ?? 0.5) * ($.settings?.volume?.master ?? 0.5), + }).play(); + } catch {} + }; + + // Tap the center pop-up → persist the earn, then deep-link to its place on the + // achievements page where the locked→earned flip plays. + window.followAchievementReveal = async (id) => { + $.achievementReveals = []; + await saveNow(); + location.href = `/achievements?reveal=${id}`; + }; + window.dismissAchievementReveal = (id) => + ($.achievementReveals = $.achievementReveals.filter((r) => r.id !== id)); + // The deep-link flip fires its own SFX off the CSS animation phases (no timers). + window.achRevealSfx = (e) => { + if (e.animationName.includes('Shake')) playReveal('Unspecified Impact Layer (1)'); + if (e.animationName.includes('Flip')) playReveal('Victory Stinger 1'); + }; + + const commitAchievement = (ach) => { + const now = $.clock.now || Date.now(); + $.achievements = { ...$.achievements, [ach.id]: { earnedAt: now } }; + // A seasonal achievement earned in a prior season just notifies on repeat; every + // genuine first-time unlock (all account + first-ever seasonal) gets the reveal. + if (ach.scope === 'seasonal' && window.achEarnedInPriorSeason(ach.id)) { + window.notify?.success?.(`${ach.title} earned again`, { icon: ach.icon }); + playReveal('Fire & Shimmer'); + } else { + // Denormalise the display fields so the reveal markup binds direct loop-alias + // properties (@[r.icon]) — a function call in an each-row name-binding aborts the + // row render in Vibe. + $.achievementReveals = [ + ...$.achievementReveals, + { id: ach.id, at: now, icon: ach.icon, title: ach.title, description: ach.description }, + ]; + playReveal('Fire Themed GUI - Hammer Of Fire'); + } + }; + + // Evaluate every not-yet-earned achievement against its scope's stat tree and unlock + // any whose threshold is now met. Runs whenever stats move (see afterUpdate below). + window.checkAchievements = () => { + if (!$.gameStateLoaded) return; + const lifetime = window.lifetimeStats(); + ALL_ACHIEVEMENTS.forEach((ach) => { + const tree = ach.scope === 'seasonal' ? $.statistics : lifetime; + if (!achProgress(ach, tree).met) return; + const already = + ach.scope === 'seasonal' ? $.achievements?.[ach.id] : window.achEarnedEver(ach.id); + if (already) return; + commitAchievement(ach); + }); + }; + + window.INITIAL_COMBAT = INITIAL_COMBAT; + window.calculateCombatStatsByCharacter = calculateCombatStatsByCharacter; + window.getLevelByExperience = getLevelByExperience; + window.getExperienceByLevel = getExperienceByLevel; + window.getCurrentExperienceAtLevel = getCurrentExperienceAtLevel; + window.getExperienceForNextLevel = getExperienceForNextLevel; + window.getExperienceReward = getExperienceReward; + window.allowedNumberOfBrawlers = allowedNumberOfBrawlers; + window.allowedNumberOfPotions = allowedNumberOfPotions; + window.isAccountPremium = isAccountPremium; + window.isDev = config.IS_DEV; + + window.formatReleaseDate = formatReleaseDate; + window.releaseNotesGoTo = (page) => { + $.releaseNotes = releaseNotesPageData(page); + document.querySelector('release-notes-scroll')?.scrollTo({ top: 0 }); + }; + window.releaseNotesPrev = () => releaseNotesGoTo($.releaseNotes.page - 1); + window.releaseNotesNext = () => releaseNotesGoTo($.releaseNotes.page + 1); + window.releaseNotesBack = () => ($.overlay = { name: 'GameMenu' }); + + // Escape closes the top-most closable modal before falling back to the game menu. + // Component-local modals register a { open, close } probe keyed by name (re-mounts + // overwrite rather than stack). Mandatory modals like AccountName never register, so + // Escape can't dismiss them. + window.__escapeModals ||= {}; + window.registerEscapeModal = (key, open, close) => { + window.__escapeModals[key] = { open, close }; + }; + + // A brawler is "busy" while it's a participant in the current combat. Returns the + // activity descriptor (label + the overlay to open on click) or null when free. + window.brawlerActivity = (uuid) => { + if (!uuid || !$.combat?.duration) return null; + const fighting = $.combat.teamsStartState?.[0]?.combatants?.some((c) => c.uuid === uuid); + if (!fighting) return null; + const settled = $.elapsedMilliseconds >= $.combat.duration; + return { label: settled ? 'View outcome' : 'Brawling..', spinner: !settled, overlay: 'Combat' }; + }; + + // Committed to a teamplay (waiting room, live, or a finished one not yet + // claimed/left) — locks the account out of other fights. + window.accountInTeamplay = () => !!$.pvp.teamplay.active; + // Returns the teamplay id if this brawler is one of mine in the active teamplay. + window.teamplayBrawler = (uuid) => { + const tp = $.pvp.teamplay.active; + if (!tp?.teams) return null; + const mine = tp.teams.some((team) => + team.slots.some((slot) => slot.owner_id === $.accountId && slot.brawler?.uuid === uuid), + ); + return mine ? tp._id : null; + }; + // Badge label/action depend on whether the session is waiting, fighting, or done. + window.teamplayBrawlerLabel = () => { + const status = $.pvp.teamplay.active?.status; + return status === 'live' ? 'Brawling' : status === 'completed' ? 'View outcome' : 'In teamplay'; + }; + window.teamplayBrawlerClick = (uuid) => { + const tp = $.pvp.teamplay.active; + if (tp && (tp.status === 'live' || tp.status === 'completed')) window.resumeTeamplayCombat?.(); + else if (teamplayBrawler(uuid)) location.href = '/teamplay/' + teamplayBrawler(uuid); + }; + // A teamplay fight running or finished elsewhere — surfaced on the fight bar so you + // can keep brawling here while opening that combat. Returns its status, else null. + window.teamplayElsewhere = () => { + const status = $.pvp.teamplay.active?.status; + return status === 'live' || status === 'completed' ? status : null; + }; + + // Tester-only: copy the current combat's seed so a run can be reproduced by pasting + // it back into the fight bar's seed input. + window.copyCombatSeed = () => { + const seed = $.combat?.seed; + if (!seed) return; + navigator.clipboard?.writeText(seed); + notify.success('Seed copied'); + }; + + window.isPotionBrewer = (uuid) => + $.accountRewards >= 5 && $.buildings.medicum.assignedBrawlers.includes(uuid); + window.isPalaestraTrainer = (uuid) => + $.accountRewards >= 10 && $.buildings.palaestra.assignedBrawlers.includes(uuid); + + // Busy brawlers route to their activity (the combat overlay) instead of the + // detail page. Free brawlers let the link navigate normally. + window.brawlerClick = (e, uuid) => { + const activity = brawlerActivity(uuid); + if (!activity) return; + e?.preventDefault(); + $.overlay = { name: activity.overlay }; + }; + + window.selectBrawler = (e, uuid) => { + // Cleared here — not on pointerup — so the release lands in the same update + // batch as the selection change; sword one keeps its animation instead of + // restarting when [armed] hands over to :not(:disabled). + $.selectPress = false; + if (!$.maxBrawlers || !uuid) return; + e?.preventDefault(); + e?.stopPropagation(); + if (brawlerActivity(uuid)) return; + // A brawler tied up brewing potions at the Medicum or training at the + // Palaestra is unavailable for fights; free them via that page's cross first. + if (isPotionBrewer(uuid) || isPalaestraTrainer(uuid)) return; + if ($.selectedBrawlers.includes(uuid)) { + $.selectedBrawlers = $.selectedBrawlers.filter((id) => id !== uuid); + } else if ($.selectedBrawlers.length < $.maxBrawlers) { + $.selectedBrawlers = [...$.selectedBrawlers, uuid]; + } + // Rebuild immediately so the slot flips in the same frame as the click — the + // flip flag survives because committedKeys is only advanced post-paint. + if (window.updateFightSlots) updateFightSlots(); + }; + + // Brawler card-hand selection (shared by the FightButton fight bar and the + // Medicum's brewer picker). The brewer is excluded so they can't be drafted + // into a fight while tied up at the Medicum. + const characterToCard = (ref) => { + const char = CHARACTERS(ref, true); + return { + id: ref.uuid, + uuid: ref.uuid, + name: char.name, + image: char.image, + x: char.mugshot.x, + y: char.mugshot.y, + }; + }; + + window.brawlHandCards = (characters = $.characters, selectedBrawlers = $.selectedBrawlers) => + (characters || []) + .filter( + (c) => + !selectedBrawlers.includes(c.uuid) && + !isPotionBrewer(c.uuid) && + !isPalaestraTrainer(c.uuid), + ) + .map(characterToCard); + + window.handCardPress = (e) => { + const uuid = e.target.closest('[data-card-id]')?.dataset.cardId; + if (!uuid) return; + $.selectPress = + $.combat.duration === 0 && !brawlerKnockedOut(uuid) && !anySelectedBrawlerKnockedOut(); + }; + window.handCardCancel = () => ($.selectPress = false); + window.handCardClick = (e) => { + const uuid = e.target.closest('[data-card-id]')?.dataset.cardId; + if (uuid) selectBrawler(e, uuid); + }; + + if (!window.__brawlHandReleaseBound) { + window.__brawlHandReleaseBound = true; + document.addEventListener('pointerup', (e) => { + if ($.selectPress && !e.target.closest?.('[data-card-id]')) $.selectPress = false; + }); + } + + // Restore token from cookie BEFORE vibe initializes so the first hydration + // already knows we're logged in — avoids a login-screen flash before the + // ready hook would otherwise restore it. + const cookie = getCookie(); + + // Compiled mode is detectable by the absence of the [vibe-fouc] marker — the + // compiler strips it at build, runtime keeps it until PHASE_READY. Capture it + // now, before hydration removes it, so the COMPILED badge reflects load time. + const compiled = !document.querySelector('[vibe-fouc], .vibe-fouc'); + + window.$ = vibe( + { + ...appState, + compiled, + token: cookie?.token, + page: { name: pageName, params: routeParams }, + }, + { debug: false, noCache: false }, + ); + + // Force synchronous boot so window.$ is the real proxy immediately + // (vibe() defers boot to a microtask, but page scripts need $ right away) + window.$ = vibeBoot(); + + // Tester season clock — persisted so a jump survives reloads (e.g. to test the + // downtime screen after refresh). Folded into the clock anchor on auth. + $.clock.devOffset = +window.localStorage.getItem('devClockOffset') || 0; + + // Media queries + const queries = { + desktop: '(min-width: 1200px)', + tablet: '(min-width: 768px) and (max-width: 1199px)', + smartphone: '(max-width: 767px)', + landscape: '(orientation: landscape)', + portrait: '(orientation: portrait)', + hoverable: '(hover: hover)', + }; + + const mqls = {}; + const updateMedia = () => { + const media = {}; + Object.keys(mqls).forEach((key) => { + media[key] = mqls[key].matches; + }); + try { + $.mqs = media; + } catch {} + }; + Object.keys(queries).forEach((key) => { + mqls[key] = window.matchMedia(queries[key]); + mqls[key].addEventListener('change', updateMedia); + }); + + // Initialize services (keystroke handling lives in component, mounted via Layout) + initInputMode(); + initCombatLoop(); + initSocket(); + initAmbient(); + + $.on('ready', () => { + updateMedia(); + + // Apply dark mode from saved settings + document.body.toggleAttribute('dark', !!$.settings?.darkMode); + document.body.toggleAttribute('light', !$.settings?.darkMode); + + // Discrete key actions all ride the global `keys` state seeded by + // . Registering them here in boot — never in a component script — + // keeps the listeners alive for the page's lifetime in BOTH runtime and + // compiled modes (a component-script `$.on` is dropped by the compiled + // component-lifecycle pass, which is why pressing `i` did nothing there). + onKeyPress('keyi', () => { + $.inventoryOpen = !$.inventoryOpen; + window.hideTooltip?.(); + }); + + onKeyPress('escape', () => { + if ($.promptModal?.open) return window.promptModalCancel?.(); + const modal = Object.values(window.__escapeModals).find((m) => m.open()); + if (modal) return modal.close(); + if (!$.gameKeyboardDisabled) { + $.overlay = Object.keys($.overlay).length ? {} : { name: 'GameMenu' }; + } + }); + + // Dev chords stay a direct listener: modifier combos + preventDefault don't + // fit the single-key rising-edge `keys` model. Match on e.code so we don't + // have to deal with Option producing the special `∂` character on macOS. + document.addEventListener('keydown', (e) => { + if ((window.isDev || $.settings.isTester) && e.shiftKey && e.altKey && e.code === 'KeyD') { + e.preventDefault(); + $.settings.devbarOpen = !$.settings.devbarOpen; + } + if ((window.isDev || $.settings.isTester) && e.shiftKey && e.altKey && e.code === 'KeyS') { + e.preventDefault(); + $.vibeStateInspector = !$.vibeStateInspector; + } + }); + + // Holding Alt/Option reveals extra detail in tooltips. The pressed state + // lives in global `keys` state so components can react to it; afterUpdate + // mirrors it onto a `body[alt-down]` attribute that drives the CSS reveal. + // Clear on blur so the state doesn't stick if the key-up lands elsewhere. + const setAlt = (on) => $.keys.alt !== on && ($.keys = { ...$.keys, alt: on }); + document.addEventListener('keydown', (e) => e.key === 'Alt' && setAlt(true)); + document.addEventListener('keyup', (e) => e.key === 'Alt' && setAlt(false)); + window.addEventListener('blur', () => setAlt(false)); + + // Client clock. Once authenticated we run off the server anchor; before that + // (the login screen) we approximate from the client's own wall time so the + // Season tag and overlay can render pre-login. The server re-anchors on auth. + setInterval(() => { + $.clock.now = $.clock.server + ? $.clock.server + (performance.now() - $.clock.client) + : Date.now() + ($.clock.devOffset || 0); + const n = seasonNumber($.clock.now); + if (n !== $.season) $.season = n; + const prem = $.premiumUntil > 0 && $.clock.now < $.premiumUntil; + if (prem !== $.isPremiumNow) $.isPremiumNow = prem; + }, 250); + }); + + $.on('afterUpdate', (current, prev) => { + if (current.keys.alt !== prev.keys.alt) { + document.body.toggleAttribute('alt-down', current.keys.alt); + } + + if (current.bossHighscore !== prev.bossHighscore) { + document.body.toggleAttribute('the-wild', (current.bossHighscore || 0) >= 15); + if (current.bossHighscore) + incStat('progression.bossHighscore.amount', { max: current.bossHighscore }); + } + + if ( + current.combat?.fightId !== prev.combat?.fightId || + current.bossHighscore !== prev.bossHighscore || + current.season !== prev.season + ) { + const fight = + current.combat?.fightId && + seasonArena(current.season).find((f) => f.id === current.combat.fightId); + document.body.toggleAttribute( + 'combat-the-wild', + fight ? fight.minLevel >= 16 : (current.bossHighscore || 0) >= 15, + ); + } + + if (current.cutscene !== prev.cutscene) { + document.body.toggleAttribute('cutscene-open', !!current.cutscene); + } + + const justConnected = current.socket && !prev.socket && current.token; + const justGotToken = current.token && !prev.token && current.socket; + if (justConnected || justGotToken) { + loadGameState(current.token); + } + + try { + const level = getLevelByExperience(current.experience || 0); + const prevLevel = getLevelByExperience(prev.experience || 0); + if (level !== prevLevel) incStat('progression.level.amount', { max: level }); + if (level > prevLevel && prev.experience > 0) { + $.overlay = { name: 'AccountProgression' }; + $.characters.forEach((c) => { + try { + correctHealth(c); + } catch {} + }); + try { + new Howl({ + src: [AUDIO['Fire & Shimmer']], + volume: ($.settings?.volume?.sfx ?? 0.5) * ($.settings?.volume?.master ?? 0.5), + }).play(); + } catch {} + } + } catch {} + + // Sync data-src → src (runtime mode ships raw @[…] in eager URL attrs, which + // the browser would prefetch before hydration — data-src defers that to here) + document.querySelectorAll('img[data-src], video[data-src]').forEach((el) => { + const ds = el.dataset.src; + if (ds && !ds.endsWith('/') && !ds.includes('@[') && el.src !== ds && !el.src.endsWith(ds)) + el.src = ds; + }); + }); + + // Unlock achievements the moment their underlying stats cross the threshold. Gated on + // stats moving (or the just-loaded transition) so it isn't re-run on every flush; the + // commit reassigns $.achievements, which the page + reveal bind to reactively. + $.on('afterUpdate', (current, prev) => { + if (!current.gameStateLoaded) return; + if ( + current.statistics !== prev.statistics || + current.accountStatistics !== prev.accountStatistics || + current.gameStateLoaded !== prev.gameStateLoaded + ) + window.checkAchievements(); + }); + + // Account-progression carousel: scroll to the first claimable level each time the + // overlay opens. The trigger lives here (runs once per page in both modes) because + // compiled mode executes a component's script only once — re-arming on every open + // has to come from a persistent subscription. afterUpdate lands it in compiled + // mode (slides are pre-rendered, scrollable as soon as the overlay shows); runtime + // mode renders the slides via DOM mutation afterwards, so afterDomMutation lands it. + let scrollToClaimable = false; + let animateScroll = false; + + // easeOutBack: eases to the target, overshooting slightly past it before settling. + const easeOutBack = (t) => { + const c1 = 1.70158; + return 1 + (c1 + 1) * (t - 1) ** 3 + c1 * (t - 1) ** 2; + }; + + // Glide the carousel to centre a slide with an overshoot. Scroll-snap is switched + // off for the tween — mandatory snapping would fight the per-frame scrollLeft — then + // restored, re-holding the target (itself a snap point). + const glideToSlide = (el, target) => { + const to = Math.max(0, target.offsetLeft - (el.clientWidth - target.offsetWidth) / 2); + const from = el.scrollLeft; + if (Math.abs(to - from) < 1) return; + el.style.scrollSnapType = 'none'; + const startedAt = performance.now(); + const frame = (now) => { + const t = Math.min(1, (now - startedAt) / 520); + el.scrollLeft = from + (to - from) * easeOutBack(t); + if (t < 1) requestAnimationFrame(frame); + else el.style.scrollSnapType = ''; + }; + requestAnimationFrame(frame); + }; + + const scrollProgression = (animate) => { + const el = document.querySelector('[progression-scroll] slides'); + if (!el) return false; + // On reopen the track mounts in stages — the full-width bar + // lands first (one scrollable child), so gate on the whole slide set being + // present, else scrollIntoView centers the bar → mid-track (level 13). + const slides = el.querySelectorAll('slide'); + if (slides.length < MAX_LEVEL) return false; + // Reading scrollWidth flushes layout — wait until the track is scrollable. + if (el.scrollWidth <= el.clientWidth) return false; + const level = getLevelByExperience($.experience); + const target = slides[Math.min($.accountRewards + 1, level) - 1]; + if (!target) return false; + if (animate) glideToSlide(el, target); + else target.scrollIntoView({ behavior: 'instant', block: 'nearest', inline: 'center' }); + document.documentElement.style.setProperty( + '--progression-sb', + el.offsetHeight - el.clientHeight + 'px', + ); + return true; + }; + + $.on('afterUpdate', (current, prev) => { + const opening = current.overlay?.name === 'AccountProgression'; + if (opening && prev.overlay?.name !== 'AccountProgression') { + scrollToClaimable = true; + animateScroll = false; + } + // A claim bumps accountRewards — glide to the next claimable card with an overshoot + // (in runtime mode the slides also rebuild, resetting scrollLeft, so re-assert it). + if (opening && current.accountRewards !== prev.accountRewards) { + scrollToClaimable = true; + animateScroll = true; + } + if (!opening) scrollToClaimable = false; + if (scrollToClaimable && scrollProgression(animateScroll)) scrollToClaimable = false; + }); + $.on('afterDomMutation', () => { + if (scrollToClaimable && scrollProgression(animateScroll)) scrollToClaimable = false; + }); +}; diff --git a/js/combat-loop.js b/js/combat-loop.js new file mode 100644 index 00000000..edc72747 --- /dev/null +++ b/js/combat-loop.js @@ -0,0 +1,623 @@ +import { COMBAT_TICK_TIME } from '/js/constants/APP.js'; +import STATUS_EFFECTS, { STATUS_ORDER, isStandaloneStatus } from '/js/constants/STATUS_EFFECTS.js'; +import { seededRandom } from '/js/utils.js'; +import { + COMBAT_RING_TILT, + COMBAT_OUTER_RING_TILT, + COMBAT_RING_DEPTH_SCALE, + COMBAT_RING_BASE_RADIUS, + COMBAT_CARD_ALPHA_NEAR, + COMBAT_CARD_ALPHA_FAR, +} from '/js/constants/APP.js'; + +// Lead time (ms) for showing a freshly applied status. The status-pop +// animation (animations.css, 400ms) is clearly visible from its overshoot +// peak at ~60%, so this lead makes the chip read as arriving exactly when +// the ability connects, like the hit-marker flash. +const STATUS_POP_LEAD = 150; + +export const getGeometry = (n) => ({ + scale: 1 / (1 + Math.log2(Math.max(1, n / 8))), +}); + +// Perspective foreshortening of the ring, gated per-combat by combat.perspectiveEnabled. +// Off only when explicitly disabled (the preview switch); every real combat tilts by +// default. Applied at display time so it composes with rotateCombatToViewer's rotation. +const ringTilt = () => ($.combat?.perspectiveEnabled === false ? 1 : COMBAT_RING_TILT); +// The outer team-label ring's tilt — only ever a CSS cue (no JS positions ride it). +const outerTilt = () => ($.combat?.perspectiveEnabled === false ? 1 : COMBAT_OUTER_RING_TILT); + +// Team counts divisible by 4 (4, 8, 12, …) otherwise seat a team on the pure vertical +// axis (dead top and bottom). We spin the ring half a slot (rotation/2 = 180/teamCount) so +// the teams straddle the vertical centre line evenly — none on it, half each side — and +// the player lands lower-left (315° for 4 teams → the X; 292.5° for 8). Applies in both +// modes (it's a layout choice, not a perspective cue). ringPosition's angle convention +// (x = sinθ, y = cosθ); applied at display time, so it composes with the viewer rotation. +export const ringAngleOffset = (teamCount) => + teamCount >= 4 && teamCount % 4 === 0 ? 180 / teamCount : 0; + +// Perspective depth scaling: nearer combatants (bottom of the ring, +y) render larger, +// farther ones (top, -y) smaller — linear in the un-squashed circle-space y (the true +// depth, already viewer-rotated). No-op when perspective is off. +const depthScale = (y) => + $.combat?.perspectiveEnabled === false + ? 1 + : 1 + COMBAT_RING_DEPTH_SCALE * (y / COMBAT_RING_BASE_RADIUS); + +// Glass-card opacity by depth: most translucent nearest the camera (bottom of the ring, +// at the NEAR floor) and most opaque farthest away (top, at FAR). Full FAR (opaque) when +// perspective is off, so cards read as ordinary glass. +const cardAlpha = (y) => { + if ($.combat?.perspectiveEnabled === false) return COMBAT_CARD_ALPHA_FAR; + const near = (y / COMBAT_RING_BASE_RADIUS + 1) / 2; + return COMBAT_CARD_ALPHA_FAR + (COMBAT_CARD_ALPHA_NEAR - COMBAT_CARD_ALPHA_FAR) * near; +}; + +// Backdrop-blur ("glassiness") factor 0..1: none at the front (closest, no glass) up to +// full at the back. Full glass when perspective is off. +const cardBlur = (y) => { + if ($.combat?.perspectiveEnabled === false) return 1; + return 1 - (y / COMBAT_RING_BASE_RADIUS + 1) / 2; +}; + +// Compute enriched per-combatant render props from the raw liveTeams shape. +// `upcoming` is the same combatant in the next pending event (if it lands +// within STATUS_POP_LEAD) — its statuses render in place of the current ones. +export const enrichCombatant = (c, ti, ci, elapsed, scale, team, upcoming) => { + const pos = c.position || { x: 0, y: 0, rot: 0 }; + // The ring is foreshortened at display time: positions are computed and viewer-rotated + // on a flat circle (so rotateCombatToViewer's rigid rotation stays valid), then every y + // is squashed by the ring tilt here, turning the circle into a vertical-minor ellipse + // without distorting the rotation maths or squashing the sprites. + const tilt = ringTilt(); + // 4-team perspective spins the ring onto the diagonals (see ringAngleOffset): rotate the + // circle position by the offset, then squash y. rot picks up the same offset so depth (z) + // and facing follow. offset is 0 in every other case, leaving positions untouched. + const offDeg = ringAngleOffset($.liveTeams?.length || 0); + const offRad = (offDeg * Math.PI) / 180; + const cosO = Math.cos(offRad); + const sinO = Math.sin(offRad); + const x = pos.x * cosO + pos.y * sinO; + // ry is the rotated circle-space depth (pre-squash) — the true near/far signal once the + // diagonal spin is applied, so the depth cues (size, alpha, blur) read it, not pos.y. + const ry = pos.y * cosO - pos.x * sinO; + const y = ry * tilt; + const rot = pos.rot + offDeg; + + // Stack cards by the same near/far depth the glass cues read (ry): nearer the camera + // (larger ry, bottom of the ring) ⇒ higher z-index, so a closer card always overlaps a + // farther one. The old z keyed off facing angle, so overlapping cards mis-stacked. + const z = 1 + Math.round(((ry / COMBAT_RING_BASE_RADIUS + 1) / 2) * 999); + const angleDiff = ((rot - 0 + 540) % 360) - 180; + const facingRight = angleDiff < 0; + + const abilitiesCopied = c.abilitiesCopied || []; + const totalTime = + (c.abilities || []).reduce((acc, a) => acc + (a.ticks || 0), 0) * COMBAT_TICK_TIME || 1; + const individualProgress = + ((c.statuses?.knockedOut ? c.statuses.knockedOut : elapsed) / totalTime) % 1; + + const anims = c.animations || []; + const activeByName = (name) => + anims.find((a) => a.start < elapsed && a.end > elapsed && a.vfxName === name); + + const attackAnim = anims.find( + (a) => + a.start < elapsed && + a.end > elapsed && + [ + 'basicAttackFast', + 'basicAttackRegular', + 'basicAttackSlow', + 'pounce', + 'whirlwind', + 'boom', + ].includes(a.vfxName), + ); + + // Compute attack start/end points (for sprite charge animation) — the target rides the + // same diagonal spin + squash as the combatant so the lunge vector stays true. + const tgtX = attackAnim?.targetX ?? pos.x; + const tgtY = attackAnim?.targetY ?? pos.y; + const tx = tgtX * cosO + tgtY * sinO; + const ty = (tgtY * cosO - tgtX * sinO) * tilt; + const dX = tx - x, + dY = ty - y; + const distance = Math.hypot(dX, dY) || 1; + const ux = dX / distance, + uy = dY / distance; + const pouncing = attackAnim?.vfxName === 'pounce'; + let anticipate = 0; + if (attackAnim?.vfxName === 'basicAttackSlow') anticipate = 50; + if (attackAnim?.vfxName === 'basicAttackRegular') anticipate = 30; + if (attackAnim?.vfxName === 'basicAttackFast') anticipate = 10; + if (pouncing) anticipate = 16; + const attackStartX = x - ux * anticipate; + const attackStartY = y - uy * anticipate; + const step = Math.min(pouncing ? 14 : 5, distance); + const attackEndX = x + ux * step; + const attackEndY = y + uy * step; + const attackDuration = (attackAnim?.end || 0) - (attackAnim?.start || 0); + + const isStunned = (c.statuses?.stunned?.ticks || 0) > 0 || (c.statuses?.confused?.ticks || 0) > 0; + const immobilized = isStunned || (c.statuses?.cocooned?.ticks || 0) > 0; + + // Single active attack animation class (gated by not-stunned) + const attackClass = !isStunned && attackAnim ? attackAnim.vfxName : ''; + const attackAnimationName = attackClass ? `bb-${attackClass}` : 'none'; + const attackAnimationDuration = attackClass === 'whirlwind' ? '500ms' : `${attackDuration}ms`; + const stompAnim = activeByName('stomp'); + const stomping = !isStunned && !!stompAnim; + const stompDuration = stompAnim ? stompAnim.end - stompAnim.start : 0; + const catchAnim = activeByName('catchThrow'); + const catching = !isStunned && !!catchAnim; + const catchDuration = catchAnim ? catchAnim.end - catchAnim.start : 0; + const hatching = !!activeByName('hatch'); + const hurtActive = !!activeByName('hurt'); + const blockActive = !!activeByName('block'); + const attackBlockedActive = !!activeByName('attackBlocked'); + const whirlwindActive = !!activeByName('whirlwind'); + const spinAnim = activeByName('spin'); + const spinning = !isStunned && !!spinAnim; + const spinDuration = spinAnim ? spinAnim.end - spinAnim.start : 0; + const attackDodgedActive = !!activeByName('attackDodged'); + const attackMissedActive = !!activeByName('attackMissed'); + const chargeAnim = activeByName('abilityCharge'); + const recoverAnim = activeByName('abilityRecover'); + const releasingActive = !!activeByName('abilityRelease'); + const animProgress = (a) => + a ? Math.min(1, (elapsed - a.start) / Math.max(1, a.end - a.start)) : 0; + + // Health-bar floaters — collect all active hurt/armorHurt/heal/attackMissed animations. + const floaters = anims + .filter( + (a) => + a.start < elapsed && + a.end > elapsed && + [ + 'hurt', + 'armorHurt', + 'heal', + 'fullHealth', + 'mend', + 'attackMissed', + 'attackDodged', + 'attackBlocked', + ].includes(a.vfxName), + ) + .map((a) => { + const healthFraction = a.healthFraction || 0; + // <40% of total health: normal. 41-80%: +25%. 81%+: +50%. Crits add a + // further 25% on top. + const sizeScale = + (healthFraction < 0.4 ? 1 : healthFraction <= 0.8 ? 1.25 : 1.5) * (a.isCritical ? 1.25 : 1); + return { + id: a.id, + vfxName: a.vfxName, + amount: a.amount || 0, + prevented: !!a.prevented, + isCritical: !!a.isCritical, + healthFraction, + sizeScale, + random: seededRandom(0, 1, a.id || '0', 0.001), // stable pseudo-random from the (deterministic) id + dir: facingRight ? -1 : 1, + }; + }); + + // Within the lead window, render the upcoming event's statuses wholesale — + // adds, expiries and threshold conversions all flip atomically, one lead + // ahead of the tick they belong to. Converting pairs sit adjacent in + // STATUS_DISPLAY_ORDER, so a conversion swaps in place without re-fanning. + const displayStatuses = upcoming?.statuses || c.statuses; + + const buildStatus = (k, def) => { + const rec = displayStatuses?.[k]; + return { + statusKey: k, + key: `${k}-${rec?.instance || 0}`, + name: def.name || def.text, + description: def.description || '', + icon: + def.kind === 'threshold' ? STATUS_EFFECTS[def.convertsInto]?.icon || def.icon : def.icon, + category: def.category, + standalone: isStandaloneStatus(k), + permanent: !!def.permanent, + ticks: rec?.ticks || 0, + value: rec?.value || 0, + max: rec?.max || 0, + announce: rec?.announce, + }; + }; + + // Threshold + permanent (End game) statuses show while their value is set; + // tick-counted ones disappear the moment their countdown hits 0. + const statusDisplay = STATUS_ORDER.map((k) => buildStatus(k, STATUS_EFFECTS[k])).filter((s) => + s.max > 0 || s.permanent ? s.value > 0 : s.ticks > 0, + ); + + // Flatten ability cells for the AbilityBar (keyed by uuid, sized by ticks). + const abilityCells = abilitiesCopied.map((a, i) => { + const chainLink = a.chainLink || 0; + const chainDividers = + chainLink > 1 + ? Array.from( + { length: chainLink - 1 }, + (_, j) => `${(((j + 1) / chainLink) * 100).toFixed(4)}%`, + ) + : []; + return { + uuid: `${a.id || 'a'}-${i}`, + id: a.id || '', + name: a.name || '', + statusEffects: a.statusEffects || [], + icon: a.icon || 'claw', + ticks: a.ticks || 1, + elements: a.elements || [], + chainDividers, + }; + }); + + // Knocked-out: filter grayscale (status flag is set mid-combat; HP fallback covers post-combat / restored states) + const knockedOut = !!c.statuses?.knockedOut || (c.combatStats?.currentHealth || 0) <= 0; + + // Provocation-weighted chance of being targeted, among still-living teammates. + // Mirrors the combat picker: an attack on this team lands on each member with + // probability provocation / sum(team provocation). Recomputes live as allies fall. + const livingTeammates = (team?.combatants || []).filter( + (m) => (m.combatStats?.currentHealth || 0) > 0, + ); + const teamProvocation = livingTeammates.reduce( + (acc, m) => acc + (m.combatStats?.provocation || 0), + 0, + ); + const provocation = c.combatStats?.provocation || 0; + const provocationChance = !knockedOut && teamProvocation > 0 ? provocation / teamProvocation : 0; + const showProvocation = livingTeammates.length > 1 && !knockedOut; + + // Precompute image URL (main is `/images/races/{image}`, here `/static/images/races/{image}`) + const imageUrl = c.image ? `/static/images/races/${c.image}` : ''; + + const size = c.size || 1; + const spriteHeight = 144 * size; + + return { + cardId: `${ti}-${ci}`, + id: c.id || `${ti}-${ci}`, + name: c.name, + damage: c.damage || 0, + currentHealth: c.combatStats?.currentHealth || 0, + bufferedHealth: c.combatStats?.bufferedHealth || 0, + maxHealth: c.combatStats?.maxHealth || 0, + currentArmor: c.combatStats?.currentArmor || 0, + maxArmor: c.combatStats?.maxArmor || 0, + armorHit: floaters.some((f) => f.vfxName === 'armorHurt'), + provocationChance: Math.round(provocationChance * 100), + showProvocation, + knockedOut, + immobilized, + facingRight, + x, + y, + z, + rot, + scale: scale * depthScale(ry), + glassAlpha: cardAlpha(ry), + glassBlur: cardBlur(ry), + // Sprite offsets / vars for position transform + spriteHeight, + attackClass, + attackAnimationName, + attackAnimationDuration, + stomping, + stompDuration, + stompAnimId: stomping ? stompAnim.id : '', + stompProgress: stomping ? animProgress(stompAnim) : 0, + catching, + catchDuration, + hatching, + attackStartX, + attackStartY, + attackEndX, + attackEndY, + attackDuration, + dir: facingRight ? 1 : -1, + attackAnimId: attackAnim?.id || '', + hurtActive, + blockActive, + attackBlocked: attackBlockedActive, + whirlwindActive, + spinning, + spinDuration, + attackDodgedActive, + attackMissedActive, + charging: !!chargeAnim, + chargeProgress: animProgress(chargeAnim), + recovering: !!recoverAnim, + recoverProgress: animProgress(recoverAnim), + releasing: releasingActive, + floaters, + statusDisplay, + abilityCells, + individualProgress, + image: c.image || '', + imageUrl, + uuid: c.uuid, + spawned: !!c.spawned, + }; +}; + +export const init = () => { + let animationId = null; + let lastTimestamp = 0; + let audioQueue = []; + let playingNonce = null; // replayNonce of the combat currently mounted; a new one (re)starts + const retriggered = new Map(); // cardId -> last animId seen + const shaken = new Set(); // floater ids that already shook the screen + + const updateCombatDisplay = () => { + const teams = $.liveTeams; + if (!teams?.length) return; + + const totalCombatants = teams.reduce((a, t) => a + (t.combatants?.length || 0), 0); + const { scale } = getGeometry(totalCombatants); + document.documentElement.style.setProperty('--combat-scale', scale); + document.documentElement.style.setProperty('--combat-tilt', ringTilt()); + document.documentElement.style.setProperty('--combat-outer-tilt', outerTilt()); + + const elapsed = $.elapsedMilliseconds; + + const nextEvent = $.combat.events?.[0]; + const lookahead = + nextEvent && nextEvent.eventTimestamp - elapsed < STATUS_POP_LEAD ? nextEvent.teams : null; + + const cards = teams.flatMap((team, ti) => { + return ( + team.combatants?.map((c, ci) => { + // Card frame tracks toughness — count-scale (P/E) and boss bonus, clamped to + // [1, 2]. Low-`power` adds (eggs, chaff) drop to 0.75 so they read as minor; + // brawlers and regular foes stay at 1. + const power = c.power ?? 1; + const frame = + power < 1 + ? 0.75 + : Math.min(2, Math.max(1, (c.countScale ?? 1) * power * (c.boss ? 1.5 : 1))); + return enrichCombatant( + c, + ti, + ci, + elapsed, + scale * frame, + team, + lookahead?.[ti]?.combatants?.[ci], + ); + }) || [] + ); + }); + + $.combatCards = cards; + + // Arena-level thrown projectiles (Catch!'s dynamite, etc.) live in the same + // animation stream as sprite VFX. Collect the ones in flight this frame and + // hand them to the projectile layer; CSS keyframes drive the arc + spin. + $.combatProjectiles = teams.flatMap((team) => + (team.combatants || []).flatMap((c) => + (c.animations || []) + .filter((a) => a.projectile && a.start <= elapsed && a.end > elapsed) + .map((a) => { + // Same display-time transform as the combatants: spin onto the diagonals + // (4-team perspective) then foreshorten, so projectiles fly across the plane. + const tilt = ringTilt(); + const offRad = (ringAngleOffset($.liveTeams?.length || 0) * Math.PI) / 180; + const cosO = Math.cos(offRad); + const sinO = Math.sin(offRad); + const startX = a.startX * cosO + a.startY * sinO; + const startY = (a.startY * cosO - a.startX * sinO) * tilt; + const endX = a.endX * cosO + a.endY * sinO; + const endY = (a.endY * cosO - a.endX * sinO) * tilt; + const dx = endX - startX; + const dist = Math.hypot(dx, endY - startY); + return { + id: a.id, + icon: a.icon, + startX, + startY, + endX, + endY, + arcHeight: a.trajectory === 'arc' ? Math.min(100, dist * 0.2) : 0, + spin: (a.spin || 0) * (dx >= 0 ? 1 : -1), + duration: a.end - a.start, + }; + }), + ), + ); + + // A single hit landing 81%+ of the target's total health shakes the whole + // combat — once per hit, keyed by the floater's id. A Stomp shakes too, fired + // at the foot-slam (90% through the bb-stomp keyframe) and keyed by its anim id. + cards.forEach((c) => { + c.floaters.forEach((f) => { + if (f.vfxName === 'hurt' && f.healthFraction > 0.8 && !shaken.has(f.id)) { + shaken.add(f.id); + window.shakeCombat?.(); + } + }); + if (c.stompProgress >= 0.9 && !shaken.has(c.stompAnimId)) { + shaken.add(c.stompAnimId); + window.shakeCombat?.(); + } + }); + + // Retrigger attack animation by toggling animation-name via a DOM tickle. + // Walk through enriched combatants and compare attackAnimId to what we last set. + cards.forEach((c, idx) => { + const last = retriggered.get(c.cardId); + if (c.attackAnimId && c.attackAnimId !== last) { + retriggered.set(c.cardId, c.attackAnimId); + window.retriggerCombatantAnim?.(idx); + } else if (!c.attackAnimId && last) { + retriggered.set(c.cardId, ''); + } + }); + }; + + window.retriggerCombatantAnim = (idx) => { + const el = document.querySelectorAll('combatant-sprite')[idx]; + if (!el) return; + // Vibe's hydrate does setAttribute('style', ...) every flush, wiping any inline + // animation-name we set. Force a reflow so the browser commits the 'none' state + // synchronously — then clearing it makes the CSS animation restart fresh before + // Vibe's next microtask-flush replaces the style attribute. + el.style.animationName = 'none'; + void el.offsetWidth; + el.style.animationName = ''; + }; + + window.shakeCombat = () => { + const el = document.querySelector('combat-stage'); + if (!el) return; + // Restart the keyframe even if a previous shake is still mid-flight. + el.removeAttribute('shaking'); + void el.offsetWidth; + el.setAttribute('shaking', ''); + }; + + const playSfx = (sfx) => { + // Pick the variant deterministically from the (seeded) sfx id so a rewatch plays + // the identical sound sequence — a fully reproducible replay, audio included. + const variant = sfx.variants?.[seededRandom(0, sfx.variants.length - 1, sfx.id || '0')]; + const src = window.AUDIO?.[variant]; + if (!src || !window.Howl) return; + try { + new window.Howl({ + src: [src], + volume: ($.settings?.volume?.combat ?? 1) * ($.settings?.volume?.master ?? 0.5), + }).play(); + } catch {} + }; + + const loop = (timestamp) => { + if (!lastTimestamp) lastTimestamp = timestamp; + const deltaTime = timestamp - lastTimestamp; + $.elapsedMilliseconds += deltaTime * ($.combatSpeed || 1); + lastTimestamp = timestamp; + + // Advance through every event whose tick has elapsed — not just one per frame. + // Under frame drops (long fights), several ticks can pass between frames; if we + // consumed only one, the displayed combat would lag behind the real-time clock + // and then snap to the finish, which reads as a speed-up. + let due = 0; + while ($.combat.events[due] && $.elapsedMilliseconds > $.combat.events[due].eventTimestamp) { + due++; + } + if (due > 0) { + $.liveTeams = $.combat.events[due - 1].teams; + $.combat.events = $.combat.events.slice(due); + } + + while (audioQueue.length && audioQueue[0].start <= $.elapsedMilliseconds) { + playSfx(audioQueue.shift()); + } + + // Re-enrich every tick (cheap, keeps anim state fresh) + updateCombatDisplay(); + + if ($.elapsedMilliseconds > $.combat.duration) { + $.liveTeams = $.combat.teamsEndState; + updateCombatDisplay(); + cancelAnimationFrame(animationId); + animationId = null; + + // Spectating (live or a re-watch) never touches my roster — I'm not in this fight, + // and a replay of a past one must not overwrite my current HP. + if (!$.combat.spectator) + $.characters.forEach((character) => { + const myCharacter = $.liveTeams[0]?.combatants?.find((c) => c.uuid === character.uuid); + if (myCharacter) { + // Floored at 0 — overkill drives currentHealth negative, but my stored + // roster HP must never go below empty (it surfaces as a negative HP %). + character.overrides.combatStats.currentHealth = Math.max( + 0, + myCharacter.combatStats.currentHealth - myCharacter.combatStats.healingReceived, + ); + } + }); + return; + } + + animationId = requestAnimationFrame(loop); + }; + + const pauseCombat = () => { + cancelAnimationFrame(animationId); + animationId = null; + }; + const resumeCombat = () => { + if ($.combat.duration > 0 && $.elapsedMilliseconds < $.combat.duration) { + lastTimestamp = 0; + animationId = requestAnimationFrame(loop); + } + }; + + document.addEventListener('pauseCombat', pauseCombat); + document.addEventListener('resumeCombat', resumeCombat); + // Force a single repaint after a display setting (e.g. the perspective toggle) changes + // while the loop is idle — a live fight already re-enriches every frame, but a paused or + // finished board needs the nudge to reflect the new tilt. + document.addEventListener('redrawCombat', updateCombatDisplay); + + $.on('afterUpdate', (current, prev) => { + // (Re)start whenever a combat with a *new* replayNonce mounts — covers the first open + // AND the spectator "re-watch" reassigning $.combat mid-overlay (prev already had a + // duration, so a !prev.combat.duration check would miss it). Keyed on the primitive + // nonce, not object identity: Vibe re-clones current.combat every flush the live loop + // slices events, so a reference check would restart the fight on every frame. + if (current.combat?.duration > 0 && current.combat.replayNonce !== playingNonce) { + playingNonce = current.combat.replayNonce; + if (animationId) cancelAnimationFrame(animationId); + animationId = null; + lastTimestamp = 0; + retriggered.clear(); + shaken.clear(); + + // Reopened combats (teamplay "View outcome" / live rejoin) carry resumeAt — the + // real-time playhead — so the fight picks up where it actually is instead of + // replaying from the top. A fresh fight has no resumeAt and starts at 0. + const resumeAt = Math.max(0, current.combat.resumeAt || 0); + + // Already over: paint the final board and don't run the clock. The end-of-fight + // HP writeback is the server's authority for teamplay, so we must not re-run it. + if (resumeAt >= current.combat.duration) { + $.elapsedMilliseconds = current.combat.duration; + audioQueue = []; + $.liveTeams = current.combat.teamsEndState; + updateCombatDisplay(); + return; + } + + $.elapsedMilliseconds = resumeAt; + // Drop the sounds for the part we skipped so a resume doesn't burst them at once. + audioQueue = [...(current.combat.audio || [])] + .filter((a) => a.start >= resumeAt) + .sort((a, b) => a.start - b.start); + // Seek the board to the playhead so the opening frames don't flash before the + // loop catches up (no-op for a fresh fight, where resumeAt is 0). + let due = 0; + while ($.combat.events[due] && resumeAt > $.combat.events[due].eventTimestamp) due++; + $.liveTeams = due > 0 ? $.combat.events[due - 1].teams : current.combat.teamsStartState; + if (due > 0) $.combat.events = $.combat.events.slice(due); + updateCombatDisplay(); + animationId = requestAnimationFrame(loop); + return; + } + + if ( + !animationId && + !current.combat?.duration && + current.combat?.teamsStartState !== prev.combat?.teamsStartState + ) { + $.elapsedMilliseconds = 0; + $.liveTeams = current.combat?.teamsStartState || []; + updateCombatDisplay(); + } + }); +}; diff --git a/js/combat.js b/js/combat.js new file mode 100644 index 00000000..c90a0c70 --- /dev/null +++ b/js/combat.js @@ -0,0 +1,1342 @@ +import { ABILITY_PRIORITY, COMBAT_TICK_TIME } from '/js/constants/APP.js'; +import { + calculateCombatStatsByCharacter, + prepareCombatant, + ringPosition, + seededRandom, + seededWeightedIndex, +} from '/js/utils.js'; +import VFX from '/js/constants/VFX.js'; +import SFX from '/js/constants/SFX.js'; +import { + TYPE, + DOT_HIT_DAMAGE_FRACTION, + DOT_TOTAL_DAMAGE_FRACTION, +} from '/js/constants/ABILITIES.js'; +import CHARACTERS from '/js/constants/CHARACTERS.js'; +import STATUS_EFFECTS from '/js/constants/STATUS_EFFECTS.js'; + +const VALUE_STATUS_FIELDS = [ + 'damageMultiplierIncoming', + 'damageMultiplierOutgoing', + 'hitChanceModifierIncoming', + 'hitChanceModifierOutgoing', +]; + +const VALUE_STATUS_KEYS = Object.entries(STATUS_EFFECTS) + .filter(([, def]) => VALUE_STATUS_FIELDS.some((f) => typeof def[f] === 'number')) + .map(([key]) => key); + +// Reactive-trigger statuses (Riposte, and future Thorns/crit-punishers) carry a +// `trigger` config instead of a stat modifier. They apply, decay and display like +// value statuses, but resolveTriggers fires their effect when their event lands +// on the holder. +const TRIGGER_STATUS_KEYS = Object.entries(STATUS_EFFECTS) + .filter(([, def]) => def.trigger) + .map(([key]) => key); + +// Statuses an ability grants to itself/its team — stat buffs and trigger buffs. +const SELF_STATUS_KEYS = [...new Set([...VALUE_STATUS_KEYS, ...TRIGGER_STATUS_KEYS])]; + +// Negative statuses a cleanse strips. endGame is permanent (the sudden-death +// failsafe) so it's never cleared; thresholds keep their tolerance ceiling and +// only have their built-up value reset. +const DEBUFF_KEYS = Object.entries(STATUS_EFFECTS) + .filter(([, def]) => def.category === 'debuff' && !def.permanent) + .map(([key]) => key); + +const cleanseDebuffs = (combatant) => { + DEBUFF_KEYS.forEach((key) => { + const s = combatant.statuses[key]; + combatant.statuses[key] = + STATUS_EFFECTS[key].kind === 'threshold' ? { ...s, value: 0 } : { ticks: 0, value: 0 }; + }); +}; + +const sumStatusField = (statuses, field) => + VALUE_STATUS_KEYS.reduce((acc, key) => { + if (typeof STATUS_EFFECTS[key][field] !== 'number') return acc; + return acc + (statuses?.[key]?.value || 0); + }, 0); + +const damageTakenBoost = (statuses) => sumStatusField(statuses, 'damageMultiplierIncoming'); +const damageDealtBoost = (statuses) => sumStatusField(statuses, 'damageMultiplierOutgoing'); +const hitChanceTakenModifier = (statuses) => sumStatusField(statuses, 'hitChanceModifierIncoming'); +const hitChanceDealtModifier = (statuses) => sumStatusField(statuses, 'hitChanceModifierOutgoing'); + +// Elemental attacks hit slightly harder than plain physical ones, then the +// target's resistance to that element (a percentage) blunts the blow. Physical +// attacks (no element) are unchanged. +const ELEMENTAL_DAMAGE_BONUS = 0.15; +const elementalMultiplier = (ability, target) => { + const element = ability.elements?.[0]; + if (!element) return 1; + const resistance = target.combatStats.resistances?.[element] || 0; + return (1 + ELEMENTAL_DAMAGE_BONUS) * Math.max(0, 1 - resistance / 100); +}; + +// Ability status tuples are [key, factor]. The factor scales the status's +// magnitude by the ability's ticks — buildup for thresholds, duration for direct +// effects/buffs (default 1 = one per tick). For Uninterruptable the factor is its +// proc chance instead. +const statusTuple = (ability, key) => ability.statusEffects?.find(([k]) => k === key); +const hasStatus = (ability, key) => !!statusTuple(ability, key); +const statusFactor = (ability, key) => statusTuple(ability, key)?.[1] ?? 1; +const statusTicks = (ability, key) => Math.floor(ability.ticks * statusFactor(ability, key)); + +// Tick damage a wounding/venomous hit carries into its Bleeding/Poisoned value. +const dotValue = (combatant, ability) => + Math.floor( + ability?.damage + ? combatant.combatStats.damage * ability.damage * DOT_HIT_DAMAGE_FRACTION + : combatant.combatStats.damage * DOT_TOTAL_DAMAGE_FRACTION, + ); + +const applyValueStatus = (recipient, currentAbility, key) => { + const def = STATUS_EFFECTS[key]; + const value = VALUE_STATUS_FIELDS.map((f) => def[f]).find((v) => typeof v === 'number'); + const prev = recipient.statuses[key] || { ticks: 0, value: 0 }; + recipient.statuses[key] = { + ticks: prev.ticks + statusTicks(currentAbility, key), + value, + element: currentAbility.elements?.[0], + // A trigger status can carry a spawn spec from the ability that applied it, + // so resolveTriggers knows what to summon when its event lands. + ...(currentAbility.spawn ? { spawn: currentAbility.spawn } : {}), + }; +}; + +// Ability-granted stats (Block → +blockChance, Powershot → +crit) are applied +// when the ability starts — before this tick's attacks resolve — and removed +// when it ends, after them. Buffs therefore cover attacks on both boundary +// ticks; on a tick where one ability hands over to the next, both stat sets +// are briefly live (accepted: chained identical buffs double-count that tick). +const applyAbilityStats = (combatant, ability) => { + Object.entries(ability.combatStats || {}).forEach(([key, value]) => { + combatant.combatStats[key] = (combatant.combatStats[key] || 0) + value; + }); +}; + +const removeAbilityStats = (combatant, ability) => { + Object.entries(ability.combatStats || {}).forEach(([key, value]) => { + combatant.combatStats[key] = (combatant.combatStats[key] || 0) - value; + }); +}; + +const applyNonEnemyStatuses = (combatant, currentAbility, teams, now, audio) => { + const recipients = + currentAbility.target === 'self' + ? [combatant] + : currentAbility.target === 'team' + ? teams[combatant.teamIndex].combatants.filter((c) => c.combatStats.currentHealth > 0) + : []; + if (recipients.length === 0) return; + SELF_STATUS_KEYS.forEach((key) => { + if (!hasStatus(currentAbility, key)) return; + recipients.forEach((r) => applyValueStatus(r, currentAbility, key)); + }); + bufferAudio(audio, currentAbility.sfx, now - 200); +}; + +// While casting an uninterruptable ability the caster absorbs immobilizes +// (stun/cocoon). absorbsImmobilize flags an "Immune!" pop on the buff chip (a +// remount via a bumped instance) and reports the hit as absorbed; applyImmobilize +// routes every immobilize through it so any current/future one is covered. +const absorbsImmobilize = (target) => { + const u = target.statuses.uninterruptable; + if (!u || u.ticks <= 0) return false; + u.instance = (u.instance || 0) + 1; + u.announce = 'Immune!'; + return true; +}; + +const applyImmobilize = (target, key, status) => { + if (absorbsImmobilize(target)) return; + target.statuses[key] = status; +}; + +// Generic threshold buildup: add `amount`, and when the bar fills convert into the +// paired effect (convertsInto) for convertAmount + overflow ticks, then nudge the +// threshold up so repeated control hits diminishing returns — two mirrored +// Stompers can't perma-lock. Immobilize conversions route through applyImmobilize +// so Uninterruptable can absorb them; DOT conversions carry the dealer's tick +// damage; the rest take their own effect value. +const applyThreshold = (target, combatant, ability, key, amount) => { + const def = STATUS_EFFECTS[key]; + const s = target.statuses[key]; + s.value += amount; + if (s.value < s.max) return; + const overflow = s.value - s.max; + s.value = 0; + s.max += 1; + const into = def.convertsInto; + const intoDef = STATUS_EFFECTS[into]; + const ticks = target.statuses[into].ticks + def.convertAmount + overflow; + if (into === 'bleeding' || into === 'poisoned') { + const value = Math.max( + target.statuses[into].value || 0, + Math.max(1, dotValue(combatant, ability)), + ); + target.statuses[into] = { ticks, value }; + } else if (into === 'stunned' || into === 'cocooned') { + applyImmobilize(target, into, { ticks, value: 1 }); + } else { + target.statuses[into] = { ticks, value: intoDef.damageMultiplierIncoming ?? 1 }; + } +}; + +// Apply every status an ability carries to one enemy target: thresholds build up +// (ticks × factor), a direct stun immobilizes, a direct DOT stacks its tick +// damage, and value statuses (Vulnerable, Obscured, …) apply for their scaled +// duration. Caster-only entries (Uninterruptable/Unstoppable) are handled at cast. +const applyEnemyStatuses = (target, combatant, ability) => { + ability.statusEffects.forEach(([key]) => { + const def = STATUS_EFFECTS[key]; + if (def.kind === 'threshold') { + applyThreshold(target, combatant, ability, key, statusTicks(ability, key)); + } else if (key === 'stunned' || key === 'confused') { + applyImmobilize(target, key, { + ticks: Math.max(target.statuses[key].ticks, statusTicks(ability, key)), + value: 1, + }); + } else if (key === 'bleeding' || key === 'poisoned') { + const value = Math.max( + target.statuses[key].value || 0, + Math.max(1, dotValue(combatant, ability)), + ); + target.statuses[key] = { + ticks: target.statuses[key].ticks + statusTicks(ability, key), + value, + }; + } else if (VALUE_STATUS_KEYS.includes(key)) { + applyValueStatus(target, ability, key); + } + }); +}; + +// Fan an ability's statuses out to every living enemy (mirrors the 'team' branch +// of applyNonEnemyStatuses, but for the opposing teams). Used by Stomp. +const applyEnemiesStatuses = (combatant, currentAbility, teams, now, audio) => { + const enemies = teams + .filter((_, i) => i !== combatant.teamIndex) + .flatMap((team) => team.combatants.filter((c) => c.combatStats.currentHealth > 0)); + if (enemies.length === 0) return; + enemies.forEach((target) => applyEnemyStatuses(target, combatant, currentAbility)); + bufferAudio(audio, currentAbility.sfx, now - 200); +}; + +// One-shot area damage: a thrown bomb (Catch!) that lands once and washes the +// whole enemy team — not a sustained per-tick breath (see tickBreaths). Mirrors +// the breath's per-enemy maths but resolves a single time, on the cast's +// completion. Like the breath, it can't be blocked or dodged. +const applyEnemiesDamage = ( + combatant, + currentAbility, + teams, + now, + seed, + tickCount, + luckDisabled, +) => { + const enemies = teams + .filter((_, i) => i !== combatant.teamIndex) + .flatMap((team) => team.combatants.filter((c) => c.combatStats.currentHealth > 0)); + + enemies.forEach((target) => { + const isCritical = isLucky( + combatant.combatStats.criticalChance, + `${seed}_${tickCount}_${combatant.id}_${target.id}_catch`, + luckDisabled, + ); + + const weakened = + combatant.combatStats.damage * + currentAbility.damage * + (1 + damageDealtBoost(combatant.statuses)) * + (1 + damageTakenBoost(target.statuses)) * + elementalMultiplier(currentAbility, target); + let amount = Math.floor( + weakened * (1 + (isCritical ? combatant.combatStats.criticalDamage : 0)), + ); + + const armor = target.combatStats.currentArmor; + if (armor > 0) { + amount = Math.max(0, amount - armor); + const armorPenetration = combatant.combatStats.armorPenetration || 0; + if (armorPenetration > 0) { + const penetrated = Math.min(armorPenetration, armor); + target.combatStats.currentArmor = armor - penetrated; + bufferAnimation(target, { ...VFX.armorHurt, amount: penetrated }, now); + } + } + + if (amount <= 0) return; + target.combatStats.currentHealth -= amount; + target.combatStats.bufferedHealth = Math.max(0, target.combatStats.bufferedHealth - amount); + bufferAnimation(target, { ...VFX.hurt, amount, isCritical }, now); + }); +}; + +const isLucky = (chance, seed, luckDisabled) => { + if (luckDisabled) return false; + const random = seededRandom(0, 1, seed, 0.01); + + return random < chance; +}; + +export const healFull = (characters) => + characters.map((character) => { + const combatStats = calculateCombatStatsByCharacter(CHARACTERS(character, true)); + + return { + ...character, + overrides: { + ...character.overrides, + combatStats: { + ...character.overrides?.combatStats, + currentHealth: combatStats.maxHealth, + }, + }, + }; + }); + +export const prepareTeams = (...teams) => { + const preparedCombatants = teams.map((team, teamIndex) => { + const preparedTeam = (teamIndex !== 0 ? healFull(team) : team).map( + (combatant, combatatantIndex) => + prepareCombatant( + CHARACTERS(combatant, true), + teams.length, + team.length, + teamIndex, + combatatantIndex, + ), + ); + + return preparedTeam; + }); + + return preparedCombatants.map((team, index) => ({ + name: `Team ${index}`, + index, + combatants: team, + })); +}; + +const moreThanOneTeamStanding = (teams) => { + const teamsStanding = teams.filter((team) => + team.combatants.some((combatant) => combatant.combatStats.currentHealth > 0), + ); + return teamsStanding.length > 1; +}; + +// Fight tally, accumulated from the player's seat (team 0) across every damage and +// heal instance. Reset per fight in generateCombat and returned on the result; the +// stats page is fed from here rather than reconstructing hits from the snapshots. +let combatSummary; + +// Deterministic VFX/SFX/animation ids. The simulation is fully seeded, so the order +// these are minted in is identical on every build of the same fight — a monotonic +// counter (seed-prefixed for cross-fight uniqueness) reproduces the same ids each +// rewatch. The replay derives the floater scatter from the id (combat-loop), so a +// random id (crypto.randomUUID) made the same fight jitter differently every replay. +// Reset per fight in generateCombat, alongside combatSummary. +let idSeed = ''; +let idCounter = 0; +const nextAnimationId = () => `${idSeed}-${idCounter++}`; + +const bufferAnimation = (combatant, vfx, timestamp) => { + const newVFX = structuredClone(vfx); + + newVFX.start = timestamp; + newVFX.end = timestamp + COMBAT_TICK_TIME; + + newVFX.id = nextAnimationId(); + + // Hurt floaters scale with how big the instance is as a share of the target's + // total health pool — measured by damage actually dealt, not the raw (possibly + // overkill) instance. currentHealth is already decremented here, so the pre-hit + // health is currentHealth + amount; a 100-dmg hit on a 1-HP target dealt 1. + if (newVFX.vfxName === 'hurt') { + const maxHealth = combatant.combatStats.maxHealth || 0; + const amount = newVFX.amount || 0; + const dealt = Math.min(amount, Math.max(0, combatant.combatStats.currentHealth + amount)); + newVFX.healthFraction = maxHealth > 0 ? dealt / maxHealth : 0; + // Damage on a team-0 combatant is taken, on anyone else is dealt by us. + if (combatant.teamIndex === 0) { + combatSummary.damageReceived += dealt; + combatSummary.largestHitReceived = Math.max(combatSummary.largestHitReceived, dealt); + } else { + combatSummary.damageDealt += dealt; + combatSummary.largestHitDealt = Math.max(combatSummary.largestHitDealt, dealt); + } + } else if (newVFX.vfxName === 'heal' && combatant.teamIndex === 0) { + combatSummary.largestHeal = Math.max(combatSummary.largestHeal, newVFX.amount || 0); + } + + combatant.animations.push(newVFX); +}; + +const bufferAudio = (audio, sfx, timestamp) => { + const newSFX = structuredClone(sfx); + + newSFX.id = nextAnimationId(); + newSFX.start = timestamp; + + audio.push(newSFX); +}; + +// Re-seat a whole team after its roster changes (spawn, hatch, removal) so the +// layout matches a freshly-prepared team of that size — the same `ringPosition` +// math as the initial seating, keyed off the current count. Anything else drifts +// the surviving cards out of their even spread (e.g. hatchlings creeping inward). +const restackTeam = (teams, teamIndex) => { + const team = teams[teamIndex]; + team.combatants.forEach((c, i) => { + c.position = ringPosition(teamIndex, teams.length, team.combatants.length, i); + }); +}; + +// Generic mid-combat spawn: inject a CHARACTERS.js entity into a team. The sim +// re-derives its combatant list every tick, so the spawn acts from the next tick; +// it also lands in this tick's end-of-tick snapshot, so it renders from the moment +// it appears. `spec` = { character, overrides } — overrides reach the entity (e.g. +// the Jester's `maxHealth: 1`). Reused by anything that spawns (eggs → hatchlings). + +const spawnCombatant = (teams, teamIndex, spec) => { + const team = teams[teamIndex]; + const combatant = prepareCombatant( + { id: spec.character, overrides: spec.overrides }, + teams.length, + team.combatants.length + 1, + teamIndex, + team.combatants.length, + ); + combatant.spawned = true; + team.combatants.push(combatant); + restackTeam(teams, teamIndex); + return combatant; +}; + +// Swap a combatant for a new entity in its own slot (an Egg → Scorchling hatch). +// Replacing at the same index — rather than push + splice — keeps every other +// combatant's index, so the rest of the team holds its seat instead of shuffling +// (the centred boss would otherwise slide to an edge as the egg dropped out). +const replaceCombatant = (teams, teamIndex, index, spec) => { + const team = teams[teamIndex]; + const combatant = prepareCombatant( + { id: spec.character, overrides: spec.overrides }, + teams.length, + team.combatants.length, + teamIndex, + index, + ); + combatant.spawned = true; + team.combatants.splice(index, 1, combatant); + restackTeam(teams, teamIndex); + return combatant; +}; + +// Reactive triggers: when `event` lands on `victim`, any active trigger status it +// holds whose `trigger.on` matches fires. A trigger either deals counter damage +// back to the `attacker` (scaled off `incomingDamage`) or spawns an entity into the +// victim's team (the spec rides on the status instance). Counters are direct (no +// block/dodge/crit/armor) and never themselves trigger reactions, so two +// counter-holders can't loop; spawns are gated by the caller to surviving hits. +const resolveTriggers = (victim, attacker, event, incomingDamage, now, audio, teams) => { + TRIGGER_STATUS_KEYS.forEach((key) => { + const status = victim.statuses[key]; + if (!status || (status.ticks || 0) <= 0) return; + const { on, returnDamage } = STATUS_EFFECTS[key].trigger; + const fires = Array.isArray(on) ? on.includes(event) : on === event; + if (!fires) return; + + if (status.spawn && teams) { + spawnCombatant(teams, victim.teamIndex, status.spawn); + bufferAudio(audio, SFX.doublePersona, now - 100); + } + + const amount = Math.floor(incomingDamage * (returnDamage || 0)); + if (amount <= 0) return; + attacker.combatStats.currentHealth -= amount; + attacker.combatStats.bufferedHealth = Math.max(0, attacker.combatStats.bufferedHealth - amount); + bufferAnimation(attacker, { ...VFX.hurt, amount, isCritical: false }, now); + bufferAudio(audio, SFX.stab, now - 100); + }); +}; + +const SPIN_FLOURISH_TIME = 300; + +const SPRITE_VFX = [ + 'basicAttackFast', + 'basicAttackRegular', + 'basicAttackSlow', + 'pounce', + 'whirlwind', + 'block', + 'stomp', + 'catchThrow', + 'boom', + 'hatch', +]; + +const injectAnimation = (combatant, target, currentAbility, now, teams, events = []) => { + const start = now - currentAbility.ticks * COMBAT_TICK_TIME; + const animations = []; + + const spinFlourish = + currentAbility.type === TYPE.WindUp && currentAbility.vfx.vfxName === 'whirlwind'; + if (spinFlourish) { + // A whirlwind on a wind-up is a release flourish: charge through the + // wind-up, then burst into a few really fast spins the instant the hit + // lands — damage resolves at `now`, exactly as the spin begins. + animations.push({ ...VFX.abilityCharge, start, end: now }); + animations.push({ vfxName: 'spin', start: now, end: now + SPIN_FLOURISH_TIME }); + } else if (SPRITE_VFX.includes(currentAbility.vfx.vfxName)) { + const vfx = structuredClone(currentAbility.vfx); + vfx.start = start; + vfx.end = now + (vfx.vfxName === 'block' ? 250 : 0); + vfx.targetX = target.position.x; + vfx.targetY = target.position.y; + animations.push(vfx); + } else if (currentAbility.type === TYPE.WindUp) { + animations.push({ ...VFX.abilityCharge, start, end: now }); + animations.push({ ...VFX.abilityRelease, start: now, end: now + VFX.abilityRelease.duration }); + } else { + animations.push({ ...VFX.abilityRecover, start, end: now }); + } + + // Generic thrown projectile: an arena-level icon that flies from the caster to + // the struck target. Released ~78% through the wind-up (the snap) and lands on + // the cast's completion, when the hit resolves. Config lives on the ability + // (icon / trajectory: 'arc' | 'straight' / spin degrees) so any ability can throw. + if (currentAbility.projectile) { + const { icon, trajectory = 'straight', spin = 0 } = currentAbility.projectile; + animations.push({ + vfxName: 'projectile', + projectile: true, + icon, + trajectory, + spin, + start: now - currentAbility.ticks * COMBAT_TICK_TIME * 0.2, + end: now, + startX: combatant.position.x, + startY: combatant.position.y, + endX: target.position.x, + endY: target.position.y, + }); + } + + animations.forEach((a) => (a.id = nextAnimationId())); + + const cIndex = teams[combatant.teamIndex].combatants.findIndex(({ id }) => id === combatant.id); + combatant.injectedAnimations.push(...animations); + + events.forEach((event) => { + if (event.eventTimestamp < start) return; + // A combatant spawned mid-fight (e.g. a Double Persona clone) is absent from + // snapshots that predate its spawn — there is nothing to decorate there. + const snapshot = event.teams[combatant.teamIndex].combatants[cIndex]; + if (snapshot) snapshot.animations.push(...combatant.injectedAnimations); + }); +}; + +const pickAbility = (abilities, ability, now, startOrEnd) => + now % abilities[abilities.length - 1].end === + ability[startOrEnd] % abilities[abilities.length - 1].end; + +const sortByAbilityPriority = (a, b, now, startOrEnd) => { + const aAbility = a.abilities.find((ability) => + pickAbility(a.abilities, ability, now, startOrEnd), + ); + const bAbility = b.abilities.find((ability) => + pickAbility(b.abilities, ability, now, startOrEnd), + ); + + const aPriority = ABILITY_PRIORITY.indexOf(aAbility.id); + const bPriority = ABILITY_PRIORITY.indexOf(bAbility.id); + + const normalizedAPriority = aPriority === -1 ? Number.MAX_SAFE_INTEGER : aPriority; + const normalizedBPriority = bPriority === -1 ? Number.MAX_SAFE_INTEGER : bPriority; + + if (normalizedAPriority !== normalizedBPriority) return normalizedAPriority - normalizedBPriority; + + return 0; +}; + +const timedAbility = (combatants, now, startOrEnd) => + combatants.filter((combatant) => + combatant.abilities.some((ability) => + pickAbility(combatant.abilities, ability, now, startOrEnd), + ), + ); + +const prioritySorting = (combatants, now, startOrEnd) => + combatants.sort((a, b) => sortByAbilityPriority(a, b, now, startOrEnd)); + +// Hard-control abilities (Stomp fans concussion→stun across enemies; Kick stuns). +// They resolve in their own pass, gated only by the pre-tick stun snapshot, so two +// of them landing the same tick both fire instead of the first pre-empting the +// second. Damage abilities never carry raw control — their threshold debuffs +// (concussion/wound) convert to it instead. +const isControlAbility = (ability) => ability.target === 'enemies' || ability.id === 'mindsnap'; + +const tickStatusEffects = (combatants, now) => { + combatants.forEach((combatant) => { + if (combatant.statuses.stunned.ticks > 0) { + combatant.statuses.stunned.ticks -= 1; + } else { + combatant.statuses.stunned.value = 0; + } + + if (combatant.statuses.cocooned.ticks > 0) { + combatant.statuses.cocooned.ticks -= 1; + } else { + combatant.statuses.cocooned.value = 0; + } + + if (combatant.statuses.confused.ticks > 0) { + combatant.statuses.confused.ticks -= 1; + } else { + combatant.statuses.confused.value = 0; + } + + if (combatant.statuses.uninterruptable.ticks > 0) { + combatant.statuses.uninterruptable.ticks -= 1; + } else { + combatant.statuses.uninterruptable.value = 0; + } + + SELF_STATUS_KEYS.forEach((key) => { + const s = combatant.statuses[key]; + if (!s) return; + if (s.ticks > 0) { + s.ticks -= 1; + } else { + s.value = 0; + } + }); + + if (combatant.statuses.bleeding.ticks > 0) { + const bleedDamage = combatant.statuses.bleeding.value; + const weakenedDamage = (1 + damageTakenBoost(combatant.statuses)) * bleedDamage; + const finalDamage = Math.floor(weakenedDamage); + combatant.combatStats.currentHealth -= finalDamage; + combatant.combatStats.bufferedHealth = Math.max( + 0, + combatant.combatStats.bufferedHealth - finalDamage, + ); + bufferAnimation(combatant, { ...VFX.hurt, amount: finalDamage }, now); + combatant.statuses.bleeding.ticks -= 1; + } else { + combatant.statuses.bleeding.value = 0; + } + + if (combatant.statuses.poisoned.ticks > 0) { + const poisonDamage = combatant.statuses.poisoned.value; + const weakenedDamage = (1 + damageTakenBoost(combatant.statuses)) * poisonDamage; + const finalDamage = Math.floor(weakenedDamage); + combatant.combatStats.currentHealth -= finalDamage; + combatant.combatStats.bufferedHealth = Math.max( + 0, + combatant.combatStats.bufferedHealth - finalDamage, + ); + bufferAnimation(combatant, { ...VFX.hurt, amount: finalDamage }, now); + combatant.statuses.poisoned.ticks -= 1; + } else { + combatant.statuses.poisoned.value = 0; + } + }); +}; + +// Failsafe so two mutually-immune armored combatants can't stall forever: past the +// time threshold, armor erodes each tick (max too, so `harden` can't restore it). +const ARMOR_DECAY_PER_TICK = 2; + +const decayArmor = (combatants) => { + combatants.forEach((combatant) => { + const { combatStats } = combatant; + if (combatStats.maxArmor <= 0) return; + combatStats.maxArmor = Math.max(0, combatStats.maxArmor - ARMOR_DECAY_PER_TICK); + combatStats.currentArmor = Math.min(combatStats.currentArmor, combatStats.maxArmor); + }); +}; + +// Sudden death: once a fight passes a minute, everyone gains the "End game" skull +// debuff and bleeds 1 HP per tick. Guarantees convergence for any stalemate the +// other systems can't break — mirrored control loops, regenerating tanks, or a +// build with no damage at all — so a combat can never run forever. +const END_GAME_MS = 60000; + +const applyEndGame = (combatants) => { + combatants.forEach((combatant) => { + const { combatStats } = combatant; + combatant.statuses.endGame = { ticks: 0, value: 1 }; + combatStats.currentHealth -= 1; + combatStats.bufferedHealth = Math.max(0, combatStats.bufferedHealth - 1); + }); +}; + +// Mark anyone at or below zero health as knocked out and wipe their statuses. +// Idempotent (the knockedOut guard), so it can run after every damage source. +const markKnockouts = (teams, now) => { + teams.forEach((team) => + team.combatants.forEach((c) => { + if (c.combatStats.currentHealth <= 0 && !c.statuses.knockedOut) { + c.statuses.knockedOut = now; + Object.entries(STATUS_EFFECTS).forEach(([key, def]) => { + c.statuses[key] = + def.kind === 'threshold' ? { max: 0, value: 0 } : { ticks: 0, value: 0 }; + }); + } + }), + ); +}; + +// A breath is the only ability that deals damage to a whole team at once: a +// Channeling + 'enemies' ability with a damage multiplier. The multiplier is the +// per-tick share each enemy takes while the breath sustains (see tickBreaths), +// not a single blow — a 4-tick breath washes every enemy four times. +const isBreath = (ability) => + ability.type === TYPE.Channeling && ability.target === 'enemies' && ability.damage > 0; + +// The ability a combatant is mid-way through at `now` (the one whose [start, end) +// window contains the cycle-relative time), as opposed to one merely starting or +// ending this tick. Mirrors the window-matching the Kick handler uses. +const activeAbility = (combatant, now) => { + const total = combatant.abilities[combatant.abilities.length - 1].end; + const t = ((now % total) + total) % total; + return combatant.abilities.find((ability) => { + const start = ability.start % total; + const end = ability.end % total; + if (end > start) return t >= start && t < end; + if (end < start) return t >= start || t < end; + return true; + }); +}; + +// Channeled breath: a dragon's exhale is a sustained wash, not a single blow, so +// every tick it is active it pours its per-tick share onto every living enemy — +// the sim's only true area damage. It flows through armor and can crit like any +// hit, but can't be blocked or dodged (there is no edge to parry a flood), which +// is what lets one breather pressure a whole party. Threshold/value debuffs the +// breath carries (concussion, vulnerability) still land once per channel via the +// control pass; this only resolves the damage. +const tickBreaths = (teams, combatants, now, seed, tickCount, audio, luckDisabled) => { + combatants.forEach((combatant) => { + if ( + combatant.statuses.stunned.value === 1 || + combatant.statuses.cocooned.value === 1 || + combatant.statuses.confused.value === 1 + ) { + return; + } + const ability = activeAbility(combatant, now); + if (!isBreath(ability)) return; + + const enemies = teams + .filter((_, i) => i !== combatant.teamIndex) + .flatMap((team) => team.combatants.filter((c) => c.combatStats.currentHealth > 0)); + if (enemies.length === 0) return; + + enemies.forEach((target) => { + const isCritical = isLucky( + combatant.combatStats.criticalChance, + `${seed}_${tickCount}_${combatant.id}_${target.id}_breath`, + luckDisabled, + ); + + const weakened = + combatant.combatStats.damage * + ability.damage * + (1 + damageDealtBoost(combatant.statuses)) * + (1 + damageTakenBoost(target.statuses)) * + elementalMultiplier(ability, target); + let amount = Math.floor( + weakened * (1 + (isCritical ? combatant.combatStats.criticalDamage : 0)), + ); + + const armor = target.combatStats.currentArmor; + if (armor > 0) { + amount = Math.max(0, amount - armor); + const armorPenetration = combatant.combatStats.armorPenetration || 0; + if (armorPenetration > 0) { + const penetrated = Math.min(armorPenetration, armor); + target.combatStats.currentArmor = armor - penetrated; + bufferAnimation(target, { ...VFX.armorHurt, amount: penetrated }, now); + } + } + + if (amount <= 0) return; + target.combatStats.currentHealth -= amount; + target.combatStats.bufferedHealth = Math.max(0, target.combatStats.bufferedHealth - amount); + bufferAnimation(target, { ...VFX.hurt, amount, isCritical }, now); + }); + + bufferAudio(audio, ability.sfx, now - 200); + }); +}; + +// Mend channel: the support counterpart to the breath. Every tick it sustains, +// the caster clears all negative effects from one random living ally (its own +// team, itself included) — resolved per-tick here rather than on completion. +// Mend is cast Uninterruptable, so an immobilized caster is the breath's guard +// mirrored, not a live path. +const tickMend = (teams, combatants, now, seed, tickCount, audio) => { + combatants.forEach((combatant) => { + if ( + combatant.statuses.stunned.value === 1 || + combatant.statuses.cocooned.value === 1 || + combatant.statuses.confused.value === 1 + ) { + return; + } + const ability = activeAbility(combatant, now); + if (!ability?.cleanse) return; + + const allies = teams[combatant.teamIndex].combatants.filter( + (c) => c.combatStats.currentHealth > 0, + ); + if (allies.length === 0) return; + + const ally = + allies[seededRandom(0, allies.length - 1, `${seed}_${tickCount}_${combatant.id}_mend`)]; + cleanseDebuffs(ally); + bufferAnimation(ally, { ...VFX.mend }, now); + bufferAudio(audio, ability.sfx, now - 200); + }); +}; + +// Monotonic id stamped on every generated combat. The render loop keys "is this a new +// combat to (re)start?" off this primitive — it survives Vibe's per-flush re-cloning of +// the combat snapshot, where an object-reference check does not (a re-watch reassigning +// $.combat, or the live loop slicing events, would otherwise restart the loop forever). +let combatBuildSeq = 0; + +export const generateCombat = (teams, seed = `${Math.random()}`, fightId) => { + // Boss fights disable luck for deterministic outcomes — read it off the decorated + // combatants (a boss enemy carries `boss`) so seasonally-promoted bosses count too. + const luckDisabled = teams.some((team) => team.combatants?.some((c) => c.boss)); + const events = []; + combatSummary = { + damageDealt: 0, + damageReceived: 0, + largestHitDealt: 0, + largestHitReceived: 0, + largestHeal: 0, + }; + idSeed = seed; + idCounter = 0; + + let now = 0; + let tickCount = 0; + + const teamsStartState = structuredClone(teams); + teams = structuredClone(teams); + + const armorDecayTick = (60000 + Math.max(0, teams.length - 2) * 30000) / COMBAT_TICK_TIME; + + const audio = []; + + let healingEfficiency = 1; + + events.push( + structuredClone({ + eventTimestamp: now, + teams, + }), + ); + + while (moreThanOneTeamStanding(teams)) { + const stillStandingCombatants = teams + .flatMap((team) => team.combatants.map((combatant) => combatant)) + .filter((combatant) => combatant.combatStats.currentHealth > 0); + + tickStatusEffects(stillStandingCombatants, now); + + if (tickCount >= armorDecayTick) decayArmor(stillStandingCombatants); + + if (now >= END_GAME_MS) applyEndGame(stillStandingCombatants); + + if (now > 0) { + tickBreaths(teams, stillStandingCombatants, now, seed, tickCount, audio, luckDisabled); + tickMend(teams, stillStandingCombatants, now, seed, tickCount, audio); + markKnockouts(teams, now); + } + + const combatantsStarting = timedAbility(stillStandingCombatants, now, 'start'); + const combatantsEnding = timedAbility(stillStandingCombatants, now, 'end'); + const orderedCombatantsStarting = prioritySorting(combatantsStarting, now, 'start'); + const orderedCombatantsEnding = prioritySorting(combatantsEnding, now, 'end'); + + orderedCombatantsStarting.forEach((combatant) => { + const currentAbilityIndex = combatant.abilities.findIndex((ability) => + pickAbility(combatant.abilities, ability, now, 'start'), + ); + const currentAbility = combatant.abilities[currentAbilityIndex]; + + // A single ability that fills the whole rotation starts and ends on the same + // wrap tick (end ≡ start under the cycle modulo), so it's always active. Apply + // its stats once and keep them — re-applying every cycle would stack, and the + // remove pass leaves it alone — instead of adding then removing them each wrap. + const continuous = + combatant.abilities.find((ability) => + pickAbility(combatant.abilities, ability, now, 'end'), + ) === currentAbility; + if (!continuous || !combatant.continuousStatsApplied) { + applyAbilityStats(combatant, currentAbility); + if (continuous) combatant.continuousStatsApplied = true; + } + + if (currentAbility.type === TYPE.WindDown || currentAbility.type === TYPE.Channeling) { + applyNonEnemyStatuses(combatant, currentAbility, teams, now, audio); + } + + // Uninterruptable cast: the status tuple's factor is its proc chance, rolled + // as the cast begins (1 = always). On success the caster wears the buff for + // the cast's length, showing the chip and absorbing immobilizes. + const uninterruptableChance = statusFactor(currentAbility, 'uninterruptable'); + if ( + hasStatus(currentAbility, 'uninterruptable') && + (uninterruptableChance >= 1 || + seededRandom(0, 1, `${seed}_${now}_${currentAbilityIndex}_uninterruptable`, 0.01) < + uninterruptableChance) + ) { + combatant.statuses.uninterruptable = { + ticks: currentAbility.castTicksRemaining ?? currentAbility.ticks, + value: 1, + instance: combatant.statuses.uninterruptable?.instance || 0, + }; + } + + combatant.damage = Math.floor(combatant.combatStats.damage * currentAbility.damage); + }); + + // Resolve all abilities ending this tick so seating/order can't decide + // outcomes. Eligibility is the pre-tick snapshot — a combatant stunned at the + // start of the tick does nothing — captured before any control lands. + const preStunnedAtTickStart = new Set( + orderedCombatantsEnding.filter( + (c) => + c.statuses.stunned.value === 1 || + c.statuses.cocooned.value === 1 || + c.statuses.confused.value === 1, + ), + ); + + // Pick the defending team uniformly at random, then weight the individual by + // provocation (each combatant starts at 5, so an even team is an even split; + // more provocation pulls attacks proportionally). + const selectDefender = (combatant, currentAbilityIndex) => { + const targetableCombatants = stillStandingCombatants.filter( + ({ teamIndex }) => teamIndex !== combatant.teamIndex, + ); + const enemyTeamIndices = [...new Set(targetableCombatants.map((c) => c.teamIndex))]; + const defendingTeamIndex = + enemyTeamIndices[ + seededRandom(0, enemyTeamIndices.length - 1, `${seed}_${currentAbilityIndex}_${now}_team`) + ]; + const defenders = targetableCombatants.filter((c) => c.teamIndex === defendingTeamIndex); + return defenders[ + seededWeightedIndex( + defenders.map((c) => c.combatStats.provocation || 0), + `${seed}_${currentAbilityIndex}_${now}_defender`, + ) + ]; + }; + + // Pass 1 — hard control. Gated only by the pre-tick snapshot, so two controls + // resolving the same tick BOTH land (mirror Stomps stun each other) instead of + // the first pre-empting the second. The stuns applied here then gate pass 2, + // cancelling the victims' same-tick attacks, heals and buffs. + if (now > 0) { + orderedCombatantsEnding.forEach((combatant) => { + if (preStunnedAtTickStart.has(combatant)) return; + const currentAbilityIndex = combatant.abilities.findIndex((ability) => + pickAbility(combatant.abilities, ability, now, 'end'), + ); + const currentAbility = combatant.abilities[currentAbilityIndex]; + if (!isControlAbility(currentAbility)) return; + + const target = selectDefender(combatant, currentAbilityIndex); + injectAnimation(combatant, target, currentAbility, now, teams, events); + + if (currentAbility.target === 'enemies') { + applyEnemiesStatuses(combatant, currentAbility, teams, now, audio); + // A breath pours its damage per-tick (tickBreaths); a one-shot AoE + // (thrown bomb) lands its damage here, once, as the cast completes. + if (currentAbility.damage > 0 && !isBreath(currentAbility)) { + applyEnemiesDamage( + combatant, + currentAbility, + teams, + now, + seed, + tickCount, + luckDisabled, + ); + } + } + + if (currentAbility.id === 'mindsnap') { + const total = target.abilitiesCopied[target.abilitiesCopied.length - 1].end; + const t = ((now % total) + total) % total; + const targetCurrentAbility = target.abilitiesCopied.find((ability) => { + const start = ability.start % total; + const end = ability.end % total; + if (end > start) return t >= start && t < end; + else if (end < start) return t >= start || t < end; + else return true; + }); + const endTime = targetCurrentAbility.end % total; + const remainingTime = endTime > t ? endTime - t : total - t + endTime; + applyImmobilize(target, 'confused', { + ticks: remainingTime / COMBAT_TICK_TIME, + value: 1, + }); + bufferAudio(audio, currentAbility.sfx, now - 200); + } + }); + } + + // Pass 2 — everything else (heals, buffs, attacks), in stable order so RNG + // seeds keyed by `i` stay deterministic. A combatant stunned by pass 1 (or + // pre-tick) reads as `immobilized` here, so its action is cancelled. + // Self-replacing casts (an Egg's Hatch) collect here and resolve after the + // pass, so removing the caster never shifts indices mid-iteration. + const hatchEvents = []; + orderedCombatantsEnding.forEach((combatant, i) => { + const currentAbilityIndex = combatant.abilities.findIndex((ability) => + pickAbility(combatant.abilities, ability, now, 'end'), + ); + const currentAbility = combatant.abilities[currentAbilityIndex]; + const isControl = isControlAbility(currentAbility); + const target = selectDefender(combatant, currentAbilityIndex); + + const damage = { + amount: 0, + isCritical: false, + }; + const heal = { + amount: 0, + }; + + const isWindUp = currentAbility.type === TYPE.WindUp; + const stunned = combatant.statuses.stunned; + const cocooned = combatant.statuses.cocooned; + const confused = combatant.statuses.confused; + const immobilized = stunned.value === 1 || cocooned.value === 1 || confused.value === 1; + + if (now > 0) { + if (!immobilized && !isControl) { + injectAnimation(combatant, target, currentAbility, now, teams, events); + } + + if (immobilized) { + if (stunned.value === 1 && stunned.ticks === 0) { + combatant.statuses.stunned = { + ticks: 0, + value: 0, + }; + } + if (cocooned.value === 1 && cocooned.ticks === 0) { + combatant.statuses.cocooned = { + ticks: 0, + value: 0, + }; + } + if (confused.value === 1 && confused.ticks === 0) { + combatant.statuses.confused = { + ticks: 0, + value: 0, + }; + } + } else if (isWindUp && !isControl) { + const healingAmount = Math.floor( + combatant.combatStats.maxHealth * currentAbility.healing * healingEfficiency, + ); + + const missingHealth = + combatant.combatStats.maxHealth - combatant.combatStats.currentHealth; + const actualHealingDone = Math.min(healingAmount, missingHealth); + + combatant.combatStats.currentHealth += actualHealingDone; + combatant.combatStats.bufferedHealth += actualHealingDone; + combatant.combatStats.healingReceived += actualHealingDone; + + if (actualHealingDone > 0) { + bufferAudio(audio, SFX.chew, now - 200); + bufferAnimation(combatant, { ...VFX.heal, amount: actualHealingDone }, now); + } else if (healingAmount > 0) { + bufferAnimation(combatant, VFX.fullHealth, now); + } + + applyNonEnemyStatuses(combatant, currentAbility, teams, now, audio); + + // A cast that hatches into another entity (Egg → Scorchling) registers + // its spawn now; the swap itself runs once the pass is done. + if (currentAbility.replaceSelf && currentAbility.spawn) { + hatchEvents.push({ combatant, spec: currentAbility.spawn }); + } + + const attacksEnemy = currentAbility.target === 'enemy'; + + // Unstoppable attacks ignore the target's block and dodge entirely. + const stoppable = !hasStatus(currentAbility, 'unstoppable'); + + // Block chance is inert for a player with no shield equipped; NPCs block + // bare-handed (canBlock is baked per combatant in prepareCombatant). + const isBlocked = + attacksEnemy && + stoppable && + target.canBlock && + isLucky( + target.combatStats.blockChance, + `${seed}_${tickCount}_${i}_blockChance`, + luckDisabled, + ); + + const isDodged = + attacksEnemy && + stoppable && + isLucky( + target.combatStats.dodgeChance, + `${seed}_${tickCount}_${i}_dodgeChance`, + luckDisabled, + ); + + const isMissed = + currentAbility.damage > 0 && + !luckDisabled && + !isLucky( + combatant.combatStats.hitChance + + hitChanceTakenModifier(target.statuses) + + hitChanceDealtModifier(combatant.statuses), + `${seed}_${tickCount}_${i}_hitChance`, + luckDisabled, + ); + + if (isBlocked) { + bufferAudio(audio, SFX.block, now - 100); + bufferAnimation(target, VFX.attackBlocked, now); + const blockedDamage = combatant.combatStats.damage * currentAbility.damage; + resolveTriggers(target, combatant, 'block', blockedDamage, now, audio, teams); + } else if (isDodged) { + bufferAudio(audio, SFX.dodge, now - 100); + bufferAnimation(target, VFX.attackDodged, now); + const dodgedDamage = combatant.combatStats.damage * currentAbility.damage; + resolveTriggers(target, combatant, 'dodge', dodgedDamage, now, audio, teams); + } else if (isMissed) { + bufferAudio(audio, SFX.dodge, now - 100); + bufferAnimation(target, VFX.attackMissed, now); + } else if (attacksEnemy) { + const isCritical = isLucky( + combatant.combatStats.criticalChance, + `${seed}_${tickCount}_${i}_criticalDamage`, + luckDisabled, + ); + + const abilityDamage = combatant.combatStats.damage * currentAbility.damage; + const weakenedDamage = + abilityDamage * + (1 + damageDealtBoost(combatant.statuses)) * + (1 + damageTakenBoost(target.statuses)) * + elementalMultiplier(currentAbility, target); + const criticalDamage = + weakenedDamage * (1 + (isCritical ? combatant.combatStats.criticalDamage : 0)); + damage.amount = Math.floor(criticalDamage); + damage.isCritical = isCritical; + + const armor = target.combatStats.currentArmor; + if (armor > 0) { + damage.amount = Math.max(0, damage.amount - armor); + + const armorPenetration = combatant.combatStats.armorPenetration || 0; + if (armorPenetration > 0) { + const penetrated = Math.min(armorPenetration, armor); + target.combatStats.currentArmor = armor - penetrated; + bufferAnimation(target, { ...VFX.armorHurt, amount: penetrated }, now); + } + + if (damage.amount === 0) { + bufferAnimation(target, { ...VFX.armorHurt, prevented: true }, now); + bufferAudio(audio, SFX.armorHit, now - 200); + } + } + + target.combatStats.currentHealth -= damage.amount; + target.combatStats.bufferedHealth = Math.max( + 0, + target.combatStats.bufferedHealth - damage.amount, + ); + + let playAudio = false; + if (damage.amount > 0) { + bufferAnimation(target, { ...VFX.hurt, ...damage }, now); + playAudio = true; + } + + // A landed, survived blow fires the target's reactive 'damaged' triggers + // (e.g. Double Persona splits off a fragile double, Thorns counters). A + // lethal blow does not — the act ends with them. Counters scale off the + // attacker's full swing (abilityDamage), so a counter ignores how much the + // defender's armor soaked — matching the blocked case, which counters the + // full swing too. + if (damage.amount > 0 && target.combatStats.currentHealth > 0) { + resolveTriggers(target, combatant, 'damaged', abilityDamage, now, audio, teams); + } + + applyEnemyStatuses(target, combatant, currentAbility); + + if ( + playAudio || + hasStatus(currentAbility, 'bleeding') || + currentAbility.name === 'Demoralizing Shout' + ) { + bufferAudio(audio, currentAbility.sfx, now - 200); + } + } + + if (currentAbility.id === 'harden') { + if (combatant.combatStats.currentArmor > 0) { + combatant.combatStats.currentArmor = combatant.combatStats.maxArmor; + } + } + } + } + + markKnockouts(teams, now); + }); + + orderedCombatantsEnding.forEach((combatant) => { + const endedAbility = combatant.abilities.find((ability) => + pickAbility(combatant.abilities, ability, now, 'end'), + ); + // A continuous (full-rotation) ability ends and restarts on the same tick; + // its stats were applied once and must persist, so don't remove them. + const restarts = combatant.abilities.find((ability) => + pickAbility(combatant.abilities, ability, now, 'start'), + ); + if (endedAbility === restarts) return; + removeAbilityStats(combatant, endedAbility); + }); + + // Resolve hatches: swap each caster for its offspring in the same slot, so the + // rest of the team keeps its seat. Done after the passes (and before the + // snapshot) so this tick renders the hatched team. + hatchEvents.forEach(({ combatant, spec }) => { + const team = teams[combatant.teamIndex]; + const idx = team.combatants.indexOf(combatant); + if (idx === -1) return; + replaceCombatant(teams, combatant.teamIndex, idx, spec); + bufferAudio(audio, SFX.boom, now - 100); + }); + + events.push( + structuredClone({ + eventTimestamp: now, + teams, + }), + ); + + if (tickCount % 12 === 0 && tickCount !== 0) { + healingEfficiency = Math.max(0, healingEfficiency - 0.05); + } + + now += COMBAT_TICK_TIME; + tickCount += 1; + } + + const duration = events[events.length - 1]?.eventTimestamp; + const teamsEndState = events[events.length - 1].teams; + const winningTeam = teamsEndState.find((team) => + team.combatants.some((combatant) => combatant.combatStats.currentHealth > 0), + ); + + const combined = Object.values( + audio.reduce((acc, item) => { + const key = `${item.sfxName}-${item.start}`; + if (!acc[key]) { + acc[key] = { + sfxName: item.sfxName, + start: item.start, + duration: item.duration, + id: item.id, + variants: item.variants, + count: 1, + }; + } else { + acc[key].count += 1; + } + return acc; + }, {}), + ); + + return { + audio: combined, + events, + teamsStartState, + teamsEndState, + duration, + winningTeam, + fightId, + seed, + summary: combatSummary, + replayNonce: ++combatBuildSeq, + }; +}; + +// Spin the whole arena so the viewing player's team sits where team 0 does (front- +// left), so every client watches its own brawlers on the left. Positions are baked +// screen coordinates (ringPosition: x = sin(rot)·R, y = cos(rot)·R about the ring +// centre), so this is a rigid rotation of every point by −viewerTeamIndex·(360/teams) +// degrees — a real rotation, not a relabelling of teams: combatant/team indices and +// the winner are untouched, so the outcome stays identical everywhere. No-op when the +// viewer is team 0 already or has no brawler in this fight (viewerTeamIndex < 0). +export const rotateCombatToViewer = (combat, viewerTeamIndex) => { + const teamCount = combat.teamsStartState?.length || 0; + if (viewerTeamIndex <= 0 || teamCount < 2) return combat; + + const deg = viewerTeamIndex * (360 / teamCount); + const rad = (deg * Math.PI) / 180; + const cos = Math.cos(rad); + const sin = Math.sin(rad); + const rotatePoint = (o, kx, ky) => { + const x = o[kx]; + const y = o[ky]; + if (typeof x !== 'number' || typeof y !== 'number') return; + o[kx] = x * cos - y * sin; + o[ky] = x * sin + y * cos; + }; + + // A visited-set rotates each real object exactly once — load-bearing because the + // same objects recur across frames: teamsEndState aliases events[last].teams, and + // (crucially) one animation object is pushed by reference into every event snapshot + // from its start tick on (injectAnimation), so without per-animation dedup a multi- + // frame attack would rotate 3× and a 120° spin would wrap back to where it started. + const seen = new WeakSet(); + const rotateCombatant = (c) => { + if (!c || seen.has(c)) return; + seen.add(c); + if (c.position && !seen.has(c.position)) { + seen.add(c.position); + rotatePoint(c.position, 'x', 'y'); + if (typeof c.position.rot === 'number') c.position.rot -= deg; + } + (c.animations || []).forEach((a) => { + if (!a || seen.has(a)) return; + seen.add(a); + rotatePoint(a, 'startX', 'startY'); + rotatePoint(a, 'endX', 'endY'); + rotatePoint(a, 'targetX', 'targetY'); + }); + }; + const rotateFrames = (teams) => + (teams || []).forEach((team) => (team.combatants || []).forEach(rotateCombatant)); + + rotateFrames(combat.teamsStartState); + combat.events?.forEach((e) => rotateFrames(e.teams)); + rotateFrames(combat.teamsEndState); + + return combat; +}; diff --git a/js/combatResult.js b/js/combatResult.js new file mode 100644 index 00000000..7f1f66c6 --- /dev/null +++ b/js/combatResult.js @@ -0,0 +1,32 @@ +import { teamColor } from '/js/helpers.js'; + +// Pure post-fight outcome helpers, shared by the live combat overlay (Combat.html +// assigns them onto window for bare markup calls) and the /_internal preview page. +// No side effects, no $ access — everything is derived from the passed combat object. + +export const combatEnded = (combat, elapsedMilliseconds) => + combat.duration > 0 && elapsedMilliseconds >= combat.duration; + +export const combatOutcome = (combat) => { + const idx = combat.winningTeam?.index; + // Teamplay: my brawlers can be on any team, so the result is judged against the + // team I'm on, not team 0. + if (combat.context === 'teamplay') + return idx === undefined ? 'draw' : idx === combat.myTeamIndex ? 'victory' : 'defeat'; + return idx === 0 ? 'victory' : idx === undefined ? 'draw' : 'defeat'; +}; + +// Spectators (live watch or a re-watch) see a neutral result instead of win/lose: +// the winning team by number, or DRAW. Participants fall through to combatOutcome. +export const combatResultOutcome = (combat) => + combat.spectator ? (combat.winningTeam ? 'spectator' : 'draw') : combatOutcome(combat); + +export const combatResultLabel = (combat) => + combat.spectator && combat.winningTeam + ? combat.teamNames?.[combat.winningTeam.index] || `Team ${combat.winningTeam.index + 1}` + : ''; + +// Winning side's palette colour, so a spectated result can tint the team name to +// match the ring labels. Empty for participants (they see VICTORY/DEFEAT, not a team). +export const combatResultTeamColor = (combat) => + combat.spectator && combat.winningTeam ? teamColor(combat.winningTeam.index) : ''; diff --git a/js/config.js b/js/config.js new file mode 100644 index 00000000..41e451ef --- /dev/null +++ b/js/config.js @@ -0,0 +1,16 @@ +import { isTester as isTesterEmail } from '../server/constants/testers.js'; +import { isAdmin as isAdminEmail } from '../server/constants/admins.js'; + +const IS_DEV = import.meta.env.VITE_VERCEL_ENV === 'development'; + +export { isTesterEmail, isAdminEmail }; + +export default { + WEBSOCKET_CONNECT: import.meta.env.VITE_WEBSOCKET_CONNECT ?? '', + ENVIRONMENT: import.meta.env.VITE_VERCEL_ENV ?? 'production', + IS_DEV, + IS_PROD: !IS_DEV, + AUTO_EMAIL: import.meta.env.VITE_AUTO_EMAIL ?? '', + AUTO_PASSWORD: import.meta.env.VITE_AUTO_PASSWORD ?? '', + WORKTREE: import.meta.env.VITE_WORKTREE ?? '', +}; diff --git a/js/connectSocket.js b/js/connectSocket.js new file mode 100644 index 00000000..55df3de7 --- /dev/null +++ b/js/connectSocket.js @@ -0,0 +1,123 @@ +import AsyncAwaitWebsocket from '@ape-egg/async-await-websockets'; + +import config from '/js/config.js'; +import { buildDiffPayload, setSaveBaseline } from '/js/diff.js'; +import { initTeamplayListeners, resubscribe } from '/js/teamplay.js'; +import { PERSISTED_KEYS } from '/js/constants/DEFAULT_GAME_STATE.js'; + +let saveTimeout = null; + +const buildSavePayload = () => ({ + token: $.token, + timeOffset: $.clock.devOffset || 0, + ...Object.fromEntries( + PERSISTED_KEYS.map((key) => { + const value = $[key]; + return [key, value && typeof value === 'object' ? JSON.parse(JSON.stringify(value)) : value]; + }), + ), +}); + +// Diff against the last acknowledged save and send only what changed; commit the +// snapshot as the new baseline once the server confirms. An empty diff is skipped. +const persist = async () => { + const snapshot = buildSavePayload(); + const payload = buildDiffPayload(snapshot); + if (!Object.keys(payload.update).length) return; + await $.socket.sendAsync('store-game-state', payload); + setSaveBaseline(snapshot); +}; + +const saveGameState = () => { + clearTimeout(saveTimeout); + saveTimeout = setTimeout(async () => { + if (!$.socket || !$.token) return; + + await persist(); + + console.info('Game state saved'); + }, 1000); +}; + +// Flush any pending debounced save immediately, wait for server ACK, and +// return. Use this before a full-page navigation that depends on the saved +// state being readable by the destination page (e.g. recruiting a brawler +// and redirecting to /brawlers/). +export const saveNow = async () => { + clearTimeout(saveTimeout); + saveTimeout = null; + if (!$.socket || !$.token) return; + await persist(); + console.info('Game state saved (forced)'); +}; + +// Settings live in localStorage so they survive navigation. Each key is written +// individually (matching how app.js reads them back on boot). +const persistSettings = () => { + if (!$.settings) return; + Object.entries($.settings).forEach(([key, value]) => { + window.localStorage.setItem(key, JSON.stringify(value)); + }); +}; + +let wasConnected = false; + +export const init = () => { + const ws = AsyncAwaitWebsocket(config.WEBSOCKET_CONNECT); + + ws.on('open', (e) => { + $.socket = e.target; + if (wasConnected) notify.success('Connected to game server'); + wasConnected = true; + // Rejoin any teamplay rooms the connection lost on a reconnect. + resubscribe(); + }); + + ws.on('close', () => { + if ($.socket) notify.error("Can't connect to game server"); + $.socket = undefined; + }); + + ws.on('broadcast', (data) => console.info('Broadcast:', data)); + + initTeamplayListeners(ws); + + // Flush pending save before page unloads (MPA navigation, tab close, etc.). + // Settings persist synchronously here too: a change made right before leaving + // (e.g. toggling Test Mode) is written before the page goes, rather than racing + // the async afterUpdate write — which reads stale localStorage until it runs. + window.addEventListener('pagehide', () => { + persistSettings(); + if (!saveTimeout || !$.socket || !$.token) return; + clearTimeout(saveTimeout); + const snapshot = buildSavePayload(); + const payload = buildDiffPayload(snapshot); + if (Object.keys(payload.update).length) $.socket.sendAsync('store-game-state', payload); + }); + + $.on('afterUpdate', (current, prev) => { + persistSettings(); + + // Capture the just-loaded state as the diff baseline so the first save after boot + // only carries genuine changes, not a redundant re-send of everything we loaded. + if (current.gameStateLoaded && !prev.gameStateLoaded) setSaveBaseline(buildSavePayload()); + + // Only save when game data actually changed + if ( + current.characters !== prev.characters || + current.inventory !== prev.inventory || + current.materials !== prev.materials || + current.statistics !== prev.statistics || + current.achievements !== prev.achievements || + current.experience !== prev.experience || + current.coins !== prev.coins || + current.accountRewards !== prev.accountRewards || + current.potions !== prev.potions || + current.buildings !== prev.buildings || + current.seasonPass !== prev.seasonPass || + current.bossHighscore !== prev.bossHighscore + ) { + saveGameState(); + } + }); +}; diff --git a/js/constants/ABILITIES.js b/js/constants/ABILITIES.js new file mode 100644 index 00000000..b4528ff3 --- /dev/null +++ b/js/constants/ABILITIES.js @@ -0,0 +1,1524 @@ +import VFX from '/js/constants/VFX.js'; +import SFX from '/js/constants/SFX.js'; +import entity from '/js/entity.js'; +import { deepMerge } from '/js/helpers.js'; +import STATUS_EFFECTS, { STATUS_EFFECT } from '/js/constants/STATUS_EFFECTS.js'; + +export const TYPE = { + WindUp: 'WindUp', + WindDown: 'WindDown', + Channeling: 'Channeling', +}; + +// DOT tick damage fractions (see dotValue in combat.js): a pure-DOT hit bleeds +// for a flat share of total damage; a hit that also deals damage bleeds for a +// share of that hit. Exported so descriptions and combat read the same number. +export const DOT_TOTAL_DAMAGE_FRACTION = 0.2; +export const DOT_HIT_DAMAGE_FRACTION = 0.3; + +// Formats a fraction as a percentage with up to one decimal (whole numbers stay +// clean), keeping the %s in ability descriptions tied to their real values. +const pct = (fraction) => `${+(Math.abs(fraction) * 100).toFixed(1)}%`; + +export const ALL_ABILITIES = { + stab: { + name: 'Stab', + type: TYPE.WindUp, + description: { + simple: 'A quick stab that wounds the target.', + extended: 'A quick stab that wounds the target.', + }, + ticks: 2, + icon: 'stab', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 0.95, + healingModifier: null, + }, + cut: { + name: 'Cut', + type: TYPE.WindUp, + description: { + simple: 'A quick cut that wounds the target.', + extended: 'A quick cut that wounds the target.', + }, + ticks: 1, + icon: 'cut', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + daggerThrow: { + name: 'Dagger Throw', + type: TYPE.WindUp, + description: { + simple: + 'Hurl your dagger in a flash — critical chance surges, but the throw lands for half damage.', + extended: + 'Hurl your dagger in a flash — critical chance surges, but the throw lands for half damage.', + }, + ticks: 1, + icon: 'daggerThrow', + basic: false, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 0.5, + healingModifier: null, + combatStats: { criticalChance: 1 }, + }, + pierce: { + name: 'Pierce', + type: TYPE.WindUp, + description: { + simple: 'A piercing shot that wounds the target.', + extended: 'A piercing shot that wounds the target.', + }, + ticks: 3, + icon: 'bowshot', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.bowShot, + damageModifier: 0.95, + healingModifier: null, + }, + powerShot: { + name: 'Powershot', + type: TYPE.WindUp, + description: { + simple: + 'Draw the string taut for a piercing shot. While charging, critical chance and critical damage surge.', + extended: + 'Draw the string taut for a piercing shot. While charging, critical chance and critical damage surge.', + }, + ticks: 6, + icon: 'powerShot', + basic: false, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackSlow, + sfx: SFX.bowShot, + damageModifier: 1, + healingModifier: null, + combatStats: { criticalChance: 0.03, criticalDamage: 0.5 }, + }, + slingshot: { + name: 'Slingshot', + type: TYPE.WindUp, + description: { + simple: 'Whip a stone from a leather sling — a quick shot that almost never misses.', + extended: 'Whip a stone from a leather sling — a quick shot that almost never misses.', + }, + ticks: 2, + icon: 'slingshot', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackFast, + sfx: SFX.bowShot, + damageModifier: 0.9, + healingModifier: null, + combatStats: { hitChance: 0.5 }, + }, + swing: { + name: 'Swing', + type: TYPE.WindUp, + description: { + simple: 'A sweeping swing that leaves the target exposed.', + extended: 'A sweeping swing that leaves the target exposed.', + }, + ticks: 3, + icon: 'slash', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.exposed, 1]], + vfx: VFX.basicAttackRegular, + sfx: SFX.swing, + damageModifier: 1, + healingModifier: null, + }, + wideSwing: { + name: 'Wide Swing', + type: TYPE.WindUp, + elements: ['fire'], + description: { + simple: 'Wind up a sweeping arc that strikes every enemy at once.', + extended: + 'Wind up a long, sweeping arc — when it lands, it carves through the entire enemy team.', + }, + ticks: 4, + icon: 'wideSwing', + basic: false, + target: 'enemies', + statusEffects: [], + vfx: VFX.whirlwind, + sfx: SFX.weaponSwing, + damageModifier: 0.6, + healingModifier: null, + }, + slam: { + name: 'Slam', + type: TYPE.WindUp, + description: { + simple: 'A heavy slam that concusses the target.', + extended: 'A heavy slam that concusses the target.', + }, + ticks: 4, + icon: 'slam', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.concussed, 1]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 1.05, + healingModifier: null, + }, + punch: { + name: 'Punch', + type: TYPE.WindUp, + description: { + simple: 'A basic punch.', + extended: 'A basic punch.', + }, + ticks: 2, + icon: 'punch', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackFast, + sfx: SFX.punch, + damageModifier: 0.9, + healingModifier: null, + }, + skewer: { + name: 'Skewer', + type: TYPE.WindUp, + description: { + simple: 'A quick strike that wounds the target.', + extended: 'A quick strike that wounds the target.', + }, + ticks: 4, + icon: 'skewer', + basic: false, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + weave: { + name: 'Weave', + type: TYPE.WindUp, + description: { + simple: 'Spits clinging silk that builds toward a full cocoon.', + extended: 'Spits clinging silk that builds toward a full cocoon.', + }, + ticks: 3, + icon: 'weave', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.webbed, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.bowShot, + damageModifier: null, + healingModifier: null, + }, + block: { + name: 'Block', + type: TYPE.Channeling, + description: { + simple: + 'Raise your shield, bolstering your block chance against incoming attacks for the duration.', + extended: (a) => + `Raise your shield, bolstering your block chance by ${pct(a.combatStats.blockChance)} against incoming attacks for the duration.`, + }, + ticks: 3, + icon: 'block', + basic: true, + target: 'self', + statusEffects: [], + vfx: VFX.block, + sfx: SFX.stab, + damageModifier: null, + healingModifier: null, + combatStats: { blockChance: 0.6 }, + }, + shieldBash: { + name: 'Shield Bash', + type: TYPE.WindUp, + description: { + simple: 'Lunge forward and bash your opponent with your shield.', + extended: 'Lunge forward and bash your opponent with your shield.', + }, + ticks: 3, + icon: 'shieldBash', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.concussed, 1]], + vfx: VFX.basicAttackRegular, + sfx: SFX.slam, + damageModifier: 1.05, + healingModifier: null, + }, + mindsnap: { + name: 'Mindsnap', + type: TYPE.WindUp, + description: { + simple: 'Snap at your opponent’s mind, confusing them.', + extended: + 'Snap at your opponent’s mind, confusing them for the ticks remaining in their current ability cast.', + }, + ticks: 6, + icon: 'confused', + basic: false, + target: 'enemy', + elements: ['fire', 'lightning', 'nature', 'frost', 'earth'], + statusEffects: [[STATUS_EFFECT.confused, Infinity]], + vfx: VFX.kick, + sfx: SFX.mindsnap, + damageModifier: null, + healingModifier: null, + }, + whirlwind: { + name: 'Whirlwind', + type: TYPE.Channeling, + description: { + simple: 'Quickly spin and deal damage each tick.', + extended: 'Quickly spin and deal damage each tick.', + }, + ticks: 10, + chainLink: 10, + icon: 'whirlwind', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.uninterruptable, 1]], + vfx: VFX.whirlwind, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + berserk: { + name: 'Berserk', + type: TYPE.Channeling, + elements: ['frost'], + description: { + simple: + 'Fly into a frost-fueled frenzy, hacking the enemy each tick. The cast cannot be interrupted.', + extended: + 'Fly into a frost-fueled frenzy, hacking the enemy each tick. The cast cannot be interrupted.', + }, + ticks: 4, + chainLink: 4, + icon: 'berserk', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.uninterruptable, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + lacerate: { + name: 'Lacerate', + type: TYPE.WindUp, + description: { + simple: 'Bleeds your opponent for a portion of your total damage.', + extended: () => + `Bleeds your opponent for ${pct(DOT_TOTAL_DAMAGE_FRACTION)} of your total damage.`, + }, + ticks: 2, + icon: 'lacerate', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.bleeding, 2]], + vfx: VFX.basicAttackFast, + sfx: SFX.doubleCut, + damageModifier: null, + healingModifier: null, + }, + demoralizingShout: { + name: 'Demoralizing Shout', + type: TYPE.WindUp, + description: { + simple: 'Weakens your opponent. They take more damage for the duration of the effect.', + extended: () => + `Weakens your opponent. They take ${pct(STATUS_EFFECTS.vulnerable.damageMultiplierIncoming)} more damage for the duration of the effect.`, + }, + ticks: 2, + icon: 'demoShout', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.vulnerable, 3]], + vfx: VFX.filler, + sfx: SFX.bling, + damageModifier: null, + healingModifier: null, + }, + stoneskin: { + name: 'Stone Skin', + type: TYPE.WindDown, + elements: ['earth'], + description: { + simple: 'Hardens your skin to stone. Take less damage for the duration of the effect.', + extended: () => + `Hardens your skin to stone. Take ${pct(STATUS_EFFECTS.stoneskinned.damageMultiplierIncoming)} less damage for the duration of the effect.`, + }, + ticks: 2, + icon: 'stoneSkin', + basic: true, + target: 'self', + statusEffects: [[STATUS_EFFECT.stoneskinned, 3]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + }, + taunt: { + name: 'Taunt', + type: TYPE.Channeling, + elements: ['earth'], + description: { + simple: 'Roar a challenge, drawing the enemy onto yourself for the duration of the effect.', + extended: (a) => + `Roar a challenge, raising your provocation by ${a.combatStats.provocation} so enemies are far more likely to strike you for the duration of the effect.`, + }, + ticks: 3, + icon: 'taunt', + basic: false, + target: 'self', + statusEffects: [], + vfx: VFX.filler, + sfx: SFX.warcry, + damageModifier: null, + healingModifier: null, + combatStats: { provocation: 50 }, + }, + smokebomb: { + name: 'Smoke Bomb', + type: TYPE.WindDown, + elements: ['lightning'], + description: { + simple: + 'Vanish in a cloud of smoke. Attackers are less likely to hit you for the duration of the effect.', + extended: () => + `Vanish in a cloud of smoke. Attackers are ${pct(STATUS_EFFECTS.obscured.hitChanceModifierIncoming)} less likely to hit you for the duration of the effect.`, + }, + ticks: 2, + icon: 'smokeBomb', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.obscured, 3]], + vfx: VFX.filler, + sfx: SFX.dodge, + damageModifier: null, + healingModifier: null, + }, + shieldWall: { + name: 'Shield Wall', + type: TYPE.WindUp, + elements: ['frost'], + description: { + simple: + 'Lock shields into a wall of ice. All teammates take less damage for the duration of the effect.', + extended: () => + `Lock shields into a wall of ice. All teammates take ${pct(STATUS_EFFECTS.warded.damageMultiplierIncoming)} less damage for the duration of the effect.`, + }, + ticks: 6, + icon: 'block', + basic: true, + target: 'team', + statusEffects: [[STATUS_EFFECT.warded, 3]], + vfx: VFX.block, + sfx: SFX.block, + damageModifier: null, + healingModifier: null, + }, + spikeWall: { + name: 'Spike Wall', + type: TYPE.WindUp, + elements: ['earth'], + description: { + simple: + 'Raise a wall of spikes. For the duration, every attack against you — landed or blocked — strikes back at the attacker.', + extended: () => + `Raise a wall of spikes. For the duration, every attack against you — landed or blocked — returns ${pct(STATUS_EFFECTS.thorns.trigger.returnDamage)} of its damage to the attacker.`, + }, + ticks: 4, + icon: 'spikeWall', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.thorns, 1]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + }, + warcry: { + name: 'War Cry', + type: TYPE.WindUp, + elements: ['frost'], + description: { + simple: 'Rally your team. All teammates deal more damage for the duration of the effect.', + extended: () => + `Rally your team. All teammates deal ${pct(STATUS_EFFECTS.inspired.damageMultiplierOutgoing)} more damage for the duration of the effect.`, + }, + ticks: 2, + icon: 'warCry', + basic: false, + target: 'team', + statusEffects: [[STATUS_EFFECT.inspired, 3]], + vfx: VFX.filler, + sfx: SFX.warcry, + damageModifier: null, + healingModifier: null, + }, + intimidatingRoar: { + name: 'Intimidating Roar', + type: TYPE.WindUp, + elements: [], + description: { + simple: + 'A bone-shaking roar. Your opponent takes more damage for the duration of the effect.', + extended: () => + `A bone-shaking roar. Your opponent takes ${pct(STATUS_EFFECTS.intimidated.damageMultiplierIncoming)} more damage for the duration of the effect.`, + }, + ticks: 2, + icon: 'intimidatingRoar', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.intimidated, 3]], + vfx: VFX.filler, + sfx: SFX.bling, + damageModifier: null, + healingModifier: null, + }, + stomp: { + name: 'Stomp', + type: TYPE.WindUp, + elements: ['earth'], + description: { + simple: + 'Rear back, then crash down. Every enemy receives concussion — enough to stagger most off their feet.', + extended: + 'Rear back, then crash down. Every enemy receives concussion — enough to stagger most off their feet.', + }, + ticks: 4, + icon: 'stomp', + basic: false, + target: 'enemies', + statusEffects: [[STATUS_EFFECT.concussed, 2]], + vfx: VFX.stomp, + sfx: SFX.stomp, + damageModifier: null, + healingModifier: null, + }, + eatMeat: { + name: 'Eat Meat', + type: TYPE.Channeling, + elements: ['earth'], + description: { + simple: 'Tear into a slab of meat, restoring health with every bite.', + extended: (a) => + `Tear into a slab of meat, restoring ${pct(a.calc.healing().result)} of max health per bite for a total of ${pct(a.calc.healing().result * a.chainLink)}.`, + }, + ticks: 4, + chainLink: 2, + icon: 'meat', + basic: false, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.chew, + damageModifier: null, + healingModifier: 1, + }, + cheesyTactics: { + name: 'Cheesy Tactics', + type: TYPE.Channeling, + elements: ['lightning'], + description: { + simple: 'Restores some health.', + extended: 'Restores some health.', + }, + ticks: 9, + chainLink: 3, + icon: 'cheese', + basic: true, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.chew, + damageModifier: null, + healingModifier: 1, + }, + alorasTouch: { + name: "Alora's Touch", + type: TYPE.WindUp, + elements: ['nature'], + description: { + simple: "Channel Alora's grace to restore a portion of max health.", + extended: (a) => + `Channel Alora's grace to restore ${pct(a.calc.healing().result)} of max health.`, + }, + ticks: 3, + icon: 'alorasTouch', + basic: false, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.powerReady, + damageModifier: null, + healingModifier: 1, + }, + mend: { + name: 'Mend', + type: TYPE.Channeling, + elements: ['nature'], + description: { + simple: 'Clears all negative status effects from a random friendly teammate.', + extended: + 'Each tick, clears all negative status effects from a random friendly teammate. Cannot be interrupted while casting.', + }, + ticks: 2, + icon: 'mend', + basic: false, + target: 'ally', + statusEffects: [[STATUS_EFFECT.uninterruptable, 1]], + cleanse: true, + vfx: VFX.heal, + sfx: SFX.powerReady, + damageModifier: null, + healingModifier: null, + }, + bite: { + name: 'Bite', + type: TYPE.WindUp, + description: { + simple: 'A vicious bite.', + extended: 'A vicious bite.', + }, + ticks: 2, + icon: 'bite', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.bleeding, 2]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + gore: { + name: 'Gore', + type: TYPE.WindUp, + description: { + simple: 'A goring tusk strike that wounds the enemy.', + extended: 'A goring tusk strike that wounds the enemy.', + }, + ticks: 3, + icon: 'gore', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 1]], + vfx: VFX.basicAttackRegular, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + pounce: { + name: 'Pounce', + type: TYPE.WindUp, + description: { + simple: 'Coil low, then leap in fangs-first — a heavy landing that opens a bleeding wound.', + extended: 'Coil low, then leap in fangs-first — a heavy landing that opens a bleeding wound.', + }, + ticks: 6, + icon: 'pounce', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.bleeding, 2]], + vfx: VFX.pounce, + sfx: SFX.slam, + damageModifier: 1.1, + healingModifier: null, + }, + ripAndTear: { + name: 'Rip & Tear', + type: TYPE.WindUp, + description: { + simple: 'A flurry of raking claws that leave the target wounded.', + extended: 'A flurry of raking claws that leave the target wounded.', + }, + ticks: 2, + icon: 'ripAndTear', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.swing, + damageModifier: 1, + healingModifier: null, + }, + charge: { + name: 'Charge', + type: TYPE.WindUp, + description: { + simple: 'Barrel forward headlong — a heavy blow that stuns the target on impact.', + extended: 'Barrel forward headlong — a heavy blow that stuns the target on impact.', + }, + ticks: 4, + icon: 'charge', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.stunned, 1]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 1, + healingModifier: null, + }, + poisonousSting: { + name: 'Poisonous Sting', + type: TYPE.WindUp, + description: { + simple: 'A venomous tail-stab that injects venom, building toward a debilitating poison.', + extended: 'A venomous tail-stab that injects venom, building toward a debilitating poison.', + }, + ticks: 4, + icon: 'poisonousSting', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.envenomed, 1]], + vfx: VFX.basicAttackSlow, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + execute: { + name: 'Execute', + type: TYPE.WindUp, + description: { + simple: + 'Raise the axe for a slow, certain killing blow — unstoppable, and it almost always lands a devastating critical.', + extended: + 'Raise the axe for a slow, certain killing blow. The strike cannot be blocked or dodged, and critical chance and critical damage surge enormously.', + }, + ticks: 4, + icon: 'execute', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.unstoppable, 1]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 0.8, + healingModifier: null, + combatStats: { criticalChance: 0.85 }, + }, + boom: { + name: 'BOOM!', + type: TYPE.WindUp, + description: { + simple: + 'Touch off the powder — a thunderous blast that almost always lands a critical and tears through armor.', + extended: + 'Touch off the powder for a thunderous blast. Critical chance surges and the shot punches through 2 armor.', + }, + ticks: 3, + icon: 'boom', + basic: false, + target: 'enemy', + statusEffects: [], + vfx: VFX.boom, + sfx: SFX.boom, + damageModifier: 1, + healingModifier: null, + combatStats: { criticalChance: 0.5, armorPenetration: 2 }, + }, + pretendToBeHumble: { + name: 'Haymaker!', + type: TYPE.WindUp, + description: { + simple: 'A long, telegraphed lunge. Lands hard at the end and leaves the target bleeding.', + extended: 'A long, telegraphed lunge. Lands hard at the end and leaves the target bleeding.', + }, + ticks: 12, + icon: 'haymaker', + basic: false, + target: 'enemy', + statusEffects: [ + [STATUS_EFFECT.bleeding, 3], + [STATUS_EFFECT.uninterruptable, 1], + [STATUS_EFFECT.unstoppable, 1], + ], + vfx: VFX.basicAttackSlow, + sfx: SFX.stab, + damageModifier: 0.5, + healingModifier: null, + }, + harden: { + name: 'Harden', + type: TYPE.WindUp, + description: { + simple: "If armor isn't depleted regain all armor.", + extended: "If armor isn't depleted regain all armor.", + }, + ticks: 1, + icon: 'fillArmor', + basic: true, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.stab, + damageModifier: null, + healingModifier: null, + }, + recharge: { + name: 'Recharge', + type: TYPE.Channeling, + description: { + simple: 'A long, telegraphed pause to recharge your energy.', + extended: 'A long, telegraphed pause to recharge your energy.', + }, + ticks: 3, + icon: 'recharge', + basic: true, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.stab, + damageModifier: null, + healingModifier: null, + }, + playingTheVictim: { + name: 'Playing the Victim', + type: TYPE.WindUp, + description: { + simple: 'A long, drawn-out act.', + extended: 'A long, drawn-out act.', + }, + ticks: 12, + icon: 'cross', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.stab, + damageModifier: null, + healingModifier: null, + }, + sunder: { + name: 'Sunder', + type: TYPE.WindUp, + description: { + simple: 'A splitting blow that leaves the target exposed, taking more damage.', + extended: () => + `A splitting blow that stacks Exposed buildup, tipping into Vulnerable so the target takes ${pct(STATUS_EFFECTS.vulnerable.damageMultiplierIncoming)} more damage.`, + }, + ticks: 3, + icon: 'sunder', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.exposed, 2]], + vfx: VFX.basicAttackRegular, + sfx: SFX.slam, + damageModifier: 0.5, + healingModifier: null, + }, + crushingBlow: { + name: 'Crushing Blow', + type: TYPE.WindUp, + description: { + simple: 'Wind up a heavy blow that concusses on impact and lands for bonus damage.', + extended: 'Wind up a heavy blow that concusses on impact and lands for bonus damage.', + }, + ticks: 4, + icon: 'crushingBlow', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.concussed, 2]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 0.5, + healingModifier: null, + combatStats: { armorPenetration: 15 }, + }, + aimedShot: { + name: 'Aimed Shot', + type: TYPE.WindUp, + description: { + simple: 'Take careful aim — critical chance and hit chance surge for a precise shot.', + extended: 'Take careful aim — critical chance and hit chance surge for a precise shot.', + }, + ticks: 4, + icon: 'aimedShot', + basic: false, + target: 'enemy', + vfx: VFX.basicAttackSlow, + sfx: SFX.bowShot, + statusEffects: [], + damageModifier: 1, + healingModifier: null, + combatStats: { criticalChance: 0.5, hitChance: 0.2 }, + }, + riposte: { + name: 'Riposte', + type: TYPE.Channeling, + description: { + simple: + 'Settle into a duelist’s stance — dodge chance surges. While active, a dodged attack counters for a portion of the attacker’s damage.', + extended: () => + `Settle into a duelist’s stance — dodge chance surges. While active, a dodged attack counters for ${pct(STATUS_EFFECTS.riposting.trigger.returnDamage)} of the attacker’s damage.`, + }, + ticks: 4, + icon: 'riposte', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.riposting, 1]], + vfx: VFX.filler, + sfx: SFX.bling, + damageModifier: null, + healingModifier: null, + combatStats: { dodgeChance: 0.4 }, + }, + deflect: { + name: 'Deflect', + type: TYPE.Channeling, + description: { + simple: + 'Raise the shield to deflect — block chance surges. While active, a blocked attack returns the attacker’s full damage.', + extended: () => + `Raise the shield to deflect — block chance surges. While active, a blocked attack returns ${pct(STATUS_EFFECTS.deflecting.trigger.returnDamage)} of the attacker’s damage.`, + }, + ticks: 2, + icon: 'deflect', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.deflecting, 1]], + vfx: VFX.block, + sfx: SFX.block, + damageModifier: null, + healingModifier: null, + combatStats: { blockChance: 0.4 }, + }, + doublePersona: { + name: 'Double Persona', + type: TYPE.Channeling, + elements: ['fire', 'lightning', 'nature', 'frost', 'earth'], + description: { + simple: + 'Slip into a shifting two-faced act. Every blow that lands during it splits off a fragile double — but a killing blow ends the act for good.', + extended: + 'Slip into a shifting two-faced act. Every blow that lands during it splits off a fragile double — but a killing blow ends the act for good.', + }, + ticks: 3, + icon: 'doublePersona', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.splitting, 1]], + vfx: VFX.filler, + sfx: SFX.filler, + damageModifier: null, + healingModifier: null, + spawn: { + character: 'jester', + overrides: { level: 1, combatStats: { maxHealth: 1, currentHealth: 1 } }, + }, + }, + emberStrike: { + name: 'Ember Strike', + type: TYPE.WindUp, + elements: ['fire'], + description: { + simple: 'A blazing strike — critical chance and critical damage surge as the embers bite.', + extended: 'A blazing strike — critical chance and critical damage surge as the embers bite.', + }, + ticks: 3, + icon: 'emberStrike', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackRegular, + sfx: SFX.emberStrike, + damageModifier: 1.1, + healingModifier: null, + combatStats: { criticalChance: 0.1, criticalDamage: 0.3 }, + }, + goodBoys: { + name: 'Good boys!', + type: TYPE.WindUp, + elements: ['fire'], + description: { + simple: 'A roaring wave of fire that strikes three times before it lets go.', + extended: 'A roaring wave of fire that strikes three times before it lets go.', + }, + ticks: 6, + chainLink: 3, + icon: 'goodBoys', + basic: false, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackRegular, + sfx: SFX.emberStrike, + damageModifier: 1.3, + healingModifier: null, + }, + hatch: { + name: 'Hatch', + type: TYPE.WindUp, + elements: [], + description: { + simple: 'The shell trembles and splits — something claws its way into the fight.', + extended: 'The shell trembles and splits — a Scorchling claws its way into the fight.', + }, + ticks: 15, + icon: 'hatch', + basic: false, + target: 'self', + statusEffects: [], + vfx: VFX.hatch, + sfx: SFX.boom, + damageModifier: null, + healingModifier: null, + spawn: { character: 'scorchLing' }, + replaceSelf: true, + }, + frostbite: { + name: 'Frostbite', + type: TYPE.WindUp, + elements: ['frost'], + description: { + simple: 'A frost-clad strike that shatters on impact — critical damage surges.', + extended: 'A frost-clad strike that shatters on impact — critical damage surges.', + }, + ticks: 3, + icon: 'frostStrike', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackRegular, + sfx: SFX.stab, + damageModifier: 1.05, + healingModifier: null, + combatStats: { criticalDamage: 0.4 }, + }, + stormStrike: { + name: 'Storm Strike', + type: TYPE.WindUp, + elements: ['lightning'], + description: { + simple: 'Lightning crackles down the weapon — critical chance surges for a sudden strike.', + extended: 'Lightning crackles down the weapon — critical chance surges for a sudden strike.', + }, + ticks: 3, + icon: 'stormStrike', + basic: true, + target: 'enemy', + statusEffects: [], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1.05, + healingModifier: null, + combatStats: { criticalChance: 0.2 }, + }, + rendingFrenzy: { + name: 'Rending Frenzy', + type: TYPE.WindUp, + elements: ['lightning'], + description: { + simple: 'A frenzied storm of claws that leaves the target badly wounded.', + extended: 'A frenzied storm of claws that leaves the target badly wounded.', + }, + ticks: 8, + chainLink: 1, + icon: 'rendingFrenzy', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 3]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + }, + lightningStorm: { + name: 'Lightning Storm', + type: TYPE.WindUp, + elements: ['lightning'], + description: { + simple: 'Call down the storm — an unstoppable barrage that cannot be interrupted.', + extended: + 'Call down the storm — an unstoppable barrage that cannot be blocked, dodged, or interrupted.', + }, + ticks: 12, + chainLink: 12, + icon: 'lightningStorm', + basic: false, + target: 'enemies', + statusEffects: [ + [STATUS_EFFECT.uninterruptable, 1], + [STATUS_EFFECT.unstoppable, 1], + ], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 0.5, + healingModifier: null, + }, + stoneShatter: { + name: 'Stone Shatter', + type: TYPE.WindUp, + elements: ['earth'], + description: { + simple: + 'An earth-shaking blow that concusses the target — armor penetration surges, cracking their guard.', + extended: + 'An earth-shaking blow that concusses the target — armor penetration surges, cracking their guard.', + }, + ticks: 6, + icon: 'stoneShatter', + basic: true, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.concussed, 1]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 1.1, + healingModifier: null, + combatStats: { armorPenetration: 4 }, + }, + wildGrowth: { + name: 'Wild Growth', + type: TYPE.WindUp, + elements: ['nature'], + description: { + simple: 'Channel nature’s vigor to restore a portion of your health.', + extended: 'Channel nature’s vigor to restore a portion of your health.', + }, + ticks: 4, + icon: 'wildGrowth', + basic: false, + target: 'self', + statusEffects: [], + vfx: VFX.heal, + sfx: SFX.powerReady, + damageModifier: null, + healingModifier: 1, + }, + fireBreath: { + name: "Dragon's Breath", + type: TYPE.Channeling, + elements: ['fire'], + description: { + simple: 'Exhale a roaring stream of flame that sears every enemy for as long as it sustains.', + extended: + 'Exhale a roaring stream of flame. While channeling, every enemy is seared each tick — the hottest of the breaths, and the most likely to land a critical.', + }, + ticks: 4, + icon: 'dragonBreath', + basic: false, + target: 'enemies', + statusEffects: [], + vfx: VFX.boom, + sfx: SFX.boom, + damageModifier: 2, + healingModifier: null, + combatStats: { criticalChance: 0.25, criticalDamage: 0.5 }, + }, + frostBreath: { + name: "Dragon's Breath", + type: TYPE.Channeling, + elements: ['frost'], + description: { + simple: + 'Breathe out a slow, biting cold that washes the whole arena and numbs every enemy toward a freeze.', + extended: + 'Breathe out a slow, biting cold. While channeling, every enemy takes steady frost damage and gathers concussion each completion — enough cold, and they freeze solid.', + }, + ticks: 5, + icon: 'dragonBreath', + basic: false, + target: 'enemies', + statusEffects: [[STATUS_EFFECT.concussed, 0.8]], + vfx: VFX.boom, + sfx: SFX.boom, + damageModifier: 2, + healingModifier: null, + }, + natureBreath: { + name: "Dragon's Breath", + type: TYPE.Channeling, + elements: ['nature'], + description: { + simple: + 'Spew a cloud of choking spores over every enemy, rotting their defences while it lingers.', + extended: () => + `Spew a cloud of choking spores. While channeling, every enemy takes nature damage each tick and is left vulnerable, taking ${pct(STATUS_EFFECTS.vulnerable.damageMultiplierIncoming)} increased damage from every source.`, + }, + ticks: 4, + icon: 'dragonBreath', + basic: false, + target: 'enemies', + statusEffects: [[STATUS_EFFECT.vulnerable, 1]], + vfx: VFX.boom, + sfx: SFX.boom, + damageModifier: 2, + healingModifier: null, + }, + lightningBreath: { + name: "Dragon's Breath", + type: TYPE.Channeling, + elements: ['lightning'], + description: { + simple: 'Loose a crackling arc that forks across every enemy in rapid, stuttering pulses.', + extended: + 'Loose a crackling arc of lightning. The fastest of the breaths — it forks across every enemy in rapid pulses, with a high chance to crit each one.', + }, + ticks: 3, + icon: 'dragonBreath', + basic: false, + target: 'enemies', + statusEffects: [], + vfx: VFX.boom, + sfx: SFX.boom, + damageModifier: 2, + healingModifier: null, + combatStats: { criticalChance: 0.4 }, + }, + earthBreath: { + name: "Dragon's Breath", + type: TYPE.Channeling, + elements: ['earth'], + description: { + simple: + 'Blast a torrent of grit and stone shards across every enemy, shredding armour as it grinds them down.', + extended: + 'Blast a torrent of grit and stone shards. While channeling, every enemy takes earth damage each tick, the shards tear through armour, and the pummelling staggers them toward a stun.', + }, + ticks: 4, + icon: 'dragonBreath', + basic: false, + target: 'enemies', + statusEffects: [[STATUS_EFFECT.concussed, 1.5]], + vfx: VFX.stomp, + sfx: SFX.boom, + damageModifier: 2, + healingModifier: null, + combatStats: { armorPenetration: 3 }, + }, + catch: { + name: 'Catch!', + type: TYPE.WindUp, + elements: ['lightning'], + description: { + simple: 'Wind up and lob a stick of dynamite that detonates across the whole enemy team.', + extended: (a) => + `Wind up and lob a stick of dynamite at the current foe. It detonates on impact, dealing ${pct(a.calc.damage().result)} of your damage to every enemy.`, + }, + ticks: 4, + icon: 'dynamite', + basic: false, + target: 'enemies', + statusEffects: [], + vfx: VFX.catchThrow, + sfx: SFX.boom, + damageModifier: 0.75, + healingModifier: null, + projectile: { icon: 'dynamite', trajectory: 'arc', spin: 720 }, + combatStats: { + criticalChance: -0.5, + }, + }, + + // --- Blacksmith abilities (Brog & Grukk gear). All non-elemental, built from + // existing combat mechanics to fill gaps the pool didn't cover. Icons are new + // placeholder keys pending art (see TODO.md); vfx/sfx reuse existing assets so + // combat renders correctly until bespoke ones are made. --- + rupture: { + name: 'Rupture', + type: TYPE.WindUp, + description: { + simple: 'A deep, tearing cut that floods the wound with heavy bleed buildup.', + extended: + 'A deep, tearing cut that stacks heavy Wounded buildup, tipping the target into Bleeding.', + }, + ticks: 3, + icon: 'rupture', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.wounded, 3]], + vfx: VFX.basicAttackSlow, + sfx: SFX.stab, + damageModifier: 0.95, + healingModifier: null, + }, + dazingBlow: { + name: 'Dazing Blow', + type: TYPE.WindUp, + description: { + simple: 'A rattling swing that leaves the target dazed and prone to missing.', + extended: () => + `A rattling swing to the head that leaves the target Dazed, cutting their hit chance by ${pct(STATUS_EFFECTS.dazed.hitChanceModifierOutgoing)} for half the wind-up.`, + }, + ticks: 2, + icon: 'dazingBlow', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.dazed, 0.5]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 0.85, + healingModifier: null, + }, + pommelStrike: { + name: 'Pommel Strike', + type: TYPE.WindUp, + description: { + simple: 'A fast crack to the head that rattles the skull toward a stun.', + extended: 'A fast crack to the head that stacks Concussed buildup, tipping into a Stun.', + }, + ticks: 2, + icon: 'pommelStrike', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.concussed, 2]], + vfx: VFX.basicAttackFast, + sfx: SFX.slam, + damageModifier: 0.9, + healingModifier: null, + }, + exposeArmor: { + name: 'Expose Armor', + type: TYPE.WindUp, + description: { + simple: 'Pry into a gap in the guard so every later hit lands harder.', + extended: () => + `Pry into a gap in the guard, stacking Exposed buildup that tips into Vulnerable so the target takes ${pct(STATUS_EFFECTS.vulnerable.damageMultiplierIncoming)} more damage.`, + }, + ticks: 2, + icon: 'exposeArmor', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.exposed, 2]], + vfx: VFX.basicAttackSlow, + sfx: SFX.slam, + damageModifier: 0.9, + healingModifier: null, + }, + bloodlust: { + name: 'Bloodlust', + type: TYPE.Channeling, + description: { + simple: + 'Fly into a killing fever, hacking the enemy each tick while critical chance and damage surge. Cannot be interrupted.', + extended: + 'Fly into a killing fever, hacking the enemy each tick. Critical chance and critical damage surge for the duration, so every blow can crit. The cast cannot be interrupted.', + }, + ticks: 4, + chainLink: 4, + icon: 'bloodlust', + basic: false, + target: 'enemy', + statusEffects: [[STATUS_EFFECT.uninterruptable, 1]], + vfx: VFX.basicAttackFast, + sfx: SFX.stab, + damageModifier: 1, + healingModifier: null, + combatStats: { criticalChance: 0.3, criticalDamage: 0.3 }, + }, + bulwark: { + name: 'Bulwark', + type: TYPE.WindDown, + description: { + simple: 'Set your stance behind the shield and take less damage for a time.', + extended: () => + `Set your stance behind the shield — Warded, you take ${pct(STATUS_EFFECTS.warded.damageMultiplierIncoming)} less damage for the duration.`, + }, + ticks: 2, + icon: 'bulwark', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.warded, 3]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + }, + guardian: { + name: 'Guardian', + type: TYPE.WindDown, + description: { + simple: 'Throw your guard over an ally so they take less damage for a time.', + extended: () => + `Throw your guard over an ally — Warded, they take ${pct(STATUS_EFFECTS.warded.damageMultiplierIncoming)} less damage for the duration.`, + }, + ticks: 2, + icon: 'guardian', + basic: false, + target: 'ally', + statusEffects: [[STATUS_EFFECT.warded, 3]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + }, + warBanner: { + name: 'War Banner', + type: TYPE.WindDown, + description: { + simple: 'Plant the banner — the whole team strikes harder for a time.', + extended: () => + `Plant the banner and rally the line — every teammate is Inspired, dealing ${pct(STATUS_EFFECTS.inspired.damageMultiplierOutgoing)} more damage for the duration.`, + }, + ticks: 2, + icon: 'warBanner', + basic: false, + target: 'team', + statusEffects: [[STATUS_EFFECT.inspired, 3]], + vfx: VFX.filler, + sfx: SFX.bling, + damageModifier: null, + healingModifier: null, + }, + aegis: { + name: 'Aegis', + type: TYPE.WindDown, + description: { + simple: 'Raise a guard over the whole team — everyone takes less damage for a time.', + extended: () => + `Raise a guard over the whole team — every teammate is Warded, taking ${pct(STATUS_EFFECTS.warded.damageMultiplierIncoming)} less damage for the duration.`, + }, + ticks: 2, + icon: 'aegis', + basic: false, + target: 'team', + statusEffects: [[STATUS_EFFECT.warded, 2]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + }, + adrenaline: { + name: 'Adrenaline', + type: TYPE.Channeling, + description: { + simple: 'Surge with adrenaline — mend with every beat while shrugging off blows.', + extended: (a) => + `Surge with adrenaline, restoring ${pct(a.calc.healing().result)} of max health each tick — ${pct(a.calc.healing().result * a.chainLink)} across the channel — while taking ${pct(STATUS_EFFECTS.adrenalized.damageMultiplierIncoming)} less damage as you channel.`, + }, + ticks: 6, + chainLink: 6, + icon: 'adrenaline', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.adrenalized, 1]], + vfx: VFX.heal, + sfx: SFX.bling, + damageModifier: null, + healingModifier: 1.3, + }, + unbreakable: { + name: 'Unbreakable', + type: TYPE.WindDown, + description: { + simple: 'Dig in — pull the enemy onto you and shrug off the worst of it.', + extended: () => + `Dig in and roar a challenge — provocation surges to pull attacks onto you while you are Warded, taking ${pct(STATUS_EFFECTS.warded.damageMultiplierIncoming)} less damage.`, + }, + ticks: 3, + icon: 'unbreakable', + basic: false, + target: 'self', + statusEffects: [[STATUS_EFFECT.warded, 4]], + vfx: VFX.filler, + sfx: SFX.armorHit, + damageModifier: null, + healingModifier: null, + combatStats: { provocation: 30 }, + }, +}; + +// Reference tick count where a modifier of 1 yields a full 100% result. Damage +// peaks at 6 ticks; healing is deliberately slower (a full heal wants a 12-tick +// channel), so a short heal is a fraction and chainLink drips cost total. +const DAMAGE_MAX_TICKS = 6; +const HEALING_MAX_TICKS = 6; + +const scalingCalc = (ticks, modifier = 1, maxTicks = DAMAGE_MAX_TICKS) => { + if (modifier === null) return; + + const mod = 1.25; + const base = ticks / maxTicks; + const pow = +Math.pow(base, mod).toFixed(2); + const result = +(pow * modifier).toFixed(2); + + return { base, pow, modifier, result }; +}; + +// chainLink abilities scale off their full duration, then split that result +// evenly across the bites — so the per-bite value × chainLink equals a single +// undivided hit of the same length (no convexity penalty for dripping it out). +const splitForChain = (scaled, chainLink) => + scaled && chainLink ? { ...scaled, result: scaled.result / chainLink } : scaled; + +function damageCalc() { + return splitForChain(scalingCalc(this.ticks, this.damageModifier), this.chainLink); +} + +function healingCalc() { + return splitForChain( + scalingCalc(this.ticks, this.healingModifier, HEALING_MAX_TICKS), + this.chainLink, + ); +} + +function attachCalcs(a) { + Object.defineProperty(a, 'calc', { + enumerable: true, + get() { + return { + damage: damageCalc.bind(a), + healing: healingCalc.bind(a), + }; + }, + }); + return a; +} + +// Merging meta.overrides must not touch the caller's ref — refs are often live +// state ($.characters), and deepMerge mutates its target. Clone first. +export default (id, fullBody = false, meta) => { + const ent = entity( + ALL_ABILITIES, + typeof id === 'string' ? id : id.id, + typeof id === 'string' ? undefined : id.uuid, + fullBody, + typeof id === 'string' + ? meta?.overrides + : meta?.overrides + ? deepMerge(JSON.parse(JSON.stringify(id.overrides || {})), meta.overrides || {}) + : id.overrides, + ); + + if (!fullBody) return ent; + + // Descriptions are presentation-only templates (often functions of the ability) + // resolved on demand from ALL_ABILITIES at tooltip time. They must never ride on + // hydrated instances, which flow into combat teams + saved game state and get + // structuredClone'd — a function there throws DataCloneError. + delete ent.description; + + // chainLink is how many times the ability fires across its duration, so it can + // never exceed ticks — every authored ability keeps an interval (ticks/chainLink) + // of at least one tick. A stale instance whose ticks were overridden without a + // matching chainLink (e.g. a 4-tick whirlwind left on the base chainLink of 10) + // would otherwise read "triggers each 0.4 ticks" and fire sub-tick in combat. + if (ent.chainLink > ent.ticks) ent.chainLink = ent.ticks; + + return attachCalcs(ent); +}; diff --git a/js/constants/ACCESSORY_TYPES.js b/js/constants/ACCESSORY_TYPES.js new file mode 100644 index 00000000..f01e2124 --- /dev/null +++ b/js/constants/ACCESSORY_TYPES.js @@ -0,0 +1,7 @@ +export const ACCESSORY_TYPES = { + ring: { name: 'ring', races: [] }, + amulet: { name: 'amulet', races: [] }, + charm: { name: 'charm', races: [] }, +}; + +export default ACCESSORY_TYPES; diff --git a/js/constants/ACCOUNT_TITLES.js b/js/constants/ACCOUNT_TITLES.js new file mode 100644 index 00000000..76d5fef6 --- /dev/null +++ b/js/constants/ACCOUNT_TITLES.js @@ -0,0 +1,19 @@ +// Account titles — cosmetic banners a player can wear, unlocked by achievements +// (the unlocked set is derived from earned achievements that grant one, so titles +// need no separate store). Placeholder copy for now; revise down the line. +export const ALL_TITLES = { + bloodborn: { + name: 'Bloodborn', + description: 'Drew first blood in the Arena.', + }, + centurion: { + name: 'Centurion', + description: 'A hundred Arena victories to their name.', + }, + ascendant: { + name: 'Ascendant', + description: 'Reached the very height of their power.', + }, +}; + +export default (id) => (id && ALL_TITLES[id] ? { id, ...ALL_TITLES[id] } : undefined); diff --git a/js/constants/ACHIEVEMENTS.js b/js/constants/ACHIEVEMENTS.js new file mode 100644 index 00000000..62452f14 --- /dev/null +++ b/js/constants/ACHIEVEMENTS.js @@ -0,0 +1,151 @@ +// Achievements — long-running objectives whose criteria DERIVE from the statistics +// tree ($.statistics / merged lifetime). Each entry names a stat path + threshold; +// progress and earned-state fall straight out of the numbers already tracked. +// +// scope: +// 'seasonal' — recurs every season; evaluated against the CURRENT season's stats. +// 'account' — permanent; evaluated against LIFETIME (all-season merged) stats. +// reward.title (optional) unlocks an ACCOUNT_TITLES entry on earn. +// scale: stored stats finer-grained than shown (crystals tracked in hundredths) divide +// by this before comparing, so thresholds read in display units. + +export const ACH_CATEGORY_LABELS = { + combat: 'Combat', + progression: 'Progression', + economy: 'Economy', + social: 'Social', +}; + +export const ALL_ACHIEVEMENTS = [ + // ── Seasonal — reset and re-earnable each season ── + { + id: 'seasonFirstWin', + scope: 'seasonal', + category: 'combat', + title: 'First Blood', + icon: 'victory', + path: 'combat.pve.wins', + threshold: 1, + description: 'Win your first fight this season', + reward: { title: 'bloodborn' }, + }, + { + id: 'seasonArenaTen', + scope: 'seasonal', + category: 'combat', + title: 'Arena Regular', + icon: 'brawlers', + path: 'combat.pve.wins', + threshold: 10, + description: 'Win 10 PVE-fights this season', + }, + { + id: 'seasonRisingStar', + scope: 'seasonal', + category: 'progression', + title: 'Rising Star', + icon: 'experience', + path: 'progression.level.amount', + threshold: 10, + description: 'Reach level 10 this season', + }, + { + id: 'seasonCoffers', + scope: 'seasonal', + category: 'economy', + title: 'Coffers Filling', + icon: 'crystal', + path: 'economy.crystals.earned', + threshold: 25, + scale: 100, + description: 'Earn 25 crystals this season', + }, + + // ── Account — permanent, accumulate across every season ── + { + id: 'accountCenturion', + scope: 'account', + category: 'combat', + title: 'Centurion', + icon: 'victory', + path: 'combat.pve.wins', + threshold: 100, + description: 'Win 100 PVE-fights across all seasons', + reward: { title: 'centurion' }, + }, + { + id: 'accountWarlord', + scope: 'account', + category: 'combat', + title: 'Warlord of the Sands', + icon: 'brawlers', + path: 'combat.pve.wins', + threshold: 1000, + description: 'Win 1,000 PVE-fights across all seasons', + }, + { + id: 'accountAscendant', + scope: 'account', + category: 'progression', + title: 'End gamer', + icon: 'experience', + path: 'progression.level.amount', + threshold: 25, + description: 'Reach level 25', + reward: { title: 'ascendant' }, + }, + { + id: 'accountIntoTheWild', + scope: 'account', + category: 'progression', + title: 'Breaking free', + icon: 'the-arena', + path: 'progression.bossHighscore.amount', + threshold: 15, + description: 'Defeat The Emperor', + }, + { + id: 'accountFirstTeamplay', + scope: 'account', + category: 'social', + title: 'Rally Cry', + icon: 'brawlers', + path: 'social.teamplay.created', + threshold: 1, + description: 'Create your first teamplay', + }, +]; + +export const ACHIEVEMENTS_BY_ID = Object.fromEntries(ALL_ACHIEVEMENTS.map((a) => [a.id, a])); + +// Read a leaf out of a statistics tree by dotted path. Count-stats and max-stats both +// store on the leaf node; primitive leaves are bare numbers. Missing path → 0. +export const readStat = (tree, path) => { + const node = path + .split('.') + .reduce((n, k) => (n && n.nodes ? n.nodes[k] : undefined), tree || {}); + if (node == null) return 0; + return typeof node === 'number' ? node : (node.max ?? node.count ?? 0); +}; + +export const achProgress = (ach, tree) => { + const value = readStat(tree, ach.path) / (ach.scale || 1); + return { + value, + threshold: ach.threshold, + ratio: ach.threshold ? Math.min(1, value / ach.threshold) : 0, + met: value >= ach.threshold, + }; +}; + +// Distinct categories present for a scope, in catalog order. +export const scopeCategories = (scope) => + ALL_ACHIEVEMENTS.filter((a) => a.scope === scope).reduce( + (cats, a) => (cats.includes(a.category) ? cats : [...cats, a.category]), + [], + ); + +export const achievementsIn = (scope, category) => + ALL_ACHIEVEMENTS.filter((a) => a.scope === scope && a.category === category); + +export default (id) => ACHIEVEMENTS_BY_ID[id]; diff --git a/js/constants/APP.js b/js/constants/APP.js new file mode 100644 index 00000000..c1c10399 --- /dev/null +++ b/js/constants/APP.js @@ -0,0 +1,20 @@ +export const COMBAT_TICK_TIME = 400; +export const COMBAT_RING_BASE_RADIUS = 250; +// Vertical foreshortening of the combat ring — combatants sit on an ellipse, not a flat +// circle, so the ring reads as lying on the tilted arena floor. boot.js publishes this to +// CSS as --combat-tilt so the visual ring guides and team labels follow the same ellipse. +export const COMBAT_RING_TILT = 0.38; +// The outer (team-label) ring stands more upright than the combatant ring — a taller +// ellipse — so each team's badge floats above its combatants in the distance (top) and +// below them up close (bottom). Higher = more upright (1 = a full circle). +export const COMBAT_OUTER_RING_TILT = 0.72; +// Perspective depth scaling — with the ring tilted, combatants scale linearly with their +// depth: nearest the camera (bottom of the ring) render this much larger, farthest (top) +// this much smaller. Gated by perspectiveEnabled alongside the tilt. +export const COMBAT_RING_DEPTH_SCALE = 0.25; +// Glass-card opacity by depth: nearest the camera (bottom of the ring) is the most +// translucent, fading down to NEAR — the 20% floor — while the farthest (top) is the most +// opaque at FAR. Also gated by perspectiveEnabled. +export const COMBAT_CARD_ALPHA_NEAR = 0.2; +export const COMBAT_CARD_ALPHA_FAR = 0.6; +export const ABILITY_PRIORITY = ['stab', 'pierce', 'punch', 'slam', 'swing', 'whirlwind', 'block']; diff --git a/js/constants/ARENA.js b/js/constants/ARENA.js new file mode 100644 index 00000000..efe35d5b --- /dev/null +++ b/js/constants/ARENA.js @@ -0,0 +1,108 @@ +// The fixed skeleton the season seed fills. Brackets are identical every season — only +// WHICH encounter lands in each slot, and which is promoted to boss, reshuffles, keyed +// deterministically off the season's "YYYY-MM" seed (see js/seasonArena.js). + +// Each bracket spans levels [min, max]; the season seed drops one encounter per slot, +// levels spread evenly. `boss: true` promotes the top-level slot to a boss. 11-15 spans +// only 11-13 and promotes none — the Grand Champion (14) and Emperor (15) anchors cap it. +export const BRACKETS = [ + { tier: '2-5', min: 2, max: 5, boss: true }, + { tier: '6-10', min: 6, max: 10, boss: true }, + { tier: '11-15', min: 11, max: 13, boss: false }, + { tier: '16-20', min: 16, max: 20, boss: true }, + { tier: '21-25', min: 21, max: 25, boss: true }, +]; + +// Slots per bracket = floor(reshuffle pool / 5). Pool is 45 today (66 arena NPCs − 5 +// dragons − 5 gods − 3 sticky bosses). A bracket with fewer eligible encounters than this +// just fills fewer slots; a bracket with more rotates the surplus out each season. Tunable. +export const SLOTS_PER_BRACKET = 9; + +// Each reshuffle fight displays as a level SPAN [slot, slot + SPAN_WIDTH] — e.g. a slot-2 +// fight reads "2 - 4" — to keep the ladder feeling dynamic, and scales as if it sat +// SPAN_LIFT levels above its slot (a slight power-up toward the span's middle). Set +// SPAN_LIFT to 0 for a purely cosmetic span. Anchors and the dragon/god endgame keep an +// exact level. +export const SPAN_WIDTH = 2; +export const SPAN_LIFT = 1; + +// Always-present fights at fixed levels, outside the reshuffle. Lost Civilian opens the +// arena, Grand Champion + Emperor cap the mid-game, dragons (30) and gods (40) are the +// sticky endgame. `boss` grants the boss-stat bonus and the large card frame. +export const ANCHORS = { + 'lost-civilian': { level: 1, boss: false }, + 'the-grand-champion': { level: 14, boss: true }, + 'the-emperor': { level: 15, boss: true }, + 'nature-giant': { level: 25, boss: false }, + ignius: { level: 30, boss: true }, + 'frigus-mortis': { level: 30, boss: true }, + 'vita-deserto': { level: 30, boss: true }, + 'erat-herba': { level: 30, boss: true }, + 'vento-mico': { level: 30, boss: true }, + 'ragnar-god-of-fire': { level: 40, boss: true }, + 'kyl-god-of-frost': { level: 40, boss: true }, + 'elise-goddess-of-earth': { level: 40, boss: true }, + 'alora-goddess-of-nature': { level: 40, boss: true }, + 'oskar-god-of-lightning': { level: 40, boss: true }, +}; + +// The reshuffle pool for each bracket, by fight id. Seeded into the bracket's slots each +// season. Seeded from each fight's old level midpoint; retune freely. A fight listed in +// neither a pool nor ANCHORS never appears in the arena. +export const TIER_POOLS = { + '2-5': [ + 'crazy-old-man', + 'pitchfork-patrick', + 'poor-poor-knight', + 'jester', + 'sabertooth-tiger', + 'nomad', + 'giant-scorpion', + 'boar', + 'giant-rat', + ], + '6-10': [ + 'queen-arachnae', + 'regular-sized-combatant', + 'executioner', + 'beastmaster', + 'hyena', + 'pack-of-wolves', + 'the-engineer', + 'rhino', + 'plague-doctor', + 'desert-bandits', + 'goblin-warband', + ], + '11-15': [ + 'secutor', + 'blind-swordsman', + 'dimachaerus', + 'war-elephant', + 'grizzly-bear', + 'succubus', + 'golem', + ], + '16-20': ['breff', 'armorillo', 'wyvern', 'mammoth', 'owl-bear', 'bullrock'], + '21-25': [ + 'cerberus', + 'ulwar', + 'herald', + 'rune-stag', + 'yeti', + 'lightning-giant', + 'onkh', + 'warrus', + 'fire-giant', + 'earth-giant', + 'frost-giant', + ], +}; + +// Spread n slots across [min, max], levels rising; the last slot is the boss when the +// bracket promotes one. Returns [{ level, boss }] ascending, so the arena reads in order. +export const bracketSlots = (min, max, n, boss) => + Array.from({ length: n }, (_, i) => ({ + level: n === 1 ? max : Math.round(min + ((max - min) * i) / (n - 1)), + boss: boss && i === n - 1, + })); diff --git a/js/constants/ARMOR_TYPES.js b/js/constants/ARMOR_TYPES.js new file mode 100644 index 00000000..931b73a2 --- /dev/null +++ b/js/constants/ARMOR_TYPES.js @@ -0,0 +1,7 @@ +export const ARMOR_TYPES = { + light: { name: 'light', races: [] }, + medium: { name: 'medium', races: [] }, + heavy: { name: 'heavy', races: [] }, +}; + +export default ARMOR_TYPES; diff --git a/js/constants/AVAILABLE_KEYS.js b/js/constants/AVAILABLE_KEYS.js new file mode 100644 index 00000000..c57f495b --- /dev/null +++ b/js/constants/AVAILABLE_KEYS.js @@ -0,0 +1,34 @@ +export default [ + 'keyw', + 'keya', + 'keys', + 'keyd', + 'keyi', + 'keyq', + 'keye', + 'keyz', + 'keyx', + 'keyc', + 'arrowright', + 'arrowleft', + 'arrowdown', + 'arrowup', + 'escape', + 'enter', + 'shiftleft', + 'shiftright', + 'digit1', + 'digit2', + 'digit3', + 'digit4', + 'digit5', + 'numpad1', + 'numpad2', + 'numpad3', + 'numpad4', + 'numpad5', + 'numpad6', + 'numpad7', + 'numpad8', + 'numpad9', +].reduce((a, key) => ({ ...a, [key]: false }), {}); diff --git a/js/constants/BOT_NAMES.js b/js/constants/BOT_NAMES.js new file mode 100644 index 00000000..53823cf7 --- /dev/null +++ b/js/constants/BOT_NAMES.js @@ -0,0 +1,506 @@ +// Docker-style surnames (the right-of-dash half of "jovial-brattain") — famous +// scientists, mathematicians, engineers and naturalists. Used only by the bot seeder +// (scripts/seed-bots-core.js) to give each seeded bot a real accountName; stored on the +// bot's game-state doc and read straight back in teamplay. Lowercase; capitalised on use. +export const BOT_NAMES = [ + 'lovelace', + 'turing', + 'hopper', + 'babbage', + 'noether', + 'hypatia', + 'brattain', + 'colden', + 'lamarr', + 'curie', + 'einstein', + 'newton', + 'galileo', + 'kepler', + 'copernicus', + 'hawking', + 'bohr', + 'heisenberg', + 'schrodinger', + 'dirac', + 'feynman', + 'planck', + 'faraday', + 'maxwell', + 'tesla', + 'edison', + 'volta', + 'ampere', + 'ohm', + 'watt', + 'joule', + 'kelvin', + 'boyle', + 'dalton', + 'mendeleev', + 'pauling', + 'lavoisier', + 'priestley', + 'bunsen', + 'arrhenius', + 'darwin', + 'mendel', + 'pasteur', + 'koch', + 'fleming', + 'salk', + 'sabin', + 'lister', + 'jenner', + 'harvey', + 'linnaeus', + 'wallace', + 'goodall', + 'carson', + 'muir', + 'audubon', + 'cousteau', + 'attenborough', + 'leakey', + 'fossey', + 'euler', + 'gauss', + 'riemann', + 'cantor', + 'fermat', + 'pascal', + 'leibniz', + 'fibonacci', + 'ramanujan', + 'erdos', + 'hilbert', + 'godel', + 'cauchy', + 'laplace', + 'lagrange', + 'poincare', + 'galois', + 'abel', + 'jacobi', + 'bernoulli', + 'archimedes', + 'euclid', + 'pythagoras', + 'ptolemy', + 'democritus', + 'thales', + 'eratosthenes', + 'apollonius', + 'diophantus', + 'hubble', + 'sagan', + 'herschel', + 'halley', + 'tycho', + 'brahe', + 'cassini', + 'huygens', + 'kuiper', + 'oort', + 'franklin', + 'watson', + 'crick', + 'wilkins', + 'mcclintock', + 'morgan', + 'sanger', + 'avery', + 'chargaff', + 'khorana', + 'shannon', + 'neumann', + 'mccarthy', + 'minsky', + 'dijkstra', + 'knuth', + 'ritchie', + 'thompson', + 'kernighan', + 'torvalds', + 'cerf', + 'kahn', + 'engelbart', + 'licklider', + 'sutherland', + 'backus', + 'hamming', + 'hoare', + 'liskov', + 'lamport', + 'wozniak', + 'kilby', + 'noyce', + 'moore', + 'shockley', + 'bardeen', + 'hoerni', + 'faggin', + 'hoff', + 'mazor', + 'galvani', + 'coulomb', + 'oersted', + 'henry', + 'weber', + 'siemens', + 'hertz', + 'roentgen', + 'becquerel', + 'rutherford', + 'thomson', + 'chadwick', + 'fermi', + 'oppenheimer', + 'teller', + 'szilard', + 'meitner', + 'hahn', + 'joliot', + 'yalow', + 'gell', + 'higgs', + 'weinberg', + 'glashow', + 'salam', + 'wheeler', + 'penrose', + 'thorne', + 'susskind', + 'witten', + 'feigenbaum', + 'mandelbrot', + 'lorenz', + 'turcotte', + 'prandtl', + 'reynolds', + 'navier', + 'stokes', + 'bernay', + 'venturi', + 'bessel', + 'fourier', + 'legendre', + 'hermite', + 'markov', + 'kolmogorov', + 'chebyshev', + 'lyapunov', + 'sobolev', + 'banach', + 'hausdorff', + 'lebesgue', + 'borel', + 'weierstrass', + 'dedekind', + 'kronecker', + 'klein', + 'lie', + 'weyl', + 'grothendieck', + 'serre', + 'tao', + 'perelman', + 'wiles', + 'conway', + 'nash', + 'shamir', + 'rivest', + 'adleman', + 'diffie', + 'hellman', + 'merkle', + 'goldwasser', + 'blum', + 'yao', + 'karp', + 'cook', + 'levin', + 'rabin', + 'scott', + 'floyd', + 'tarjan', + 'hopcroft', + 'ullman', + 'aho', + 'sethi', + 'wirth', + 'iverson', + 'perlis', + 'newell', + 'simon', + 'lenat', + 'brooks', + 'hinton', + 'bengio', + 'lecun', + 'schmidhuber', + 'hochreiter', + 'vapnik', + 'valiant', + 'pearl', + 'kahneman', + 'tversky', + 'chomsky', + 'skinner', + 'pavlov', + 'jung', + 'piaget', + 'vygotsky', + 'maslow', + 'milgram', + 'asch', + 'festinger', + 'bandura', + 'tinbergen', + 'frisch', + 'wilson', + 'hamilton', + 'maynard', + 'trivers', + 'dawkins', + 'gould', + 'eldredge', + 'margulis', + 'lovelock', + 'haldane', + 'fisher', + 'wright', + 'dobzhansky', + 'mayr', + 'simpson', + 'huxley', + 'hooke', + 'leeuwenhoek', + 'malpighi', + 'schleiden', + 'schwann', + 'virchow', + 'ramon', + 'golgi', + 'nissl', + 'sherrington', + 'eccles', + 'hodgkin', + 'katz', + 'loewi', + 'dale', + 'banting', + 'best', + 'macleod', + 'houssay', + 'cori', + 'krebs', + 'lipmann', + 'calvin', + 'kornberg', + 'nirenberg', + 'ochoa', + 'jacob', + 'monod', + 'lwoff', + 'delbruck', + 'luria', + 'hershey', + 'lederberg', + 'tatum', + 'beadle', + 'ames', + 'berg', + 'boyer', + 'cohen', + 'mullis', + 'smith', + 'sharp', + 'roberts', + 'gilbert', + 'maxam', + 'venter', + 'collins', + 'lander', + 'church', + 'doudna', + 'charpentier', + 'zhang', + 'blackburn', + 'greider', + 'szostak', + 'hall', + 'rosbash', + 'young', + 'kandel', + 'axel', + 'buck', + 'tonegawa', + 'jerne', + 'kohler', + 'milstein', + 'edelman', + 'porter', + 'burnet', + 'medawar', + 'snell', + 'dausset', + 'benacerraf', + 'doherty', + 'zinkernagel', + 'steinman', + 'beutler', + 'hoffmann', + 'allison', + 'honjo', + 'lindqvist', + 'gurdon', + 'yamanaka', + 'wilmut', + 'campbell', + 'evans', + 'capecchi', + 'smithies', + 'brenner', + 'sulston', + 'horvitz', + 'nurse', + 'hunt', + 'hartwell', + 'greengard', + 'carlsson', + 'wiesel', + 'hubel', + 'sperry', + 'penfield', + 'broca', + 'wernicke', + 'cajal', + 'purkinje', + 'betz', + 'meynert', + 'brodmann', + 'gall', + 'flourens', + 'magendie', + 'bernard', + 'ludwig', + 'helmholtz', + 'wundt', + 'fechner', + 'ebbinghaus', + 'thorndike', + 'tolman', + 'hull', + 'wertheimer', + 'koffka', + 'lewin', + 'allport', + 'rogers', + 'ellis', + 'beck', + 'seligman', + 'csikszentmihalyi', + 'gardner', + 'sternberg', + 'binet', + 'terman', + 'wechsler', + 'spearman', + 'thurstone', + 'cattell', + 'eysenck', + 'costa', + 'mcrae', + 'goldberg', + 'gibbs', + 'clausius', + 'carnot', + 'nernst', + 'onsager', + 'debye', + 'flory', + 'staudinger', + 'ziegler', + 'natta', + 'wittig', + 'grignard', + 'sabatier', + 'haber', + 'bosch', + 'ostwald', + 'raoult', + 'vant', + 'lewis', + 'langmuir', + 'mulliken', + 'slater', + 'hund', + 'fock', + 'hartree', + 'roothaan', + 'pople', + 'kohn', + 'parr', + 'bader', + 'woodward', + 'corey', + 'sharpless', + 'noyori', + 'knowles', + 'grubbs', + 'schrock', + 'chauvin', + 'heck', + 'negishi', + 'suzuki', + 'sonogashira', + 'buchwald', + 'hartwig', + 'macmillan', + 'list', + 'benjamin', + 'crutzen', + 'molina', + 'rowland', + 'keeling', + 'revelle', + 'tyndall', + 'milankovic', + 'wegener', + 'hess', + 'vine', + 'matthews', + 'holmes', + 'bullard', + 'richter', + 'gutenberg', + 'mohorovicic', + 'lehmann', + 'oldham', + 'love', + 'rayleigh', + 'boltzmann', + 'poisson', + 'green', + 'kirchhoff', + 'doppler', + 'fizeau', + 'foucault', + 'fresnel', + 'fraunhofer', + 'zeeman', + 'stark', + 'compton', + 'raman', + 'brillouin', + 'bragg', + 'laue', + 'scherrer', + 'ewald', + 'patterson', + 'perutz', + 'kendrew', + 'klug', + 'henderson', +]; diff --git a/js/constants/CHARACTERS.js b/js/constants/CHARACTERS.js new file mode 100644 index 00000000..e527a1bb --- /dev/null +++ b/js/constants/CHARACTERS.js @@ -0,0 +1,3413 @@ +import ABILITIES from '/js/constants/ABILITIES.js'; +import { ALL_RACES } from '/js/constants/RACES.js'; +import { ZERO_RESISTANCES } from '/js/constants/ELEMENTS.js'; +import { DEFAULT_TOLERANCE } from '/js/constants/TOLERANCE.js'; +import entity from '/js/entity.js'; +import { deepMerge } from '/js/helpers.js'; +import EQUIPMENT from '/js/constants/EQUIPMENT.js'; + +const DEFAULT_MAX_HP = 24; +const DEFAULT_DAMAGE = 8; +const DEFAULT_MAX_TICKS = 15; + +export const DEFAULT_MUGSHOT_COORDINATES = { x: 0, y: 0 }; + +export const DEFAULT_MODIFIERS = { + maxHealth: 0, + maxArmor: 0, + damage: 0, + tolerance: 0, +}; + +export const DEFAULT_LUCKY_STATS = { + hitChance: 1, + criticalChance: 0.05, + criticalDamage: 0.5, + dodgeChance: 0.05, + blockChance: 0, + magicChance: 0, +}; + +const DEFAULT_RESISTANCES = ZERO_RESISTANCES; + +export const DEFAULT_EQUIPMENT = { + mainHand: null, + offHand: null, + armor: null, + accessory: null, + trinket: null, +}; + +const DEFAULT_NPC_EQUIPMENT = { + mainHand: null, + offHand: null, + armor: null, + accessory: null, + trinket: null, +}; + +export const ALL_CHARACTERS = { + elfMale: { + name: 'Brawler', + race: ALL_RACES.elf, + type: 'humanoid', + image: 'elf/male-01.webp', + mugshot: { x: 40, y: 20 }, + size: 1.2, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A patient elven archer who picks his shots and rarely misses. Keep him at the back and let the arrows do the work.', + ai: { + imageContext: + 'Lean male archer drawing a longbow with a nocked arrow\n\nLong blond hair, pointed ears, dark leather vest over a tunic, olive trousers, a quiver of arrows on the back', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP - 4, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 3, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.03, + magicChance: DEFAULT_LUCKY_STATS.magicChance + 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('pierce'), ABILITIES('pierce'), ABILITIES('pierce'), ABILITIES('pierce')], + signatureAbility: ABILITIES('alorasTouch'), + }, + elfFemale: { + name: 'Brawler', + race: ALL_RACES.elf, + type: 'humanoid', + image: 'elf/female-01.webp', + mugshot: { x: 34, y: 9 }, + size: 1.05, + equipment: { + ...DEFAULT_EQUIPMENT, + mainHand: EQUIPMENT('bow'), + armor: EQUIPMENT('paddedTunic'), + }, + description: + 'A swift elven duelist with a blade in each hand. She trades reach for a flurry of cuts and slips away before you can answer.', + ai: { + imageContext: + 'Female warrior holding a slender sword in each hand, glancing back over her shoulder\n\nLong blonde hair, pointed ears, hooded olive-green cloak over a grey dress covering her left side and the handle for one of the swords shes holding, brown boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP - 4, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 2, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.03, + magicChance: DEFAULT_LUCKY_STATS.magicChance + 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('pierce'), ABILITIES('pierce'), ABILITIES('pierce'), ABILITIES('pierce')], + signatureAbility: ABILITIES('alorasTouch'), + }, + humanMale: { + name: 'Brawler', + race: ALL_RACES.human, + type: 'humanoid', + image: 'human/male-01.webp', + mugshot: { x: 55, y: 13 }, + size: 1, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A roaring berserker with an axe in each hand and no plan beyond hitting things until they stop moving.', + ai: { + imageContext: + 'Muscular bare-chested berserker roaring with mouth open, a hand axe in each fist\n\nLong grey hair tied up, thick beard, tribal tattoos, fur mantle over the shoulders, fur kilt, fur-lined boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + damage: DEFAULT_MODIFIERS.damage + 0.05, + tolerance: DEFAULT_MODIFIERS.tolerance + 0.1, + }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('swing'), ABILITIES('swing'), ABILITIES('swing'), ABILITIES('swing')], + signatureAbility: ABILITIES('warcry'), + }, + humanFemale: { + name: 'Brawler', + race: ALL_RACES.human, + type: 'humanoid', + image: 'human/female-01.webp', + mugshot: { x: 47, y: 9 }, + size: 1, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A disciplined shield-maiden who holds the line. Sword forward, shield up, and very hard to push back.', + ai: { + imageContext: + 'Female warrior with a broad sword in one hand angled downwards at the side and a round wooden shield in the other close to body.\n\nLong brown hair, simple, war paint on the face, studded leather armor with fur-trimmed shoulders, fur-lined boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + blockChance: DEFAULT_LUCKY_STATS.blockChance + 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + damage: DEFAULT_MODIFIERS.damage + 0.04, + tolerance: DEFAULT_MODIFIERS.tolerance + 0.1, + }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('swing'), + ABILITIES('swing'), + ABILITIES('block'), + ABILITIES('shieldBash'), + ], + signatureAbility: ABILITIES('warcry'), + }, + trollMale: { + name: 'Brawler', + race: ALL_RACES.troll, + type: 'humanoid', + image: 'troll/male-01.webp', + mugshot: { x: 46, y: 18 }, + size: 1.1, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A mountain of troll dragging a tree-sized club. Slow to wind up, but every swing lands like a falling boulder.', + ai: { + imageContext: + 'Fat non-muscular male brute resting a massive wooden club on one shoulder\n\nLight brown, large round belly, small-tusked underbite, small topknot, fur loincloth with a skull, tooth necklace, barefoot, barely any neck, no pupils, one hand scratching belly, huge over-arms', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance - 0.05, + }, + armorPenetration: 1, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + maxHealth: DEFAULT_MODIFIERS.maxHealth + 0.05, + damage: DEFAULT_MODIFIERS.damage + 0.06, + }, + magicChance: 0, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('slam'), ABILITIES('slam'), ABILITIES('slam')], + signatureAbility: ABILITIES('stomp'), + }, + trollFemale: { + name: 'Brawler', + race: ALL_RACES.troll, + type: 'humanoid', + image: 'troll/female-01.webp', + mugshot: { x: 40, y: 12 }, + size: 1.1, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + "Twice the clubs, twice the bruises. She wades straight in swinging and isn't fussy about what she hits.", + ai: { + imageContext: + 'Large fat & non-muscular female brute with studded wooden club in each hand resting at her sides angled downwards.\n\nLight brown skin, brown dreadlocked hair in a tail, small tusks, tribal fur top and fur skirt, barefoot', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + damage: DEFAULT_DAMAGE, + maxArmor: 0, + currentArmor: 0, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance - 0.05, + }, + armorPenetration: 1, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + maxHealth: DEFAULT_MODIFIERS.maxHealth + 0.1, + damage: DEFAULT_MODIFIERS.damage + 0.05, + }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('slam', false, { + overrides: { ticks: 3 }, + }), + ABILITIES('slam', false, { + overrides: { ticks: 3 }, + }), + ABILITIES('slam', false, { + overrides: { ticks: 3 }, + }), + ABILITIES('slam', false, { + overrides: { ticks: 3 }, + }), + ], + signatureAbility: ABILITIES('stomp'), + }, + dwarfMale: { + name: 'Brawler', + race: ALL_RACES.dwarf, + type: 'humanoid', + image: 'dwarf/male-01.webp', + mugshot: { x: 50, y: 26 }, + size: 0.8, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + "A stubborn dwarf behind a wall of a shield. He'll outlast whatever you throw at him, then flatten what's left.", + ai: { + imageContext: + 'Stout dwarf facing left raising a war hammer in the background arm, a large steel kite shield on the foreground arm, no emblem on shield\n\nLong braided brown beard, mohawk haircut, brown leather armor and boots, fierce scowl', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance - 0.03, + blockChance: DEFAULT_LUCKY_STATS.blockChance + 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + maxArmor: DEFAULT_MODIFIERS.maxArmor + 0.15, + maxHealth: DEFAULT_MODIFIERS.maxHealth + 0.1, + tolerance: DEFAULT_MODIFIERS.tolerance + 0.1, + }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('slam'), ABILITIES('slam'), ABILITIES('block'), ABILITIES('shieldBash')], + signatureAbility: ABILITIES('stoneskin'), + }, + dwarfFemale: { + name: 'Brawler', + race: ALL_RACES.dwarf, + type: 'humanoid', + image: 'dwarf/female-01.webp', + mugshot: { x: 54, y: 11 }, + size: 0.8, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A dwarven warrior in full plate swinging a runed great axe. Heavy armor, heavier blows, and not one step back.', + ai: { + imageContext: + 'Stout female dwarf hoisting a two-handed great axe with a rune-etched blade held in both hands\n\nBraided hair, no face hair, full steel plate armor and gauntlets, dark apron', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance - 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 8, + }, + modifiers: { + ...DEFAULT_MODIFIERS, + maxArmor: DEFAULT_MODIFIERS.maxArmor + 0.2, + maxHealth: DEFAULT_MODIFIERS.maxHealth + 0.05, + tolerance: DEFAULT_MODIFIERS.tolerance + 0.1, + }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('swing', false, { overrides: { ticks: 4 } }), + ABILITIES('swing', false, { overrides: { ticks: 4 } }), + ABILITIES('swing', false, { overrides: { ticks: 4 } }), + ], + signatureAbility: ABILITIES('taunt'), + }, + goblinMale: { + name: 'Brawler', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'goblin/male-01.webp', + mugshot: { x: 56, y: 19 }, + size: 0.8, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + 'A grinning goblin cutthroat with a dagger in each fist. Small, quick, and always aiming for somewhere that hurts.', + ai: { + imageContext: + 'Small crouching goblin grinning wickedly, a dagger in each hand held in a reverse grip\n\nGreen skin, huge pointed ears, hooded brown cloak, leather harness, clawed bare feet', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP - 2, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 4, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: DEFAULT_LUCKY_STATS.criticalChance + 0.02, + criticalDamage: DEFAULT_LUCKY_STATS.criticalDamage + 0.2, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.02, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('stab'), + ABILITIES('stab'), + ABILITIES('stab'), + ABILITIES('stab'), + ABILITIES('stab'), + ABILITIES('stab'), + ], + signatureAbility: ABILITIES('catch'), + }, + goblinFemale: { + name: 'Brawler', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'goblin/female-01.webp', + mugshot: { x: 70, y: 37 }, + size: 1.2, + equipment: { ...DEFAULT_EQUIPMENT, armor: EQUIPMENT('paddedTunic') }, + description: + "A goblin skirmisher who keeps you at spear's length and jabs from just out of reach. Annoying, and proud of it.", + ai: { + imageContext: + 'Small female goblin holding a long tasseled spear upright in both hands\n\nGreen skin, large pointed ears, dented metal helmet, dark red tunic with leather armor and bracers', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP - 2, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 3, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: DEFAULT_LUCKY_STATS.criticalChance + 0.03, + criticalDamage: DEFAULT_LUCKY_STATS.criticalDamage + 0.15, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.01, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('swing'), ABILITIES('swing'), ABILITIES('swing'), ABILITIES('swing')], + signatureAbility: ABILITIES('smokebomb'), + }, + succubus: { + name: 'Succubus', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/succubus.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.2, + equipment: DEFAULT_NPC_EQUIPMENT, + description: + 'The Succubus is a deadly demon whose elegance masks her savage nature. In battle, she thrives amid chaos, lashing out with razor-sharp claws in a flurry of violent motion.

Her signature attack is a whirling dance of destruction, spinning with unrelenting speed to strike all who dare draw near. This devastating technique carves through groups of enemies with merciless efficiency, leaving little chance for escape.', + ai: { + imageContext: + 'Pale grey-skinned demoness, slender and gaunt.\n\nLong black hair and large curved ram horns.\n\nPointed ears, glowing pale eyes, long clawed fingers.\n\nA sinuous dark-red tail coiling around her.\n\nDangling a small stitched puppet from its strings.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: { + ...DEFAULT_TOLERANCE, + immobilize: DEFAULT_TOLERANCE.immobilize + 12, + }, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('crushingBlow'), + ABILITIES('whirlwind', false, { overrides: { basic: true } }), + ], + }, + rat: { + name: 'Giant rat', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/rat.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.15, + equipment: DEFAULT_NPC_EQUIPMENT, + description: + 'The Giant Rat is a vile and tenacious creature, driven by an insatiable hunger. Its bite is vicious and infectious, leaving deep wounds that continue to bleed long after the initial strike.

When not attacking, it retreats to feast on nearby scraps of food. This gluttonous act rapidly restores its health, making it a persistent and frustrating foe to defeat if left unchecked.', + ai: { + imageContext: + 'Non-muscular hulking rat rearing up on its hind legs, jaws closed and snarling\n\nMangy black fur, long pink scaly tail, sharp yellow teeth, beady black eyes, pale white eye balls', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP + 12, + currentHealth: DEFAULT_MAX_HP + 12, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('bite'), ABILITIES('cheesyTactics'), ABILITIES('bite')], + }, + golem: { + name: 'Golem', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/golem.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.2, + equipment: DEFAULT_NPC_EQUIPMENT, + description: + 'The Golem is a towering sentinel of stone, crafted for war and built to endure. Its immense frame makes it a formidable presence on the battlefield, shrugging off attacks that would shatter lesser foes.

When its armor is even partially intact, it draws upon ancient magic to restore its defenses completely, becoming nearly invulnerable once more. Only those who can deplete its armor fully stand a chance of bringing it down.', + ai: { + imageContext: + 'Avarage non-muscular build but big overbody. Hunchback hewn from pale grey stone.\n\nBroad hunched shoulders and oversized fists.\n\nCracked rock plating streaked with green moss.\n\nWorn runes carved across its chest.\n\nHeavy, blunt and immovable.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 3, + currentArmor: 3, + damage: DEFAULT_DAMAGE, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + criticalChance: null, + criticalDamage: null, + blockChance: null, + dodgeChance: null, + hitChance: null, + magicChance: null, + }, + maxTicks: Infinity, + abilities: [ABILITIES('slam'), ABILITIES('harden'), ABILITIES('slam'), ABILITIES('slam')], + }, + trainingDummy: { + name: 'Training Dummy', + race: ALL_RACES.creature, + type: 'prop', + image: 'creature/training-dummy.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A burlap sack stitched onto a post, painted with a target and patched after a thousand bouts. It never strikes back — it only stands there and takes it.

Perfect for warming up. Just do not expect it to fall over.', + ai: { + imageContext: + 'A casual stuffed practice dummy mounted on a wooden post, arms (only) made of a straw-bound crossbar\n\nPale burlap sackcloth body with stitched seams, black button eyes, straw poking from the limbs, a red painted bullseye on its chest.', + legs: 0, + }, + combatStats: { + maxHealth: 100, + currentHealth: 100, + maxArmor: 0, + currentArmor: 0, + damage: 0, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('playingTheVictim')], + }, + boar: { + name: 'Boar', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/boar.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A young one, but fed well and angry at strangers. The tusks have done damage to better fighters than the registry admits.

Watch the charge. The rest is easier.', + ai: { + imageContext: + 'Wild boar mid-charge with its head lowered and tusks forward\n\nBristly brown fur, large curved ivory tusks, small dark eyes, a coarse ridged mane along the spine', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + criticalDamage: 0.6, + }, + maxTicks: Infinity, + abilities: [ABILITIES('charge'), ABILITIES('gore'), ABILITIES('gore'), ABILITIES('gore')], + }, + jester: { + name: 'Jester', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/jester.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'All bells and balance, until the knives come out from under the motley.

He laughs while you bleed. The crowd loves it.', + ai: { + imageContext: + 'Slender jester posed mid-flourish, one hand on the hip, a curved dagger drawn in the other\n\nRed and black diamond-pattern motley, belled jester cap, pale grinning mask, curled pointed shoes with bells', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: DEFAULT_LUCKY_STATS.criticalChance + 0.05, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('stab'), + ABILITIES('doublePersona'), + ABILITIES('stab'), + ABILITIES('doublePersona'), + ABILITIES('stab'), + ], + }, + lostCivilian: { + name: 'Lost civilian', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/lost-civilian.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: 'This civilian took the wrong turn when going shopping and ended up in the arena.', + ai: { + imageContext: + 'Ordinary young man standing and reading a paper map, looking lost and worried\n\nShort brown hair, plain brown tunic and trousers, leather belt with a small pouch, worn boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 2, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.4, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('punch'), + ABILITIES('punch'), + ABILITIES('punch'), + ABILITIES('punch'), + ABILITIES('punch'), + ABILITIES('punch'), + ], + }, + nomad: { + name: 'Nomad', + race: ALL_RACES.creature, + type: 'humanoid', + image: 'creature/nomad.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "Traveled the salt road for thirty years without losing a tooth. The arena offers a hot meal and a roof, so here he is.

Don't let the years fool you. He still walks twenty miles before breakfast.", + ai: { + imageContext: + 'Hooded wanderer standing upright, gripping a tall spear staff\n\nWeathered teal cloak, layered desert robes, leather wraps and armor, face shadowed under the hood, dusty boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('stab', false, { overrides: { ticks: 4 } }), + ABILITIES('stab'), + ABILITIES('stab', false, { overrides: { ticks: 4 } }), + ABILITIES('stab'), + ], + }, + pitchforkPatrick: { + name: 'Pitchfork Patrick', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/pitchfork-patrick.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "Came down from the hills with his farm tool and a complaint about taxes. The magistrate sent him to the arena instead.

He's still using the pitchfork. He's still winning fights.", + ai: { imageContext: 'Proud stance holding a pitchfork\n\nSimple farmer clothing', legs: 2 }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('pretendToBeHumble')], + }, + poorestKnightInTown: { + name: 'Poor poor knight', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/poorest-knight-in-town.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "His armor is held together with twine and stubborn pride. The sword is real, though, and so is the training.

He fights for the coin, not the glory. There hasn't been much of either lately.", + ai: { + imageContext: + 'A really poor knight\n\nBad equipment\n\nLooks weak\n\nNot too much detail\n\nSimple design\n\nYoung lad\n\nShy pose\n\nHand-drawn\n\nWields wooded sword and broken shield', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + blockChance: 0.05, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('swing'), + ABILITIES('block', false, { overrides: { ticks: 2 } }), + ABILITIES('swing'), + ABILITIES('block', false, { overrides: { ticks: 2 } }), + ABILITIES('swing'), + ], + }, + sabertoothTiger: { + name: 'Sabertooth Tiger', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/sabertooth-tiger.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'An ancient predator, woken from frozen sleep by a foolish magus and sold to the arena for the bounty.

The bite is meant for mammoth bone. Yours will not be a challenge for it.', + ai: { + imageContext: + 'Sabertooth tiger lunging forward, mouth open in a roar, one clawed paw raised\n\nMuscular orange coat with dark stripes, pale underbelly, long curved saber fangs', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.6, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('pounce'), + ABILITIES('ripAndTear'), + ABILITIES('ripAndTear'), + ABILITIES('ripAndTear'), + ABILITIES('ripAndTear'), + ], + }, + queenArachnae: { + name: 'Queen Arachnae', + race: ALL_RACES.spider, + type: 'creature', + image: 'creature/queen-arachnae.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + power: 2, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'She nests in the crawlspaces beneath the arena, grown fat on whatever loses down there. The egg sacs she drags behind her are never empty for long.', + ai: { + imageContext: + 'Massive bloated spider crouched low on all eight legs, fangs bared\n\nSwollen dark green and brown carapace, thick segmented legs, a cluster of small yellow eyes, dripping fangs', + legs: 8, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + provocation: 13, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: { ...DEFAULT_MODIFIERS, maxArmor: 0 }, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('skewer'), ABILITIES('skewer'), ABILITIES('skewer')], + }, + spiderling: { + name: 'Spiderling', + race: ALL_RACES.spider, + type: 'creature', + image: 'creature/spiderling.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 0.5, + power: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "Fresh from the Queen Arachnae's egg sacs and already hunting. One is a nuisance; they are never one.", + ai: { + imageContext: + 'Small spider scuttling forward on splayed legs\n\nRound green-mottled abdomen, slender brown legs, small pale fangs, tiny dark eyes', + legs: 6, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: DEFAULT_LUCKY_STATS.dodgeChance + 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('weave'), ABILITIES('skewer', false, { overrides: { ticks: 3 } })], + }, + ignius: { + name: 'Ignius', + race: ALL_RACES.dragon, + type: 'creature', + image: 'creature/fire/ignius.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A young dragon caged beneath the arena and starved until the gates open. The scorch marks on the sand are older than most of the fighters who made them.', + ai: { + imageContext: + 'Classic red dragon, scaled and broad.\n\nDeep crimson hide over a paler green-tan belly and chest plates.\n\nLeathery wings half-spread.\n\nA horned head and a ridge of spines down its back.\n\nFour clawed legs and a heavy tail.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + provocation: 30, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: 15, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('fireBreath'), + ABILITIES('charge'), + ABILITIES('emberStrike'), + ABILITIES('bite'), + ABILITIES('emberStrike'), + ], + }, + scorchLing: { + name: 'Scorchling', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/scorch-ling.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 0.5, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "Ignius's whelp, hatched in the same cage and already breathing embers. It fights to prove itself to a parent that has never once looked its way.", + ai: { + imageContext: + 'Small dragon whelp standing on all fours, leathery wings half-raised\n\nRed scaled hide with glowing ember cracks, glowing orange eyes, stubby horns, a long tail', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ], + }, + dragonEgg: { + name: 'Dragon Egg', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/dragon-egg.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 0.5, + power: 0.15, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Too hot to touch and glowing faintly from within, as if a coal were trying to claw its way out. The Scorchling coiled inside is already burning to meet the arena.', + ai: { + imageContext: + 'A single large dragon egg resting upright\n\nMottled red and grey shell etched with dark crack-like runic markings, a faint inner glow as if embers smolder within', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('hatch')], + }, + crazyOldMan: { + name: 'Crazy Old Man', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/crazy-old-man.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A few drinks in and bored of a quiet life, he wandered into the arena for a bit of a thrill. He means no harm — he just fancied a story worth telling at the tavern.', + ai: { + imageContext: + 'Not a magician.\n\nSimple villager.\n\nOld and foolish.\n\nHolds a broken bottle as weapon. No backpack.\n\nDrunk and fighting stance', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('swing'), + ABILITIES('lacerate'), + ABILITIES('swing'), + ABILITIES('lacerate'), + ABILITIES('stab'), + ], + }, + dimachaerus: { + name: 'Dimachaerus', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/dimachaerus.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Two blades, no shield, and not a scrap of patience for either. He trades every defense for a storm of steel meant to end the fight in the opening breath.

Outlast the first flurry and you may yet live to watch him tire.', + ai: { imageContext: 'Simple hand-drawn design, sketch', legs: 2 }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.2, + criticalDamage: 0.8, + dodgeChance: 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('cut'), + ABILITIES('lacerate'), + ABILITIES('cut'), + ABILITIES('lacerate'), + ABILITIES('cut'), + ABILITIES('lacerate'), + ABILITIES('cut'), + ABILITIES('lacerate'), + ], + }, + secutor: { + name: 'Secutor', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/secutor.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Helmet sealed, shield braced, he advances at the pace of a closing door. Every blow you land rings off the iron and goes nowhere.

He does not rush. He learned long ago that patience outlasts fury.', + ai: { imageContext: 'Simple hand-drawn sketch design', legs: 2 }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + blockChance: 0.15, + dodgeChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('swing'), + ABILITIES('block', false, { overrides: { ticks: 2 } }), + ABILITIES('shieldBash'), + ABILITIES('swing'), + ABILITIES('block', false, { overrides: { ticks: 2 } }), + ], + }, + breff: { + name: 'Breff', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/frost/breff.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It brings its own winter. Frost spreads from where the Breff stands, and the sand stiffens to ice under its weight.

The cold reaches you a moment before it does. Neither part is kind.', + ai: { + imageContext: + 'Heavyset frost beast lumbering on four legs.\n\nIcy blue hide crusted with frost and jutting ice shards along its back.\n\nA wide fanged maw set in a heavy underbite, glowing eyes above it.\n\nRidged horns sweep back from its skull.\n\nUpperbody bigger than lower body', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.25, + criticalDamage: 0.3, + dodgeChance: 0.05, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('frostbite'), ABILITIES('shieldWall'), ABILITIES('frostbite')], + }, + armorillo: { + name: 'Armorillo', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/earth/armorillo.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It rolls itself shut at the first jeer from the stands and waits for the noise to die down. Spears skip off the jade spines, and the crowd loses patience long before the Armorillo loses its nerve.

By the time it uncurls, it is already rolling over you.', + ai: { + imageContext: + 'A Armadillo\n\nA domed shell of overlapping brown plates studded with few, but prominent, spikes.\n\nA large-scaled armoured head and clawed forefeet tucked at the base.\n\nA banded tail wraps around the curl.\n\nEarthen browns set against teal spines.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.25, + criticalDamage: 0.4, + dodgeChance: 0.25, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('stoneskin'), ABILITIES('slam'), ABILITIES('stoneShatter')], + }, + wyvern: { + name: 'Wyvern', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/lightning/wyvern.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It rides the front edge of the storm and drops out of it without warning. The Wyvern fights from above, all talon and tail, and is gone again before the dust settles.

Keep your eyes on the sky. It will not give you a second reason to.', + ai: { + imageContext: + 'Lean slate-blue wyvern stooping mid-dive.\n\nGreat membranous wings doubling as its forelimbs.\n\nA crest of red spines down its back and jaw.\n\nHooked talons and a long lashing tail.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.25, + criticalDamage: 0.3, + dodgeChance: 0.01, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('pounce'), + ABILITIES('stormStrike'), + ABILITIES('ripAndTear'), + ABILITIES('stormStrike'), + ], + }, + mammoth: { + name: 'Mammoth', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/frost/mammoth.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A wall of red wool and old ivory that crossed a frozen age to get here. The Mammoth moves at its own pace and expects the world to step aside.

Those tusks have cleared paths through worse than you. They will clear one more.', + ai: { + imageContext: + 'Great woolly mammoth heavy with shaggy fur.\n\nLong curved ivory tusks sweeping out from a lowered trunk.\n\nBroad domed head, small dark eyes.\n\nMainly brown to it\'s color. The strands of the fur is prominent.\n\nNot regular "puff hair" on top, but instead hair hanging down its face.\n\nHand-drawn and sketchy look', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.05, + criticalDamage: 0.3, + dodgeChance: 0.05, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('stomp'), ABILITIES('gore'), ABILITIES('frostbite'), ABILITIES('gore')], + }, + cerberus: { + name: 'Cerberus', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/fire/cerberus.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'One body, three tempers, and not a calm one among them. The Cerberus was set at the gate to keep things in, and it has never once been told the fight is over.

Get past one head and the other two are already on you.', + ai: { + imageContext: + 'Three snarling hound heads on one muscular body.\n\nReddish-brown fur, hackles raised.\n\nGlowing red eyes and bared fangs on every head.\n\nA spiked collar buckled around each neck.\n\nHand-drawn, sketch\n\nDynamic interesting pose', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0.05, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('bite'), ABILITIES('goodBoys'), ABILITIES('bite'), ABILITIES('bite')], + }, + ulwar: { + name: 'Ulwar', + race: ALL_RACES.creature, + type: 'humanoid', + image: 'creature/lightning/ulwar.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A man somewhere underneath, on the nights it forgets to be one. Ulwar comes into the ring already howling, and the howl is the most reasonable thing about it.

Steel slows it. Nothing yet has stopped it.', + ai: { + imageContext: + 'Gray-ish fur\n\nNo defined muscles.\n\nLooks straight ahead.\n\nDynamic "in-combat" pose.\n\nClaws ready to attack.\n\nNo pupils in eyes\n\nUnarmored, howling\n\nSquat pose', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0.05, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('intimidatingRoar'), ABILITIES('ripAndTear'), ABILITIES('rendingFrenzy')], + }, + lightningHerald: { + name: 'Herald', + race: ALL_RACES.felidae, + type: 'creature', + image: 'creature/lightning/herald.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It comes ahead of the storm, the way thunder follows a flash: proud, unhurried, certain of its welcome. The Herald announces nothing it cannot back with claw and wing.

Kneeling is not required. Surviving the introduction is.', + ai: { + imageContext: + 'A great winged lion at rest on a high crag.\n\nTawny golden hide and a full dark-amber mane.\n\nEnormous feathered wings\n\nA broad lion face with pale, level eyes.\n\nHeavy paws, a regal elegant stance.\n\nMajestic fluffy fur around neck.\n\nHand-drawn sketch look', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0.3, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('stormStrike'), + ABILITIES('ripAndTear'), + ABILITIES('stormStrike'), + ABILITIES('stormStrike'), + ], + }, + runeStag: { + name: 'Rune Stag', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/nature/rune-stag.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Old forest magic given four legs and a crown of light. The Rune Stag walks into the arena as though it wandered in by mistake, and leaves the same way.

The marks on its hide glow brighter the closer the end comes. By then it is usually yours.', + ai: { + imageContext: + 'A stately stag with a dark, heavy coat.\n\nGolden oversized antlers.\n\nLuminous rune spirals marked across its flanks and legs.\n\nCalm pale eyes.\n\nMotes of light drifting from its antlers.\n\nMajestic and mysterious look.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('gore'), ABILITIES('wildGrowth'), ABILITIES('gore'), ABILITIES('gore')], + }, + frigusMortis: { + name: 'Frigus Mortis', + race: ALL_RACES.dragon, + type: 'elemental', + image: 'creature/frost/frigus-mortis.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Cold death on the wing. Where its breath passes, the air itself stops moving and falls as glittering dust.

Frigus Mortis does not need to land a single bite. It only needs to exhale, and wait.', + ai: { + imageContext: + 'Lean blue dragon with wings spread mid-snarl.\n\nDeep-blue scales, paler frost crusting its hide.\n\nJagged ice crystals grow from its back and shoulders.\n\nWhite glowing eyes.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.5, + criticalDamage: 0.33, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: 15, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('frostBreath'), + ABILITIES('frostbite'), + ABILITIES('bite'), + ABILITIES('frostbite'), + ], + }, + vitaDeserto: { + name: 'Vita Deserto', + race: ALL_RACES.dragon, + type: 'elemental', + image: 'creature/earth/vita-deserto.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A plated wyrm that drags the weight of a quarry wherever it goes. The wings are mostly bluff. The armour is not, and the red stone set in its throat burns where a fire should be.

It never gives chase. It simply arrives, and leaves no room to slip past.', + ai: { + imageContext: + 'Stocky, low-slung armoured dragon.\n\nGrey scales layered beneath leaf-shaped stone plates along its back and shoulders.\n\nBroad veined wings spread wide.\n\nA blunt reptile head with a stubby horn and a heavy underbite.\n\nStone dragon, heavy body, dynamic pose', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.2, + criticalDamage: 0.75, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: 15, + abilities: [ + ABILITIES('earthBreath'), + ABILITIES('stoneShatter'), + ABILITIES('bite'), + ABILITIES('stoneShatter'), + ], + }, + ragnarGodOfFire: { + name: 'Ragnar God of Fire', + race: ALL_RACES.god, + type: 'elemental', + image: 'creature/fire/ragnar-god-of-fire.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'They built a fire too big and gave it a name, and the name learned to walk. Ragnar wades through the lava that birthed him as though it were warm bathwater.

The beard alone has ended more challengers than the fists. Few last long enough to reach the fists.', + ai: { + imageContext: + 'Hulking brute-god.\n\nDark grey-green hide over a broad, hunched, muscular frame.\n\nBeard is lava.\n\nGod of fire.\n\nOne big scar across the chest. Scars lightning up a bit, like there is lava inside.\n\nHuman porportions.\n\nNo weapon. Human hands.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.33, + criticalDamage: 0.33, + dodgeChance: 0.4, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('emberStrike'), + ABILITIES('crushingBlow'), + ABILITIES('emberStrike'), + ], + }, + kylGodOfFrost: { + name: 'Kyl God of Frost', + race: ALL_RACES.god, + type: 'elemental', + image: 'creature/frost/kyl-god-of-frost.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The cruelty of the high mountains given a face and a grin. Kyl rises out of the killing cold above the peaks and finds the arena pleasantly warm by comparison.

Everything he touches slows, stiffens, and stops. He is in no hurry to touch you.', + ai: { + imageContext: + 'Towering frost god risen from the cold mountains.\n\nLean, pale ice-blue body marked with darker swirling glacial patterns.\n\nBold excapt some hair is in a bun of frozen ice-cicles. Beard is also frozen ice-cicles.\n\nPointy ears, glowing eyes, a fanged grin.\n\nGod of frost.\n\nLean, not muscular.\n\nVery basic clothing.\n\nDynamic pose like casting a spell.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.25, + criticalDamage: 0.3, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('frostbite'), + ABILITIES('crushingBlow'), + ABILITIES('frostbite'), + ], + }, + natureGiant: { + name: 'Giant', + race: ALL_RACES.giant, + type: 'elemental', + image: 'creature/nature/giant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A walking acre of forest that took offence at something and never sat back down. The Nature Giant swings fists the size of fallen trunks and roots itself between blows.

Cut it and it scars over in bark. Burn it and you only make it angry.', + ai: { + imageContext: + 'A tree which chest and lowerbody is a tree trunk (no-humanlike features).\n\nMouthless, noteless, no pupils\n\nMossy skin is bark.', + legs: 1, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 1, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('slam'), ABILITIES('wildGrowth'), ABILITIES('crushingBlow')], + }, + owlBear: { + name: 'Owl Bear', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/nature/owlbear.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The worst halves of two hunters stitched into one. The Owlbear has the patience of the owl and the temper of the bear, and brings neither to a negotiation.

You hear nothing until the talons are already in you.', + ai: { + imageContext: + 'Owl head set on a heavy bear body.\n\nPlumage of dusty pink, grey and violet.\n\nTufted ears and a hooked yellow beak.\n\nFierce pale eyes over a feathered ruff.\n\nClawed bear paws beneath the feathers.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.05, + criticalDamage: 0.3, + dodgeChance: 0.02, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('pounce'), ABILITIES('ripAndTear'), ABILITIES('wildGrowth')], + }, + yeti: { + name: 'Yeti', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/frost/yeti.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It comes down from the white peaks only when the hunger does. The Yeti wears the cold like a second hide and roars loud enough to start the snow moving above you.

The horns are for show. The hands are not.', + ai: { + imageContext: + 'Towering yeti hunched forward, arms spread wide, roaring with its mouth open\n\nThick shaggy white fur, blue-grey face and hands, large curved ram horns, a fanged maw, dark heavy claws', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('slam'), + ABILITIES('frostbite'), + ABILITIES('slam'), + ], + }, + lightningGiant: { + name: 'Giant', + race: ALL_RACES.giant, + type: 'elemental', + image: 'creature/lightning/giant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Not a creature so much as a storm that learned to stand. The Lightning Giant walks on a column of howling wind, and the ground it crosses is scorched black behind it.

Strike at it and you strike a cloud. It strikes back with the sky.', + ai: { + imageContext: 'Magical entity made out of clouds. Bursts of lightning covering its surface', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 1, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('lightningStorm')], + }, + onkh: { + name: 'Onkh', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/lightning/onkh.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Something the mountains grew and never explained. Onkh hunches through the dark on stone knuckles, and the cave does not echo when it moves.

Its hide turns blades. Its eyes find you long before the torchlight does.', + ai: { + imageContext: + 'Hunchback stone creature of gray stone-plated hide.\n\nBroad shoulders, short arms.\n\nPale eyes glowing in the gloom.\n\nBig bulky body, no clear muscles showing\n\nGorilla pose. Body entirely made out of stone', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0.05, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('crushingBlow'), + ABILITIES('stormStrike', false, { + overrides: { ticks: 4 }, + }), + ABILITIES('crushingBlow'), + ], + }, + bullrock: { + name: 'Bullrock', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/fire/bullrock.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A bull that kept growing past the point of sense, then grew a mountain on its head for good measure. The Bullrock lowers that crown and the argument is over.

There is no turning it. There is only being somewhere it is not.', + ai: { + imageContext: + "Massive shaggy bull, low and heavy with muscle.\n\nA crown of grey stone plates crests its head, back and shoulders, it fulls the back like a layer of armor. Each plate overlays the next plate.\n\nBig bullhorns.\n\nPale eyes fixed and unblinking, no pupils\n\nHand-drawn, sketchy look.\n\nIt's in the middle of launching an attack (threathening)", + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.05, + criticalDamage: 0.3, + dodgeChance: 0.01, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 16, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('charge'), + ABILITIES('emberStrike'), + ABILITIES('gore'), + ABILITIES('gore'), + ], + }, + warrus: { + name: 'Warrus', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/frost/warrus.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It hauls its weight up onto the ice and dares the arena to move it. The Warrus is all blubber and bone, and the tusks have ended more challengers than any blade in the pit.

Slow to rise. Worse to be under when it comes down.', + ai: { + imageContext: + 'Enormous tusked walrus, grey-purple and blubbery.\n\nLong pale tusks below a thick whiskered snout.\n\nNo glare. Neck held high, mysterious look, no pupils.\n\nSkin covered with fur\n\nFantasy looking head with spikes going across the forehead down the spines\n\nOversized tusks. Sitting down so back legs are not visible\n\nNo glare or gloss', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.3, + dodgeChance: 0.3, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('crushingBlow'), + ABILITIES('gore'), + ABILITIES('frostbite'), + ABILITIES('gore'), + ], + }, + eliseGoddessOfEarth: { + name: 'Elise Goddess of Earth', + race: ALL_RACES.god, + type: 'elemental', + image: 'creature/earth/elise-goddess-of-earth.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The bedrock grew opinions, and none of them were kind. Elise rises out of the arena floor as though it had always been her, and the stone answers the moment she calls it.

Every blow you land is swallowed by shifting rock. Every blow she lands moves the earth itself.', + ai: { + imageContext: + 'Stone-skinned earth goddess risen from the ground.\n\nA crown of jagged crystal shards.\n\nSkin beighe like a regular human. Breasts and lower body covered with a skirt made out of stone.\n\nGodly and majestic pose, like casting a spell.\n\nLean sexy body, no abs showing.', + legs: 1, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.5, + dodgeChance: 0, + blockChance: 0.4, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('warcry'), ABILITIES('stoneShatter'), ABILITIES('crushingBlow')], + }, + aloraGoddessOfNature: { + name: 'Alora Goddess of Nature', + race: ALL_RACES.god, + type: 'elemental', + image: 'creature/nature/alora-goddess-of-nature.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'She tends the wilds the way a butcher tends a herd. Alora steps onto the sand humming a soft tune, and the green things that trail after her have teeth.

Cut her down and the roots drink deep, and she stands again the taller for it.', + ai: { + imageContext: + 'Serene nature goddess wreathed in living green.\n\nBark-and-vine body draped in leaves and flowers.\n\nAntler-like branches crowning her head.\n\nGlowing green eyes and a faint knowing smile.\n\nArmor made out of magical leafs covers breasts, under arms and legs in form of a skirt. Skirt covers legs.\n\nNoble helmet that covers forehead, ears and eyes.\n\nSexy lean body.\n\nMajestic pose, like casting a spell (without effects)', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.4, + dodgeChance: 0.4, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('wildGrowth'), + ABILITIES('gore'), + ABILITIES('wildGrowth'), + ], + }, + oskarGodOfLightning: { + name: 'Oskar God of Lightning', + race: ALL_RACES.god, + type: 'elemental', + image: 'creature/lightning/oskar-god-of-lightning.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The storm grew tired of waiting in the clouds and came down wearing a face. Oskar crosses the arena between heartbeats, and the thunder only catches up a moment after he does.

Blink, and you have already lost the exchange.', + ai: { + imageContext: + 'Crackling lightning god striking the top of bald head, making eyes spark in lightning-yellow beams (no pupils).\n\nLong bears with a old school mustache.\n\nLooks like a mad man.\n\nGlowing white eyes, a fierce grin.\n\nEnjoying being struck by the lightning.\n\nGod of lightning. Big strokes of lightning arcing around body', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.45, + criticalDamage: 0.6, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('stormStrike'), + ABILITIES('crushingBlow'), + ABILITIES('stormStrike'), + ], + }, + fireGiant: { + name: 'Giant', + race: ALL_RACES.giant, + type: 'elemental', + image: 'creature/fire/giant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A mountain that caught fire an age ago and never thought to stop. The Fire Giant lumbers into the pit trailing molten rock, and the sand turns to glass where it walks.

Stand too close and you cook. Stand too far and it closes the distance anyway.', + ai: { + imageContext: + 'Colossal entity of cracked blackened stone. Body shaped like a mountain.\n\nRivers of molten lava glowing through the fissures.\n\nA craggy head with a silhouette of a face, hiding the details of the eyes, nose and mouth.\n\nYellow/orange features.', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 1, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + fire: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('stomp'), + ABILITIES('emberStrike'), + ABILITIES('slam'), + ABILITIES('emberStrike'), + ], + }, + frostGiant: { + name: 'Giant', + race: ALL_RACES.giant, + type: 'creature', + image: 'creature/frost/giant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Carved from a glacier that learned to hold a grudge. The Frost Giant brings the dead silence of the high winter, and the breath freezes in your chest before the first blow lands.

It does not hurry. The cold does its work either way.', + ai: { + imageContext: + 'Towering humanoid carved from blue glacial ice.\n\nPale translucent body shot through with deeper blues.\n\nJagged ice shards crowning its head and forearms.\n\nFrost spreading across the ground at its feet.\n\nSketch.\n\nArms are icecicles.\n\nOne "Leg"', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 1, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + frost: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('frostbite'), + ABILITIES('crushingBlow'), + ABILITIES('frostbite'), + ABILITIES('slam'), + ], + }, + earthGiant: { + name: 'Giant', + race: ALL_RACES.giant, + type: 'creature', + image: 'creature/earth/giant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A landslide that decided to stand upright. The Earth Giant wears the quarry on its back and swings boulders as though they weighed nothing at all.

There is no dodging a hill. There is only outlasting it, and few do.', + ai: { + imageContext: + 'Massive humanoid built of boulders and packed earth.\n\nSlabs of grey stone for shoulders and fists.\n\nRoots, gravel and dirt packed between the rocks.\n\nNo face, but a crack where the next normally is, revealing a hole.\n\nResembles a mountain.\n\nNo legs, no muscles\n\nProvide perspective (the giant is HUGE).\n\nBody "traditional giant" like (not human)', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 1, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + earth: 20, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('slam'), ABILITIES('stoneShatter'), ABILITIES('slam')], + }, + eratHerba: { + name: 'Erat Herba', + race: ALL_RACES.dragon, + type: 'elemental', + image: 'creature/nature/erat-herba.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It bursts from the arena floor with a roar, ancient and furious at being woken. The Nature Dragon wears the forest like scales, and the forest fights at its side.

Wound it and it knits closed in living bark.', + ai: { + imageContext: + 'Ancient dragon sheathed in bark and living vine.\n\nLeave-like scale covers its body.\n\nAntlered horns and glowing green eyes.\n\nNature dragon\n\nMajestic wings', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.3, + criticalDamage: 0.5, + dodgeChance: 0.2, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: 15, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('natureBreath'), + ABILITIES('bite'), + ABILITIES('wildGrowth'), + ABILITIES('gore'), + ABILITIES('bite'), + ], + }, + ventoMico: { + name: 'Vento Mico', + race: ALL_RACES.dragon, + type: 'elemental', + image: 'creature/lightning/vento-mico.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It finds grounded things revolting, and it finds you very grounded indeed. The Lightning Dragon strikes from the air faster than the eye can track, trailing thunder it has already outrun.

Try not to steal its thunder. It notices.', + ai: { + imageContext: + 'Lithe winged dragon crackling\n\nLong whip-like tail and swept-back horns.\n\nGlowing white eyes fixed on its prey.\n\nLightning dragon.\n\nWings showing.\n\nThin and slick. Almost looks like lightning itself.\n\nYellow lightning features on its skin, almost like veins', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.5, + criticalDamage: 0.6, + dodgeChance: 0, + blockChance: 0, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + lightning: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: 15, + abilities: [ + ABILITIES('lightningBreath'), + ABILITIES('stormStrike'), + ABILITIES('bite'), + ABILITIES('stormStrike'), + ABILITIES('bite'), + ], + }, + giantScorpion: { + name: 'Giant Scorpion', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/giant-scorpion.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Pulled from a cave under the southern dunes. It does not understand the arena. It does not need to.

The tail is fast. The pincers are faster.', + ai: { + imageContext: + 'Giant desert cave scorpion, the size of a cart.\n\nCracked sandstone carapace, dune-brown chitin with darker banding.\n\nTwo oversized serrated pincers held forward.\n\nSegmented tail arced high overhead, tipped with a glistening venom barb.\n\nLow, flat, predatory stance.', + legs: 8, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('stab'), + ABILITIES('poisonousSting'), + ABILITIES('stab'), + ABILITIES('poisonousSting'), + ], + }, + hyena: { + name: 'Hyena', + race: ALL_RACES.felidae, + type: 'creature', + image: 'creature/hyena.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 0.9, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A scavenger from the southern scrub, dragged here for the crowd. It does not charge — it circles, and it laughs.

The jaws are built for bone. It will wait as long as it takes to use them.', + ai: { + imageContext: + 'Large spotted hyena, sloping back — high shoulders, low hindquarters.\n\nCoarse bristled mane along the neck and spine.\n\nHeavy blunt muzzle, powerful scarred jaws.\n\nMangy dust-colored spotted coat.\n\nHead low, manic grin, wild pale eyes.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.7, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('bite'), + ABILITIES('crushingBlow'), + ABILITIES('bite'), + ABILITIES('crushingBlow'), + ], + }, + executioner: { + name: 'Executioner', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/executioner.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "The arena's own headsman, pushed into the ring when the crowd grows restless for a familiar face.

He has ended more lives off the sand than on it. The axe does not know the difference.", + ai: { + imageContext: + "Hulking, broad-shouldered headsman.\n\nBlack leather executioner's hood with narrow eye-slits.\n\nBare muscled torso over a blood-stained leather apron.\n\nMassive two-handed axe with a broad crescent blade.\n\nStoic, motionless, looming.", + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: { + ...DEFAULT_TOLERANCE, + stunned: 8, + }, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('execute', false, { + overrides: { ticks: 12, combatStats: { criticalDamage: 4.5 } }, + }), + ], + }, + olderBrother: { + name: 'Older Brother', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/older-brother.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The elder of two raider brothers off the salt road. Slower than he was, but he still hits like a falling gate.', + ai: { + imageContext: + 'Broad, weathered desert raider, the older of two brothers.\n\nThick beard, sun-scarred face.\n\nLayered dusty robes over scavenged leather armor.\n\nA heavy curved sword held low.\n\nSteady, planted stance.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.7, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('swing'), ABILITIES('slam'), ABILITIES('swing'), ABILITIES('slam')], + }, + youngerBrother: { + name: 'Younger Brother', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/younger-brother.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'The younger raider brother — quick, cocky, and always a step ahead of his own caution.', + ai: { + imageContext: + 'Lean, wiry desert raider, the younger of two brothers.\n\nLight stubble, eager grin.\n\nLight dusty robes, minimal leather.\n\nA quick short blade in hand.\n\nLight on his feet, weight forward.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + dodgeChance: 0.15, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('stab'), + ABILITIES('cut'), + ABILITIES('swing'), + ABILITIES('stab'), + ABILITIES('cut'), + ABILITIES('swing'), + ], + }, + rhino: { + name: 'Rhino', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/rhino.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It charges in a straight line and remembers nothing. Be somewhere else when it arrives.

The horn is the part to worry about. The mass behind it is what does the damage.', + ai: { + imageContext: + 'Massive armored rhinoceros, enormous bulk.\n\nThick grey plated hide with deep armor-like folds.\n\nA large forward horn and a smaller second horn.\n\nSmall angry eyes, head lowered.\n\nMid-charge, head down.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + blockChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('charge'), ABILITIES('slam'), ABILITIES('gore'), ABILITIES('slam')], + }, + theEngineer: { + name: 'The Engineer', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/the-engineer.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'He built the cannon, and he will die before he leaves it. Mostly bluster and bulk — but every blow you waste on him is a blow the cannon gets to answer.', + ai: { + imageContext: + 'Stout, grease-stained siege engineer.\n\nHeavy leather apron over a soot-smudged shirt, brass goggles pushed up on his forehead.\n\nGripping an oversized iron wrench like a club.\n\nTool-belt heavy with spanners.\n\nPlanted, defiant, blocking the way.\n\nThe engineer is a small goblin creature', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + provocation: 13, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('block'), ABILITIES('slam'), ABILITIES('block'), ABILITIES('slam')], + }, + cannon: { + name: 'Cannon', + race: ALL_RACES.creature, + type: 'prop', + image: 'creature/cannon.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + power: 0.5, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Iron-throated and patient. While the engineer keeps you busy, it takes its time — and it does not miss twice.', + ai: { + imageContext: + 'A heavy bronze bombard cannon mounted on a two-wheeled wooden carriage. No creature — an inanimate siege weapon.\n\nThick banded barrel, scorched smoking muzzle.\n\nA stack of black iron cannonballs piled beside the wheels.\n\nWeathered wood, soot stains.', + legs: 0, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.7, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('boom'), ABILITIES('boom'), ABILITIES('boom'), ABILITIES('boom')], + }, + goblinHorn: { + name: 'Horn Goblin', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/horn-goblin.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "The pack's voice. When the horn sounds, every goblin in earshot fights twice as hard.", + ai: { + imageContext: + "Small green-grey goblin raising a great curled ram's-horn to its lips, cheeks puffed mid-blow.\n\nOversized ears, jagged teeth.\n\nMismatched leather scraps, a satchel at its hip.\n\nThe war-horn is the focal point.", + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE + 4, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('stab'), + ABILITIES('cut'), + ABILITIES('stab'), + ABILITIES('stab'), + ABILITIES('cut'), + ABILITIES('stab'), + ], + }, + goblinStabber: { + name: 'Stabber Goblin', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/stabber-goblin.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Goes for the soft parts and the tendons. Leaves you bleeding for the others to finish.', + ai: { + imageContext: + 'Small green-grey goblin crouched low, a crude rusty knife in each hand.\n\nOversized ears, jagged teeth, darting eyes.\n\nBlood-flecked leather scraps.\n\nReady to lunge.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: DEFAULT_LUCKY_STATS.criticalDamage + 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('lacerate'), + ABILITIES('stab'), + ABILITIES('lacerate'), + ABILITIES('stab'), + ABILITIES('lacerate'), + ABILITIES('stab'), + ], + }, + goblinBasher: { + name: 'Basher Goblin', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/basher-goblin.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Swings a club bigger than it is. What it lacks in aim it makes up for in enthusiasm.', + ai: { + imageContext: + 'Small but stocky green-grey goblin hefting an oversized crude bone club in both hands.\n\nOversized ears, jagged grin.\n\nMismatched leather scraps, braced wide.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + armorPenetration: 2, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('slam'), + ABILITIES('crushingBlow'), + ABILITIES('sunder'), + ABILITIES('sunder'), + ], + }, + goblinSlinger: { + name: 'Slinger Goblin', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/slinger-goblin.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: 'Hangs back and pelts you with stones. Hits more often than it has any right to.', + ai: { + imageContext: + 'Small green-grey goblin, one eye squinted in aim.\n\nA bulging pouch of stones at its hip.\n\nOversized ears, mismatched leather scraps.\n\nGoblin wields a handheld slingshot and takes aim.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: DEFAULT_LUCKY_STATS.criticalDamage + 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('slingshot'), + ABILITIES('slingshot'), + ABILITIES('daggerThrow'), + ABILITIES('slingshot'), + ABILITIES('slingshot'), + ABILITIES('daggerThrow'), + ABILITIES('slingshot'), + ], + }, + goblinNetter: { + name: 'Netter Goblin', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'creature/netter-goblin.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: 'Tangles you in a net so the rest can swarm. The net is the dangerous part.', + ai: { + imageContext: + 'Small green-grey goblin swinging a weighted net overhead, a crude spike in its other hand.\n\nOversized ears, sharp grin, wide stance.\n\nMismatched leather scraps.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + hitChance: DEFAULT_LUCKY_STATS.hitChance + 0.4, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('weave'), + ABILITIES('stab'), + ABILITIES('weave'), + ABILITIES('stab'), + ABILITIES('stab'), + ], + }, + plagueDoctor: { + name: 'Plague Doctor', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/plague-doctor.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "A masked physician who treats the arena's wounded — and quietly sees to the ones he's paid to.

He does not rush. He simply administers, and waits for the dose to take.", + ai: { + imageContext: + 'Tall gaunt figure in a long waxed-leather plague-doctor coat.\n\nIconic bird-beak mask with round glass eye-lenses, wide-brimmed hat.\n\nEerie, methodical, looming.\n\nLess steampunk. Make the beak clearly a mask.\n\nNo coat.\n\nSimple clothing.\n\nDynamic pose. Hold a skull "to be or not to be"-style.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + magicChance: 0.1, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('poisonousSting'), + ABILITIES('lacerate'), + ABILITIES('poisonousSting'), + ABILITIES('smokebomb'), + ], + }, + wolf: { + name: 'Wolf', + race: ALL_RACES.felidae, + type: 'creature', + image: 'creature/wolf.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: 'A lean pack-hunter. Alone it hesitates; with its pack, it does not.', + ai: { + imageContext: + 'Lean grey timber wolf, ribs showing, thick scruff at the neck.\n\nYellow eyes, ears pinned back, lips peeled off the teeth.\n\nScarred muzzle, hackles raised.\n\nLow prowling stance.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.15, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('pounce'), ABILITIES('bite'), ABILITIES('ripAndTear'), ABILITIES('bite')], + }, + regularSizedCombatant: { + name: 'Regular Sized Combatant', + race: ALL_RACES.dwarf, + type: 'humanoid', + image: 'creature/regular-sized-combatant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Just a regular-sized combatant. One fighter, normal height, nothing to remark upon.', + ai: { + imageContext: + "Two dwarves stacked on top of each other, one sitting on the other's shoulders.\n\nBottom dwarf's boots planted, arms holding the legs of the dwarf on top; top dwarf's bearded face and arms emerging at the collar, gripping an axe.", + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.7, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('cut'), + ABILITIES('swing'), + ABILITIES('crushingBlow'), + ABILITIES('swing'), + ABILITIES('cut'), + ], + }, + grizzlyBear: { + name: 'Grizzly Bear', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/grizzly-bear.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.2, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'Trapped young, kept lean, fed only on the day of the fight.

Every fiber of it wants to be somewhere else. The only way out is through you.', + ai: { + imageContext: + 'Large grizzly bear. No pupils.\n\nWild desperate eyes, jaws open mid-roar.\n\nFierce and in a "about to attack" pose', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('intimidatingRoar'), + ABILITIES('crushingBlow'), + ABILITIES('bite'), + ABILITIES('ripAndTear'), + ABILITIES('bite'), + ], + }, + beastmaster: { + name: 'Beastmaster', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/beastmaster.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'A weathered beast-tamer who lets her hyena do the killing. The whip is for keeping it hungry — and for you.', + ai: { + imageContext: + 'Lean, weathered woman, a beast-tamer.\n\nPractical leather-and-hide armor with fur trim and bone-and-tooth trophies.\n\nA long coiled whip in one hand, a bone whistle on a cord at her neck.\n\nHair tied back, sharp commanding eyes, old scars.\n\nConfident, planted stance.\n\nWell armored sexy lean body', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.15, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('lacerate'), + ABILITIES('demoralizingShout'), + ABILITIES('lacerate'), + ABILITIES('lacerate'), + ABILITIES('stab'), + ], + }, + blindSwordsman: { + name: 'Blind Swordsman', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/blind-swordsman.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "He lost his eyes years ago. He did not lose the rest.

He fights by sound and by the shift of the air, and he has outlasted men with two good eyes. The bandage isn't for show.", + ai: { + imageContext: + 'Lean, scarred swordsman with a strip of white cloth bound over his eyes.\n\nPractical worn fighting clothes, sleeves rolled.\n\nA single slender sword drawn, held low and ready.\n\nHead slightly tilted as if listening; calm, disciplined, perfectly balanced.\n\nWields a twohanded schimitar', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('riposte'), + ABILITIES('swing'), + ABILITIES('cut'), + ABILITIES('swing'), + ABILITIES('cut'), + ], + }, + warElephant: { + name: 'War Elephant', + race: ALL_RACES.creature, + type: 'creature', + image: 'creature/war-elephant.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.4, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'It will not chase you. It does not need to.

Wherever it stands, that is the dangerous part of the arena.', + ai: { + imageContext: + 'Enormous war elephant, towering over the sand.\n\nThick grey wrinkled hide, huge curved tusks capped with banded iron.\n\nBroad flapping ears, trunk raised.\n\nTattered war-barding draped over its back, massive pillar legs, planted and immovable.', + legs: 4, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: { + ...DEFAULT_TOLERANCE, + stunned: 12, + }, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ABILITIES('stomp'), ABILITIES('gore'), ABILITIES('slam'), ABILITIES('gore')], + }, + grandChampion: { + name: 'The Grand Champion', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/the-grand-champion.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + "Undefeated in forty matches. Wears the laurel and the chip on his shoulder both like jewelry.

He has fought every style the arena offers and beaten most of them. He's been waiting for you.", + ai: { + imageContext: + 'Proud, powerfully built champion gladiator in his prime.\n\nOrnate decorated breastplate and a single grand pauldron, a laurel crown on his brow.\n\nBattle-scarred but composed, an arrogant half-smile.\n\nA fine gladius held with easy confidence, statuesque stance.', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalDamage: 0.8, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('riposte'), + ABILITIES('swing'), + ABILITIES('crushingBlow'), + ABILITIES('sunder'), + ], + }, + emperor: { + name: 'The Emperor', + race: ALL_RACES.human, + type: 'humanoid', + image: 'creature/the-emperor.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: { + ...DEFAULT_NPC_EQUIPMENT, + }, + description: + 'He does not need to be here. He chose to be here.

When the Emperor enters the sand, the guards lower their pikes and the crowd holds its breath.

Win, and the city will know your name. Lose, and the city will not remember it.', + ai: { + imageContext: + 'Regal, imposing emperor seated on a massive ornate throne, not deigning to rise.\n\nGilded imperial armor and a deep purple cloak draped over the throne.\n\nA golden laurel crown, cold supremely confident expression.\n\nOne hand resting on a masterwork sword laid across his lap.\n\nThe throne is grand and carved from gold and marble — the single most important figure in the arena.\n\nKeep fidelity down, simple design', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + currentHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...{ + ...DEFAULT_LUCKY_STATS, + criticalChance: 0.2, + }, + tolerance: DEFAULT_TOLERANCE, + resistances: DEFAULT_RESISTANCES, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: Infinity, + abilities: [ + ABILITIES('warcry'), + ABILITIES('swing'), + ABILITIES('crushingBlow'), + ABILITIES('riposte'), + ], + }, + motherAlora: { + name: 'Alora', + race: ALL_RACES.creature, + type: 'humanoid', + image: 'npc/mother-alora.webp', + mugshot: { + x: 55, + y: 9, + }, + size: 1, + equipment: DEFAULT_EQUIPMENT, + description: + 'Mother of all living things and the grace behind every healer’s hands. She lends herself to the ludus for a time, mending the wounds the arena leaves behind.', + ai: { + imageContext: + 'She is adult, sweet and kind. She takes care of battle bruised gladiators.\n\nShe is a young human medic', + legs: 2, + }, + combatStats: { + maxHealth: 60, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { + ...DEFAULT_RESISTANCES, + nature: 8, + }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('alorasTouch', false, { overrides: { ticks: 12 } })], + }, + oswald: { + name: 'Oswald the Outfitter', + race: ALL_RACES.human, + type: 'humanoid', + image: 'npc/oswald.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: DEFAULT_EQUIPMENT, + description: + 'A weathered quartermaster who has outfitted a hundred doomed expeditions. His prices are fair, his steel is honest, and he never asks where the coin came from.', + ai: { + imageContext: + 'Weathered quartermaster standing, holding a wooden crate of supplies with a laden pack on his back\n\nGreying hair and beard, brown leather apron over work clothes, satchels and coiled rope, sturdy boots', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, frost: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ], + }, + mira: { + name: 'Mira the Trinketeer', + race: ALL_RACES.human, + type: 'humanoid', + image: 'npc/mira.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: DEFAULT_EQUIPMENT, + description: + 'A travelling curio-dealer whose cart rattles with oddities and half-cursed baubles. She deals only in higher-grade finds.', + ai: { + imageContext: + 'Elven curio-dealer standing, examining a small trinket in her hands\n\nLong blonde hair, pointed ears, green hooded robe and skirt, a large leather satchel hung with dangling charms and baubles', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, frost: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ABILITIES('frostbite'), + ], + }, + brog: { + name: 'Brog Ironhand', + race: ALL_RACES.dwarf, + type: 'humanoid', + image: 'npc/brog.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: DEFAULT_EQUIPMENT, + description: + 'A barrel-chested dwarf who claims his hammer has never struck the same blow twice. He forges only the heaviest gear.', + ai: { + imageContext: + 'Burly dwarf smith standing, a forging hammer in one hand and tongs in the other\n\nRed mohawk and long braided beard, bare muscular arms, a brown leather apron over a broad bare chest', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, fire: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ABILITIES('emberStrike'), + ], + }, + grukk: { + name: 'Grukk Emberfist', + race: ALL_RACES.troll, + type: 'humanoid', + image: 'npc/grukk.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1.2, + equipment: DEFAULT_EQUIPMENT, + description: + 'A troll smith who works molten ore with bare hands and a worrying grin. Only the strongest dare browse his wares.', + ai: { + imageContext: + 'Hulking troll smith standing, molten embers glowing around his bare fists\n\nGrey-green skin, lower tusks, dark topknot hair, pointed ears, a heavy leather apron', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, earth: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ABILITIES('stoneShatter'), ABILITIES('stoneShatter')], + }, + nibsy: { + name: 'Nibsy Sparkwrench', + race: ALL_RACES.goblin, + type: 'humanoid', + image: 'npc/nibsy.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 0.9, + equipment: DEFAULT_EQUIPMENT, + description: + 'A goblin tinkerer convinced that every weapon can be improved with one more spring. His contraptions are strictly top-tier.', + ai: { + imageContext: + 'Small goblin tinkerer standing, holding a sparking mechanical contraption in both hands\n\nGreen skin, large pointed ears, goggles pushed up on the forehead, leather work clothes, a tool belt hung with wrenches and gadgets', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, lightning: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('stormStrike'), + ABILITIES('stormStrike'), + ABILITIES('stormStrike'), + ABILITIES('stormStrike'), + ], + }, + doctoreVarro: { + name: 'Doctore Varro', + race: ALL_RACES.human, + type: 'humanoid', + image: 'npc/doctore-varro.webp', + mugshot: DEFAULT_MUGSHOT_COORDINATES, + size: 1, + equipment: DEFAULT_EQUIPMENT, + description: + 'A scarred ex-champion who outlasted a hundred bouts on the sand and now drills the next generation at the Palaestra. He breaks brawlers down and builds them back harder.', + ai: { + imageContext: + 'Grizzled veteran gladiator trainer standing, gripping a wooden training sword (rudis) point-down, one foot forward as if mid-drill\n\nShaved head, greying stubble, old battle scars across a muscular bare torso, leather pteruges skirt and forearm wraps, a worn red trainer’s sash at the waist', + legs: 2, + }, + combatStats: { + maxHealth: DEFAULT_MAX_HP, + maxArmor: 0, + currentArmor: 0, + damage: DEFAULT_DAMAGE, + ...DEFAULT_LUCKY_STATS, + tolerance: DEFAULT_TOLERANCE, + resistances: { ...DEFAULT_RESISTANCES, earth: 8 }, + modifiers: DEFAULT_MODIFIERS, + }, + maxTicks: DEFAULT_MAX_TICKS, + abilities: [ + ABILITIES('warcry'), + ABILITIES('swing'), + ABILITIES('crushingBlow'), + ABILITIES('riposte'), + ], + }, +}; + +// Merging meta.overrides must not touch the caller's ref — refs are often live +// state ($.characters), and deepMerge mutates its target. Clone first. +export default (id, fullBody = false, meta) => { + const character = entity( + ALL_CHARACTERS, + typeof id === 'string' ? id : id.id, + typeof id === 'string' ? undefined : id.uuid, + fullBody, + typeof id === 'string' + ? meta?.overrides + : meta?.overrides + ? deepMerge(JSON.parse(JSON.stringify(id.overrides || {})), meta.overrides || {}) + : id.overrides, + ); + // A frozen `level` rides along for cross-account combat (teamplay): the brawler's + // owner level must drive its stats on every viewer's client — not the viewer's own + // level, which is the calculateCombatStatsByCharacter fallback. entity() drops it. + if (typeof id === 'object' && id?.level != null) character.level = id.level; + return character; +}; diff --git a/src/constants/COMBAT_STATS.ts b/js/constants/COMBAT_STATS.js similarity index 100% rename from src/constants/COMBAT_STATS.ts rename to js/constants/COMBAT_STATS.js diff --git a/js/constants/DEFAULT_GAME_STATE.js b/js/constants/DEFAULT_GAME_STATE.js new file mode 100644 index 00000000..aa632a2f --- /dev/null +++ b/js/constants/DEFAULT_GAME_STATE.js @@ -0,0 +1,24 @@ +// The persisted game state — the ONLY keys written to the DB, in the order they are +// sent. Saved per season; statistics + achievements are also mirrored onto the +// account doc. Single source of truth: app.js spreads this into the live state, +// connectSocket's buildSavePayload derives its keys from it, and scripts/seed-bots.js +// builds bot documents from it so a structure change flows everywhere automatically. +export const DEFAULT_GAME_STATE = { + inventory: [], + materials: {}, // material id → owned count; granted from PVE loot, shown in the top bar. + characters: [], + statistics: {}, // recursive { count?, max?, nodes? } event log built by incStat; saved per season + mirrored to the account for the statistics page. + achievements: {}, // { : { earnedAt } } earned THIS season; saved per season + mirrored to the account (achievements.