diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..e37b69d
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+PORT=5173
diff --git a/.forgejo/workflows/deploy-prod.yml b/.forgejo/workflows/deploy-prod.yml
new file mode 100644
index 0000000..c7eb5be
--- /dev/null
+++ b/.forgejo/workflows/deploy-prod.yml
@@ -0,0 +1,28 @@
+name: Deploy Sokko G
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ deploy:
+ runs-on: docker
+
+ steps:
+ - name: Deploy on WebApps
+ env:
+ DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
+ run: |
+ apt-get update
+ apt-get install -y openssh-client
+
+ mkdir -p ~/.ssh
+ printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519
+ chmod 600 ~/.ssh/id_ed25519
+
+ ssh -o StrictHostKeyChecking=no \
+ -i ~/.ssh/id_ed25519 \
+ -p 2911 \
+ shinuwa@192.168.0.100 \
+ "sudo /usr/local/bin/deploy-sokko-g"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5a00c13
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+.env
+.DS_Store
diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md
new file mode 100644
index 0000000..4286d06
--- /dev/null
+++ b/DESIGN_SYSTEM.md
@@ -0,0 +1,921 @@
+# Design System - Sokko G
+
+Ce document est la source de verite visuelle du projet Sokko G. Toute nouvelle interface doit respecter le theme **Nebula Command**.
+
+## 1. Vision
+
+Sokko G est une webapp gaming pensee pour des groupes d'amis pendant leurs sessions de jeu. Elle doit permettre de consulter rapidement des informations, gerer des toolboxes, notes, checklists, captures d'ecran, liens, ressources et pages informatives.
+
+L'interface doit etre sombre, moderne, immersive, lisible sur desktop et mobile, agreable pendant de longues sessions, inspiree par l'espace, les nebuleuses et les interfaces gaming premium.
+
+Eviter le style RGB agressif. L'ambiance recherchee est celle d'une galaxie calme, profonde et lumineuse.
+
+## 2. Direction Artistique
+
+Nom du theme : **Nebula Command**
+
+Mots-cles :
+
+- galaxie ;
+- nebuleuse ;
+- espace profond ;
+- violet electrique ;
+- bleu cosmique ;
+- verre teinte ;
+- lumiere diffuse ;
+- interface futuriste ;
+- collaboration ;
+- gaming premium.
+
+Principes :
+
+- l'arriere-plan principal est tres sombre, legerement bleute ;
+- le violet et le bleu servent aux actions, etats actifs, informations importantes et effets de profondeur ;
+- les effets lumineux restent subtils et ne doivent jamais reduire la lisibilite ;
+- l'interface doit etre elegante, dense et exploitable pendant une session de jeu.
+
+## 3. Tokens CSS
+
+Utiliser ces variables comme base. Ne pas coder les couleurs en dur dans les composants.
+
+```css
+:root {
+ color-scheme: dark;
+
+ --color-bg-page: #070913;
+ --color-bg-deep: #050711;
+ --color-bg-sidebar: #0b0e1b;
+ --color-bg-surface: #101426;
+ --color-bg-surface-alt: #151a30;
+ --color-bg-elevated: #1a2038;
+ --color-bg-hover: #202745;
+
+ --color-primary: #8b5cf6;
+ --color-primary-hover: #9f7aea;
+ --color-primary-active: #7347dc;
+ --color-primary-soft: rgba(139, 92, 246, 0.14);
+ --color-primary-border: rgba(139, 92, 246, 0.45);
+
+ --color-secondary: #3b82f6;
+ --color-secondary-hover: #60a5fa;
+ --color-secondary-active: #2563eb;
+ --color-secondary-soft: rgba(59, 130, 246, 0.14);
+
+ --color-accent-cyan: #22d3ee;
+ --color-accent-pink: #d946ef;
+ --color-accent-indigo: #6366f1;
+
+ --color-text-primary: #f5f7ff;
+ --color-text-secondary: #b4bdd3;
+ --color-text-muted: #7d879f;
+ --color-text-disabled: #555e73;
+ --color-text-inverse: #080a13;
+
+ --color-border: rgba(150, 165, 205, 0.14);
+ --color-border-hover: rgba(150, 165, 205, 0.28);
+ --color-border-strong: rgba(167, 139, 250, 0.42);
+
+ --color-success: #34d399;
+ --color-success-soft: rgba(52, 211, 153, 0.13);
+ --color-warning: #fbbf24;
+ --color-warning-soft: rgba(251, 191, 36, 0.13);
+ --color-danger: #fb7185;
+ --color-danger-soft: rgba(251, 113, 133, 0.13);
+ --color-info: #38bdf8;
+ --color-info-soft: rgba(56, 189, 248, 0.13);
+
+ --gradient-brand: linear-gradient(135deg, #8b5cf6 0%, #6366f1 45%, #3b82f6 100%);
+ --gradient-nebula: linear-gradient(
+ 135deg,
+ rgba(139, 92, 246, 0.28),
+ rgba(59, 130, 246, 0.18),
+ rgba(217, 70, 239, 0.12)
+ );
+ --gradient-page:
+ radial-gradient(circle at 20% 10%, rgba(124, 58, 237, 0.16), transparent 34%),
+ radial-gradient(circle at 85% 20%, rgba(37, 99, 235, 0.12), transparent 30%),
+ radial-gradient(circle at 55% 90%, rgba(217, 70, 239, 0.08), transparent 35%),
+ #070913;
+
+ --font-size-xs: 0.75rem;
+ --font-size-sm: 0.875rem;
+ --font-size-base: 1rem;
+ --font-size-lg: 1.125rem;
+ --font-size-xl: 1.25rem;
+ --font-size-2xl: 1.5rem;
+ --font-size-3xl: 2rem;
+ --font-size-4xl: 2.5rem;
+
+ --font-weight-regular: 400;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+
+ --space-1: 0.25rem;
+ --space-2: 0.5rem;
+ --space-3: 0.75rem;
+ --space-4: 1rem;
+ --space-5: 1.25rem;
+ --space-6: 1.5rem;
+ --space-8: 2rem;
+ --space-10: 2.5rem;
+ --space-12: 3rem;
+ --space-16: 4rem;
+
+ --radius-sm: 6px;
+ --radius-md: 10px;
+ --radius-lg: 14px;
+ --radius-xl: 18px;
+ --radius-2xl: 24px;
+ --radius-pill: 999px;
+
+ --shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.22);
+ --shadow-md: 0 12px 30px rgba(0, 0, 0, 0.3);
+ --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.42);
+ --shadow-primary: 0 0 28px rgba(139, 92, 246, 0.22);
+ --shadow-secondary: 0 0 28px rgba(59, 130, 246, 0.18);
+
+ --duration-fast: 120ms;
+ --duration-normal: 180ms;
+ --duration-slow: 260ms;
+ --ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
+
+ --breakpoint-sm: 640px;
+ --breakpoint-md: 768px;
+ --breakpoint-lg: 1024px;
+ --breakpoint-xl: 1280px;
+ --breakpoint-2xl: 1536px;
+}
+```
+
+## 4. Typographie
+
+Police principale :
+
+```css
+font-family: "Inter", "Segoe UI", system-ui, sans-serif;
+```
+
+Police d'accent optionnelle pour logo, grands titres, compteurs et titres de toolboxes :
+
+```css
+font-family: "Space Grotesk", "Inter", sans-serif;
+```
+
+Regles :
+
+- corps de texte : 14 a 16 px ;
+- titres de cartes : 15 a 18 px ;
+- titres de page : 28 a 36 px ;
+- hauteur de ligne : 1.5 a 1.65 ;
+- paragraphes longs limites a environ 70 caracteres ;
+- eviter les gris trop sombres sur fond noir.
+
+## 5. Layout Application
+
+Desktop :
+
+- sidebar gauche : `248px`, reductible a environ `72px` ;
+- zone centrale : flexible, `max-width: 1600px` ;
+- panneau contextuel droit facultatif : `320px`, repliable.
+
+La sidebar contient le logo, le nom de l'application, la creation de toolbox, la liste des toolboxes, les raccourcis vers les pages informatives, les parametres et le profil.
+
+La zone centrale contient le titre, les actions principales, les outils, les resultats et les contenus.
+
+Le panneau droit peut afficher membres, activite recente, details, filtres, historique ou options de partage.
+
+Mobile :
+
+- navigation inferieure ou menu lateral ;
+- contenu en une colonne ;
+- boutons importants pleine largeur ;
+- modales quasi plein ecran ;
+- filtres dans un panneau bas ;
+- cibles tactiles d'au moins `44px`.
+
+## 6. Navigation
+
+Element de navigation :
+
+```css
+.nav-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ min-height: 42px;
+ padding: 10px 12px;
+ border-radius: 10px;
+ color: var(--color-text-secondary);
+ transition: 160ms ease;
+}
+
+.nav-item:hover {
+ color: var(--color-text-primary);
+ background: var(--color-bg-hover);
+}
+
+.nav-item.active {
+ color: var(--color-text-primary);
+ background: var(--color-primary-soft);
+ border: 1px solid var(--color-primary-border);
+ box-shadow: inset 3px 0 0 var(--color-primary);
+}
+```
+
+L'etat actif doit etre clair sans fond violet trop sature.
+
+## 7. Topbar
+
+La barre superieure de la zone centrale peut contenir titre de page, toolbox active, recherche globale, avatars, notifications, partage et menu utilisateur.
+
+```css
+.topbar {
+ min-height: 68px;
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ backdrop-filter: blur(18px);
+ background: rgba(7, 9, 19, 0.78);
+}
+```
+
+## 8. Cartes
+
+```css
+.card {
+ background: rgba(16, 20, 38, 0.88);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-sm);
+ padding: 20px;
+ transition:
+ transform var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ background-color var(--duration-fast) var(--ease-standard);
+}
+
+.card:hover {
+ transform: translateY(-2px);
+ border-color: var(--color-border-hover);
+ background: rgba(21, 26, 48, 0.96);
+}
+
+.card.selected {
+ border-color: var(--color-primary-border);
+ box-shadow: var(--shadow-md), var(--shadow-primary);
+}
+```
+
+Une carte peut contenir icone, titre, description courte, statut, date/auteur, actions secondaires, contenu et pied de carte.
+
+## 9. Boutons
+
+Bouton principal :
+
+```css
+.button-primary {
+ min-height: 42px;
+ padding: 0 18px;
+ border: none;
+ border-radius: var(--radius-md);
+ color: white;
+ font-weight: 600;
+ background: var(--gradient-brand);
+ box-shadow: 0 8px 22px rgba(99, 102, 241, 0.22);
+}
+
+.button-primary:hover {
+ filter: brightness(1.08);
+ transform: translateY(-1px);
+ box-shadow: 0 10px 28px rgba(139, 92, 246, 0.3);
+}
+```
+
+Bouton secondaire :
+
+```css
+.button-secondary {
+ min-height: 42px;
+ padding: 0 18px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ color: var(--color-text-primary);
+ background: var(--color-bg-surface-alt);
+}
+```
+
+Bouton fantome :
+
+```css
+.button-ghost {
+ min-height: 38px;
+ padding: 0 12px;
+ border: 1px solid transparent;
+ color: var(--color-text-secondary);
+ background: transparent;
+}
+
+.button-ghost:hover {
+ color: var(--color-text-primary);
+ background: var(--color-bg-hover);
+}
+```
+
+Bouton danger : reserve aux actions destructrices, avec confirmation si l'action est irreversible.
+
+Bouton icone :
+
+```css
+.icon-button {
+ width: 40px;
+ height: 40px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 10px;
+ color: var(--color-text-secondary);
+ background: transparent;
+}
+```
+
+## 10. Formulaires
+
+```css
+.input {
+ width: 100%;
+ min-height: 44px;
+ padding: 0 14px;
+ border-radius: var(--radius-md);
+ border: 1px solid var(--color-border);
+ background: #0c1020;
+ color: var(--color-text-primary);
+ outline: none;
+}
+
+.input::placeholder {
+ color: var(--color-text-muted);
+}
+
+.input:focus {
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16);
+}
+
+.input.error {
+ border-color: var(--color-danger);
+ box-shadow: 0 0 0 3px var(--color-danger-soft);
+}
+```
+
+Textarea :
+
+- hauteur minimale `180px` ;
+- `resize: vertical` ;
+- `line-height: 1.6` ;
+- style coherent avec les autres champs.
+
+## 11. Outils Toolbox
+
+### Bloc-note
+
+Prevoir titre, contenu, auteur, date de derniere modification, autosauvegarde, statut de sauvegarde, epinglage, partage, suppression, lecture/edition et historique eventuel.
+
+```css
+.note-editor {
+ background: rgba(5, 7, 17, 0.56);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ padding: 16px;
+}
+```
+
+### Checklist
+
+Chaque tache peut comprendre case a cocher, titre, description, responsable, priorite, echeance et menu d'actions.
+
+```css
+.checkbox {
+ width: 20px;
+ height: 20px;
+ border-radius: 6px;
+ border: 1px solid var(--color-border-hover);
+ background: var(--color-bg-deep);
+}
+
+.checkbox.checked {
+ border-color: transparent;
+ background: var(--gradient-brand);
+}
+```
+
+Priorites :
+
+- faible : bleu ;
+- normale : violet ;
+- elevee : orange ;
+- critique : rouge.
+
+Ne jamais utiliser uniquement la couleur pour communiquer la priorite.
+
+### Captures d'ecran
+
+La galerie doit etre responsive :
+
+- mobile : 1 colonne ;
+- tablette : 2 colonnes ;
+- desktop : 3 ou 4 colonnes.
+
+Carte de capture : apercu, nom, auteur, date, tags, copier le lien, telecharger, ouvrir en grand, supprimer selon permissions.
+
+Dropzone :
+
+```css
+.dropzone {
+ min-height: 160px;
+ border: 1px dashed rgba(139, 92, 246, 0.52);
+ border-radius: var(--radius-lg);
+ background: var(--color-primary-soft);
+}
+
+.dropzone.drag-active {
+ border-color: var(--color-accent-cyan);
+ background: rgba(34, 211, 238, 0.1);
+ box-shadow: 0 0 30px rgba(34, 211, 238, 0.12);
+}
+```
+
+Visionneuse : fond presque noir, image centree, zoom, navigation entre images, metadonnees en panneau lateral, fermeture avec `Escape`.
+
+## 12. Toolboxes
+
+Une toolbox represente un espace de jeu. Une carte de toolbox affiche nom, icone/image, couleur, nombre de membres, nombre d'outils, derniere activite, avatars et statut prive/public. Les toolboxes ne portent pas de champ description.
+
+La toolbox active peut utiliser une bordure en degrade, une lueur violette subtile, une pastille active et un fond legerement plus lumineux.
+
+Creation d'une toolbox :
+
+- nom ;
+- icone ;
+- couleur d'accent ;
+- confidentialite ;
+- membres ;
+- outils ajoutes immediatement.
+
+Couleurs d'accent proposees : violet, bleu, cyan, indigo, rose cosmique, vert emeraude.
+
+## 13. Pages Informatives
+
+Les pages informatives presentent des donnees structurees : objets, cartes, ressources, personnages, statistiques, strategies, equipements, recettes, quetes, evenements et liens utiles.
+
+Structure recommandee :
+
+1. titre ;
+2. description ;
+3. recherche ;
+4. filtres ;
+5. selecteur d'affichage ;
+6. grille ou tableau ;
+7. pagination ;
+8. panneau de detail.
+
+La structure visuelle doit rester independante de la source de donnees JSON ou API.
+
+Exemple :
+
+```json
+{
+ "id": "item-001",
+ "name": "Nom de l'element",
+ "category": "Categorie",
+ "rarity": "epic",
+ "tags": ["support", "coop"],
+ "image": "/images/item-001.webp",
+ "description": "Description de l'element",
+ "stats": {
+ "power": 85,
+ "speed": 42
+ }
+}
+```
+
+## 14. Filtres Et Tableaux
+
+Filtres possibles : recherche textuelle, categorie, rarete, jeu, type, auteur, date, tags, statut et favoris.
+
+Desktop : barre horizontale, panneau lateral droit ou zone repliable au-dessus du contenu.
+
+Mobile : panneau venant du bas.
+
+```css
+.filter-chip.active {
+ color: #fff;
+ background: var(--color-primary-soft);
+ border-color: var(--color-primary-border);
+}
+```
+
+Afficher le nombre de filtres actifs et prevoir une action de reinitialisation.
+
+Tableaux :
+
+- en-tete lisible en dark mode ;
+- ligne separee par `var(--color-border)` ;
+- hover discret `rgba(139, 92, 246, 0.06)` ;
+- en-tete fixe pour les longs tableaux ;
+- tri indique par une fleche ;
+- valeurs numeriques alignees a droite ;
+- mobile : cartes ou scroll horizontal.
+
+## 15. Badges, Avatars, Presence
+
+Badge :
+
+```css
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ min-height: 24px;
+ padding: 3px 9px;
+ border-radius: var(--radius-pill);
+ font-size: 12px;
+ font-weight: 600;
+}
+```
+
+Exemples :
+
+- en ligne : `background: var(--color-success-soft); color: var(--color-success);`
+- prive : `background: var(--color-primary-soft); color: #b69cff;`
+- nouveau : `background: var(--color-info-soft); color: var(--color-info);`
+- attention : `background: var(--color-warning-soft); color: var(--color-warning);`
+
+Tailles avatar :
+
+```css
+--avatar-xs: 24px;
+--avatar-sm: 32px;
+--avatar-md: 40px;
+--avatar-lg: 52px;
+```
+
+Presence :
+
+- vert : en ligne ;
+- bleu : en jeu ;
+- jaune : absent ;
+- gris : hors ligne ;
+- rouge : ne pas deranger.
+
+Ne pas reposer uniquement sur la couleur. Ajouter un tooltip ou un libelle accessible.
+
+## 16. Notifications, Modales, Menus
+
+Toasts :
+
+- position : `right: 20px; bottom: 20px;`
+- information : 4 s ;
+- succes : 3 a 4 s ;
+- avertissement : 6 s ;
+- erreur : persistante ou 8 s.
+
+Les notifications ne doivent pas masquer les actions principales.
+
+Modales :
+
+```css
+.modal-backdrop {
+ background: rgba(2, 3, 9, 0.76);
+ backdrop-filter: blur(8px);
+}
+
+.modal {
+ width: min(560px, calc(100vw - 32px));
+ max-height: calc(100vh - 48px);
+ overflow-y: auto;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: var(--color-bg-surface);
+ box-shadow: var(--shadow-lg);
+}
+```
+
+Les actions de modale sont regroupees en bas a droite. Sur mobile, une modale peut devenir un panneau plein ecran.
+
+Menus contextuels :
+
+- fond eleve ;
+- ombre forte ;
+- separateurs fins ;
+- rayon 10 a 12 px ;
+- largeur minimale 180 px ;
+- action dangereuse isolee visuellement.
+
+## 17. Etats UI
+
+Etats vides :
+
+- icone ou illustration simple ;
+- titre ;
+- explication courte ;
+- action claire ;
+- jamais de section completement vide.
+
+Chargement :
+
+- skeletons pour cartes, listes, tableaux, galeries, profils ;
+- spinner reserve aux petites actions ;
+- bouton en chargement conserve sa largeur.
+
+Erreur :
+
+- icone ;
+- titre clair ;
+- explication comprehensible ;
+- detail technique secondaire si utile ;
+- bouton pour reessayer.
+
+## 18. Icones
+
+Bibliotheque recommandee : Lucide Icons. Ne pas melanger plusieurs bibliotheques.
+
+Style :
+
+- contour ;
+- epaisseur reguliere ;
+- taille 18 a 22 px ;
+- coins legerement arrondis.
+
+Mappings recommandes :
+
+- toolbox : `Package`, `Boxes`, `Briefcase` ;
+- bloc-note : `NotebookPen` ;
+- checklist : `ListChecks` ;
+- screenshot : `Image` ;
+- membres : `Users` ;
+- informations : `Database`, `BookOpen` ;
+- parametres : `Settings` ;
+- filtre : `SlidersHorizontal` ;
+- recherche : `Search` ;
+- partager : `Share2` ;
+- ajouter : `Plus`.
+
+## 19. Animations
+
+Animations rapides et discretes uniquement :
+
+- leger deplacement vertical au survol ;
+- fondu ;
+- changement de couleur ;
+- ouverture fluide d'un panneau ;
+- apparition d'un menu ;
+- legere pulsation d'un statut en ligne ;
+- transition entre vues grille/liste.
+
+Eviter animations permanentes, rotations gratuites, zooms importants, flashes et effets neon agressifs.
+
+```css
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
+```
+
+## 20. Scrollbars
+
+Les zones scrollables doivent reprendre le style de l'ancien site : piste sombre, ombre interne claire et pouce avec degrade violet/indigo. Pour l'integration **Nebula Command**, le rail noir historique est remplace par un bleu-noir profond.
+
+Version globale recommandee :
+
+```css
+.legacy-scrollbar::-webkit-scrollbar {
+ background-color: transparent;
+ width: 6px;
+ height: 6px;
+ border-radius: 0;
+}
+
+.legacy-scrollbar::-webkit-scrollbar-track {
+ background-color: transparent;
+ border-radius: 0;
+ box-shadow: none;
+}
+
+.legacy-scrollbar::-webkit-scrollbar-thumb {
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.5, rgb(79, 26, 114)), color-stop(1, rgb(44, 1, 135)));
+ border-radius: 10px;
+}
+```
+
+Dimensions recommandees :
+
+- scrollbar principale, panneau lateral, drawer, liste de filtres ou tableau : `6px` ;
+- rail transparent pour eviter les doubles bordures avec les panneaux ;
+- thumb arrondi sans bordure interne ;
+- sur un panneau borde, ajouter un leger `padding-right` au contenu scrollable pour separer le thumb de la bordure du panneau ;
+- ne pas utiliser de scrollbar trop lumineuse sur les zones de lecture longues.
+
+Les scrollbars doivent etre appliquees aux panneaux, menus, drawers, listes de filtres, tableaux et zones de details. Utiliser la classe `.legacy-scrollbar` sur les zones internes qui doivent reprendre explicitement l'ancien rendu. Eviter les overrides globaux comme `scrollbar-width` ou `scrollbar-color`, car ils changent l'aspect par rapport a l'ancien site.
+
+## 21. Accessibilite
+
+Minimum WCAG AA.
+
+Regles :
+
+- contraste suffisant ;
+- navigation clavier complete ;
+- focus visible ;
+- labels de champs ;
+- textes alternatifs aux images ;
+- ne jamais utiliser uniquement la couleur pour transmettre une information ;
+- boutons reels pour actions ;
+- liens reels pour navigation ;
+- hierarchie correcte `h1`, `h2`, `h3` ;
+- notifications importantes annoncees aux lecteurs d'ecran ;
+- modales correctement gerees au clavier.
+
+```css
+:focus-visible {
+ outline: 2px solid var(--color-accent-cyan);
+ outline-offset: 3px;
+}
+```
+
+## 22. Fond Galaxie Et Effet Verre
+
+Fond recommande :
+
+- gradient CSS ;
+- pseudo-element avec motif discret ;
+- particules statiques seulement ;
+- aucun canvas anime en permanence par defaut.
+
+```css
+body {
+ min-height: 100vh;
+ color: var(--color-text-primary);
+ background: var(--gradient-page);
+}
+
+body::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0.25;
+ background-image:
+ radial-gradient(circle, rgba(255, 255, 255, 0.5) 1px, transparent 1px),
+ radial-gradient(circle, rgba(139, 92, 246, 0.35) 1px, transparent 1px);
+ background-size: 90px 90px, 140px 140px;
+ background-position: 0 0, 35px 60px;
+}
+```
+
+Effet verre autorise sur topbar, modales, panneaux flottants, barre de filtres et menus. Ne pas l'appliquer a toutes les cartes.
+
+```css
+.glass-panel {
+ background: rgba(16, 20, 38, 0.72);
+ border: 1px solid rgba(165, 180, 252, 0.14);
+ backdrop-filter: blur(18px);
+ -webkit-backdrop-filter: blur(18px);
+}
+```
+
+## 23. Ecrans Cibles
+
+Accueil :
+
+- message de bienvenue ;
+- toolbox recemment utilisee ;
+- bouton creer une toolbox ;
+- bouton rejoindre une toolbox si collaboration activee ;
+- section Mes toolboxes ;
+- activite recente ;
+- outils rapides.
+
+Page toolbox :
+
+- nom, icone ;
+- membres ;
+- inviter, partager, options ;
+- onglets : vue d'ensemble, notes, checklists, captures, fichiers, informations, activite ;
+- vue d'ensemble avec outils epingles, notes recentes, taches en cours, dernieres captures et activite.
+
+Pages informatives :
+
+- recherche ;
+- filtres ;
+- vue grille/table ;
+- detail ;
+- association rapide a une toolbox.
+
+## 24. Permissions Et Themes Par Toolbox
+
+Roles visuels a prevoir :
+
+- proprietaire ;
+- administrateur ;
+- membre ;
+- lecteur.
+
+Actions indisponibles :
+
+- masquer si cela simplifie l'interface ;
+- sinon desactiver avec tooltip explicatif.
+
+Chaque toolbox peut definir une couleur d'accent :
+
+```css
+.toolbox-theme {
+ --toolbox-accent: #8b5cf6;
+ --toolbox-accent-soft: rgba(139, 92, 246, 0.14);
+}
+```
+
+Cette couleur peut etre utilisee pour icone, bordure active, badges, graphiques, titre et certains boutons secondaires. La couleur principale de l'application doit rester coherente.
+
+## 25. Recommandations Techniques
+
+Stack suggeree pour une refonte propre :
+
+- React ou Next.js ;
+- TypeScript strict ;
+- Tailwind CSS ou CSS Modules ;
+- Lucide React pour les icones ;
+- Radix UI ou shadcn/ui pour les composants accessibles ;
+- Framer Motion uniquement pour quelques transitions utiles ;
+- React Hook Form pour les formulaires ;
+- Zod pour la validation ;
+- TanStack Query pour les donnees distantes ;
+- TanStack Table pour les tableaux ;
+- Zustand ou Context API pour un etat global leger.
+
+Organisation cible :
+
+```text
+src/
+ components/
+ ui/
+ Button
+ Input
+ Textarea
+ Modal
+ Dropdown
+ Badge
+ Avatar
+ Tooltip
+ Tabs
+ Card
+ Toast
+ Skeleton
+ layout/
+ AppShell
+ Sidebar
+ Topbar
+ MobileNavigation
+ ContextPanel
+ toolbox/
+ ToolboxCard
+ ToolboxHeader
+ ToolboxMembers
+ ToolboxSettings
+ CreateToolboxModal
+ tools/
+ NoteTool
+ ChecklistTool
+ ScreenshotTool
+ FileTool
+ information/
+ FilterBar
+ DataCard
+ DataTable
+ DataDetailsPanel
+ EmptyResults
+ pages/
+ hooks/
+ services/
+ stores/
+ styles/
+ types/
+```
+
+Regles de developpement :
+
+- creer les composants UI de base avant les pages ;
+- centraliser les couleurs en variables CSS ;
+- gerer les etats normal, hover, active, focus, disabled, loading et error ;
+- concevoir mobile-first ;
+- ajouter des donnees fictives JSON pour tester les vues ;
+- separer les composants visuels de la recuperation des donnees ;
+- prevoir les permissions ;
+- traiter l'accessibilite des le debut ;
+- eviter les composants de plus de 250 a 300 lignes ;
+- ajouter des tests sur les composants critiques.
diff --git a/README.md b/README.md
index e69de29..8d8b827 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,95 @@
+# Sokko G
+
+Webapp locale pour préparer et accompagner des sessions gaming sur second écran.
+
+Sokko G propose des toolboxes modulaires stockées dans le navigateur, ainsi que des pages de guides de jeu maintenues dans le dépôt. Aucune donnée utilisateur n’est envoyée côté serveur.
+
+## Fonctionnalités
+
+- Toolboxes locales stockées dans `localStorage`.
+- Outils disponibles : bloc notes, checklist avec quantités, screenshots.
+- Import/export d’une toolbox.
+- Import/export global de toutes les toolboxes.
+- Association locale entre une page jeu et une toolbox.
+- Panneau latéral redimensionnable sur les pages jeux.
+- Suivi et contrôle du quota localStorage.
+- Pages de guides de jeu éditables via JSON.
+
+## Démarrage
+
+```bash
+npm run dev
+```
+
+Par défaut, le site démarre sur `http://localhost:5173`.
+
+## Configuration
+
+Le serveur lit automatiquement un fichier `.env` à la racine du projet.
+
+```bash
+cp .env.example .env
+```
+
+Exemple :
+
+```env
+PORT=5173
+```
+
+Le fichier `.env` est ignoré par git. Pour changer le port localement, modifier `PORT`.
+
+## Vérifications
+
+Avant un push ou une mise en ligne :
+
+```bash
+npm run check
+```
+
+Cette commande vérifie la syntaxe de `website/src/app.js`, celle de `server.mjs`, puis lance les tests.
+
+## Contenu éditable
+
+Les contenus maintenus à la main sont regroupés dans `website/public/data`.
+
+| Fichier | Rôle |
+| --- | --- |
+| `website/public/data/site.json` | Textes généraux du site : home, navigation, sidebar, page toolboxes. |
+| `website/public/data/games.json` | Liste des jeux affichés sur `/games` et contenus des cards jeux. |
+| `website/public/data/mhwilds/monsters.json` | Données des monstres Monster Hunter Wilds. |
+| `website/public/data/mhwilds/endemic_life.json` | Données de la faune Monster Hunter Wilds. |
+| `website/public/data/mhwilds/i18n/fr.json` | Traductions françaises des données MHWilds. |
+| `website/public/data/mhwilds/i18n/en.json` | Traductions anglaises des données MHWilds. |
+| `website/public/data/toolbox-icons.json` | Manifeste des icônes SVG réutilisables. |
+
+Les images publiques sont dans `website/public/static`.
+
+## Structure
+
+```text
+.
+├── DESIGN_SYSTEM.md
+├── package.json
+├── server.mjs
+├── tests/
+└── website/
+ ├── public/
+ │ ├── data/
+ │ ├── static/
+ │ └── index.html
+ └── src/
+ ├── app.js
+ └── styles.css
+```
+
+## Stockage local
+
+Clés principales :
+
+- `sokkog:toolboxes` : registre local des toolboxes.
+- `sokkog:game-toolbox-links` : associations locales jeu -> toolbox.
+- `sokkog:toolbox:{toolboxId}:module:{moduleId}` : données de chaque outil.
+- `sokkog:drawer-width` : largeur du panneau latéral.
+
+Le quota applicatif est contrôlé côté navigateur avant écriture. Les imports globaux simulent l’espace nécessaire avant de modifier les données locales.
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..04b5cb6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "sokko-g",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "start": "node server.mjs",
+ "dev": "node server.mjs",
+ "check": "node --check website/src/app.js && node --check server.mjs && npm test",
+ "test": "node --test"
+ }
+}
diff --git a/server.mjs b/server.mjs
new file mode 100644
index 0000000..35bbafb
--- /dev/null
+++ b/server.mjs
@@ -0,0 +1,96 @@
+import { createReadStream, existsSync, readFileSync, statSync } from "node:fs";
+import { createServer } from "node:http";
+import { extname, join, relative, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+
+const root = resolve(fileURLToPath(new URL(".", import.meta.url)), "website");
+const publicRoot = join(root, "public");
+
+function loadEnvFile(file = ".env") {
+ if (!existsSync(file)) return;
+
+ const lines = readFileSync(file, "utf8").split(/\r?\n/);
+ lines.forEach((line) => {
+ const trimmed = line.trim();
+ if (!trimmed || trimmed.startsWith("#")) return;
+
+ const separatorIndex = trimmed.indexOf("=");
+ if (separatorIndex < 1) return;
+
+ const key = trimmed.slice(0, separatorIndex).trim();
+ const value = trimmed.slice(separatorIndex + 1).trim().replace(/^["']|["']$/g, "");
+ if (!process.env[key]) process.env[key] = value;
+ });
+}
+
+loadEnvFile();
+
+const port = Number(process.env.PORT || 5173);
+
+const types = {
+ ".html": "text/html; charset=utf-8",
+ ".css": "text/css; charset=utf-8",
+ ".js": "text/javascript; charset=utf-8",
+ ".json": "application/json; charset=utf-8",
+ ".svg": "image/svg+xml",
+ ".ico": "image/x-icon",
+ ".png": "image/png",
+ ".jpg": "image/jpeg",
+ ".jpeg": "image/jpeg",
+ ".webp": "image/webp"
+};
+
+function isInsideRoot(parent, file) {
+ const relativePath = relative(parent, file);
+ return Boolean(relativePath) && !relativePath.startsWith("..") && !relativePath.startsWith("/");
+}
+
+function fileIfReadable(file) {
+ return isInsideRoot(root, file) && existsSync(file) && statSync(file).isFile() ? file : null;
+}
+
+function resolvePath(url) {
+ let requested;
+ try {
+ requested = decodeURIComponent(new URL(url, "http://localhost").pathname);
+ } catch {
+ return null;
+ }
+
+ const candidate = fileIfReadable(resolve(root, `.${requested}`));
+ if (candidate) return candidate;
+
+ const publicCandidate = fileIfReadable(resolve(publicRoot, `.${requested}`));
+ if (publicCandidate && isInsideRoot(publicRoot, publicCandidate)) return publicCandidate;
+
+ return join(publicRoot, "index.html");
+}
+
+const server = createServer((req, res) => {
+ const file = resolvePath(req.url || "/");
+ if (!file || !existsSync(file)) {
+ res.writeHead(404);
+ res.end("Not found");
+ return;
+ }
+
+ res.writeHead(200, {
+ "Content-Type": types[extname(file)] || "application/octet-stream",
+ "Cache-Control": "no-store"
+ });
+ createReadStream(file).pipe(res);
+});
+
+server.on("error", (error) => {
+ if (error.code === "EADDRINUSE") {
+ console.error(`Port ${port} is already in use. Set PORT to another value.`);
+ process.exit(1);
+ }
+
+ console.error(error);
+ process.exit(1);
+});
+
+server.listen(port, () => {
+ console.log(`Sokko G dev server running at http://localhost:${port}`);
+});
diff --git a/tests/static-smoke.test.mjs b/tests/static-smoke.test.mjs
new file mode 100644
index 0000000..b59ae26
--- /dev/null
+++ b/tests/static-smoke.test.mjs
@@ -0,0 +1,108 @@
+import { readFile } from "node:fs/promises";
+import { test } from "node:test";
+import assert from "node:assert/strict";
+
+test("static entrypoint loads the application assets", async () => {
+ const html = await readFile("website/public/index.html", "utf8");
+
+ assert.match(html, /
<\/div>/);
+ assert.match(html, /\/favicon\.ico/);
+ assert.match(html, /\/src\/app\.js/);
+ assert.match(html, /\/src\/styles\.css/);
+});
+
+test("application defines the expected local toolbox primitives", async () => {
+ const source = await readFile("website/src/app.js", "utf8");
+
+ assert.match(source, /sokkog:toolboxes/);
+ assert.match(source, /sokkog:game-toolbox-links/);
+ assert.match(source, /DEFAULT_SITE_CONTENT/);
+ assert.match(source, /function loadSiteContent/);
+ assert.match(source, /\/data\/site\.json/);
+ assert.match(source, /APP_STORAGE_LIMIT_BYTES/);
+ assert.match(source, /function renderStorageQuota/);
+ assert.match(source, /function writeStorageValue/);
+ assert.match(source, /role="progressbar"/);
+ assert.match(source, /export-all-toolboxes/);
+ assert.match(source, /import-all-toolboxes/);
+ assert.match(source, /function createGlobalExportPayload/);
+ assert.match(source, /function importAllToolboxes/);
+ assert.match(source, /open-link-toolbox-modal/);
+ assert.match(source, /function showToolboxLinkModal/);
+ assert.match(source, /data-game-id/);
+ assert.match(source, /notepad/);
+ assert.match(source, /checklist/);
+ assert.match(source, /screenshots/);
+ assert.doesNotMatch(source, /description: _description/);
+ assert.match(source, /function showToolboxCreateModal/);
+ assert.match(source, /data-action="toolbox-create-form"/);
+ assert.match(source, /function getToolboxGameId/);
+ assert.match(source, /dragon\.png/);
+ assert.match(source, /const game = getToolboxGame\(toolbox\)/);
+ assert.match(source, /moduleColumns/);
+ assert.match(source, /data-action="set-module-layout"/);
+ assert.match(source, /data-action="edit-toolbox-title"/);
+ assert.match(source, /function renderToolboxModules/);
+ assert.match(source, /function moveToolboxModule/);
+ assert.match(source, /dragstart/);
+ assert.match(source, /qtyTarget/);
+ assert.match(source, /qtyCurrent/);
+ assert.match(source, /adjust-check-qty/);
+ assert.match(source, /paste-screenshot/);
+ assert.match(source, /clipboardData/);
+ assert.match(source, /function addScreenshotFiles/);
+ assert.match(source, /view-screenshot/);
+ assert.match(source, /function showScreenshotViewer/);
+ assert.match(source, /drop-screenshot/);
+ assert.match(source, /dataTransfer\.files/);
+});
+
+test("mhwilds data and assets are available", async () => {
+ const site = JSON.parse(await readFile("website/public/data/site.json", "utf8"));
+ const games = JSON.parse(await readFile("website/public/data/games.json", "utf8"));
+ const monsters = JSON.parse(await readFile("website/public/data/mhwilds/monsters.json", "utf8"));
+ const endemicLife = JSON.parse(await readFile("website/public/data/mhwilds/endemic_life.json", "utf8"));
+ const translations = JSON.parse(await readFile("website/public/data/mhwilds/i18n/fr.json", "utf8"));
+ const appSource = await readFile("website/src/app.js", "utf8");
+
+ assert.equal(site.brand.name, "Sokko G");
+ assert.equal(site.home.hero.title, "Sokko G");
+ assert.ok(site.toolboxes.storageHelp.items.length >= 3);
+ assert.equal(games.games[0].id, "mhwilds");
+ assert.equal(games.games[0].eyebrow, "Guide de jeu");
+ assert.match(games.games[0].image, /mhwilds\.png/);
+ assert.ok(monsters.monsters.length > 0);
+ assert.ok(endemicLife.endemicLife.length > 0);
+ assert.equal(translations.monsters, "monstres");
+ assert.match(appSource, /renderMhwildsListing/);
+ assert.match(appSource, /flip-monster-card/);
+ await readFile("website/public/static/img/mhwilds/chatacabra.png");
+});
+
+test("server supports local env configuration", async () => {
+ const server = await readFile("server.mjs", "utf8");
+ const envExample = await readFile(".env.example", "utf8");
+
+ assert.match(server, /function loadEnvFile/);
+ assert.match(server, /process\.env\.PORT/);
+ assert.match(envExample, /PORT=5173/);
+});
+
+test("legacy svg icons are available for reuse", async () => {
+ const manifest = JSON.parse(await readFile("website/public/data/toolbox-icons.json", "utf8"));
+
+ assert.ok(manifest.icons.length >= 4);
+ await readFile("website/public/static/icons/home.svg", "utf8");
+ await readFile("website/public/static/icons/checklist.svg", "utf8");
+ await readFile("website/public/static/icons/close.svg", "utf8");
+ await readFile("website/public/static/icons/columns.svg", "utf8");
+ await readFile("website/public/static/icons/export.svg", "utf8");
+ await readFile("website/public/static/icons/notepad.svg", "utf8");
+ await readFile("website/public/static/icons/picture.svg", "utf8");
+ await readFile("website/public/static/icons/rows.svg", "utf8");
+ await readFile("website/public/static/icons/rubber.svg", "utf8");
+ await readFile("website/public/static/icons/trashcan.svg", "utf8");
+ await readFile("website/public/favicon.ico");
+ await readFile("website/public/static/img/dragon.png");
+ await readFile("website/public/static/img/toolbox-icons/controller.svg", "utf8");
+});
diff --git a/website/public/data/games.json b/website/public/data/games.json
new file mode 100644
index 0000000..1de6d7e
--- /dev/null
+++ b/website/public/data/games.json
@@ -0,0 +1,38 @@
+{
+ "games": [
+ {
+ "id": "mhwilds",
+ "title": "Monster Hunter Wilds",
+ "eyebrow": "Guide de jeu",
+ "cover": "linear-gradient(135deg, rgba(139, 92, 246, 0.88) 0%, rgba(99, 102, 241, 0.82) 48%, rgba(34, 211, 238, 0.72) 100%)",
+ "image": "/static/img/mhwilds.png",
+ "summary": "Repères rapides pour préparer une chasse, suivre les priorités et garder les infos utiles sur un second écran.",
+ "sections": [
+ {
+ "title": "Préparation",
+ "items": [
+ "Choisir un repas adapté",
+ "Vérifier les pièges et consommables",
+ "Préparer un set anti-statuts"
+ ]
+ },
+ {
+ "title": "Pendant la chasse",
+ "items": [
+ "Marquer les parties cassables",
+ "Noter les timings de rage",
+ "Garder un oeil sur les objectifs secondaires"
+ ]
+ },
+ {
+ "title": "Après mission",
+ "items": [
+ "Capturer les drops rares",
+ "Mettre à jour les crafts suivis",
+ "Archiver les screenshots importants"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/website/public/data/mhwilds/endemic_life.json b/website/public/data/mhwilds/endemic_life.json
new file mode 100644
index 0000000..1040c74
--- /dev/null
+++ b/website/public/data/mhwilds/endemic_life.json
@@ -0,0 +1,1129 @@
+{
+ "endemicLife": [
+ {
+ "name": "vigorwasp",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "giant vigorwasp",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "purewasp",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "vigormantle bug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "chillmantle bug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "heatmantle bug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "wiggly litchi",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "paratoad",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "nitrotoad",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "sleeptoad",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "flashflies",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "dung beetle",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "bomb beetle",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "rime beetle",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "thunderbug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "great thunderbugs",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "flashbug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "godbug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "bitterbug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "dark hornet",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "wedge beetle",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "windrustler",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "black windrustler",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "nothpecker",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "landlight shrimp",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "amstrigian",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "hymstrigian",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "rufflizard",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "tracktail lizard",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "pallbug",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "quatreflies",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "emperor hopper",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "tyrant hopper",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "sandstar",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "leaflugger ant",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "florashell crab",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "crudeshell crab",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "curioshell crab",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "smokeshroud gekko",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "dapperwing",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "dazzlewing",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "mimiphyta",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "scarlet joyperch",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "starduster",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "vaporonid",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "omenfly",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "myriads",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "jewel scarab",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "regal jewel scarab",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "pink landlight shrimp",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "ember rufflizard",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "azure rufflizard",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gloom gekko",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "scalebat",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "blink angler",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "sparklerjelly",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "peony sparklerjelly",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "nu yaya",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gawkie",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "solanaria",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "pillopod",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "oilwell basin",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gillopod",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "petalfly",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "xu yo",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "downy crake",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "hercudrome",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gold hercudrome",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "prism hercudrome",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ }
+ ],
+ "aquaticLife": [
+ {
+ "name": "virid bowfin",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "sushifish",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "whetfish",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "goldenfish",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "platinumfish",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "burst arowana",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "bomb arowana",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest",
+ "oilwell basin"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "goldenfry",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gunpowderfish",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gravid bowfin",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "windward plains",
+ "scarlet forest",
+ "oilwell basin",
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "escunite",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "grand escunite",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "glass parexus",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "blind perch",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "iceshard cliffs",
+ "ruins of wyveria"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gastronome tuna",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "goliath squid",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "great trevally",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "gajau",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ },
+ {
+ "name": "speartuna",
+ "locations": [
+ {
+ "condition": "default",
+ "values": [
+ "scarlet forest"
+ ]
+ }
+ ],
+ "description": "to be completed"
+ }
+ ]
+}
diff --git a/website/public/data/mhwilds/i18n/en.json b/website/public/data/mhwilds/i18n/en.json
new file mode 100644
index 0000000..9790e7e
--- /dev/null
+++ b/website/public/data/mhwilds/i18n/en.json
@@ -0,0 +1,217 @@
+{
+ "and": "and",
+ "or": "or",
+ "reset": "reset",
+ "create checklist": "create checklist",
+ "to be completed": "to be completed",
+ "monsters": "monsters",
+ "endemic life": "endemic life",
+ "name": "name",
+ "weaknesses": "weaknesses",
+ "locations": "locations",
+ "ailments": "ailments",
+ "cut": "cut",
+ "blunt": "blunt",
+ "ammo": "ammo",
+ "windward plains": "windward plains",
+ "scarlet forest": "scarlet forest",
+ "ruins of wyveria": "ruins of wyveria",
+ "oilwell basin": "oilwell basin",
+ "iceshard cliffs": "iceshard cliffs",
+ "dragon": "dragon",
+ "fire": "fire",
+ "ice": "ice",
+ "thunder": "thunder",
+ "water": "water",
+ "dragonblight": "dragonblight",
+ "fireblight": "fireblight",
+ "iceblight": "iceblight",
+ "thunderblight": "thunderblight",
+ "waterblight": "waterblight",
+ "frostblight": "frostblight",
+ "bubbleblight": "bubbleblight",
+ "stench": "stench",
+ "sleep": "sleep",
+ "paralysis": "paralysis",
+ "blast": "blast",
+ "poison": "poison",
+ "webbed": "webbed",
+ "bleeding": "bleeding",
+ "stun": "stun",
+ "frenzy virus": "frenzy virus",
+ "defense down": "defense down",
+ "minor wind pressure": "minor wind pressure",
+ "dragon wind pressure": "dragon wind pressure",
+ "minor tremor": "minor tremor",
+ "weak roar": "weak roar",
+ "strong roar": "strong roar",
+ "mantle broken": "mantle broken",
+ "head": "head",
+ "nose": "nose",
+ "antenna": "antenna",
+ "neck": "neck",
+ "mouth": "mouth",
+ "torso": "torso",
+ "membrane": "membrane",
+ "tongue": "tongue",
+ "chest": "chest",
+ "belly": "belly",
+ "tentacle": "tentacle",
+ "back": "back",
+ "left wingarm": "left wingarm",
+ "right wingarm": "right wingarm",
+ "front left arm": "front left arm",
+ "front right arm": "front right arm",
+ "middle left arm": "middle left arm",
+ "middle right arm": "middle right arm",
+ "rear left arm": "rear left arm",
+ "rear right arm": "rear right arm",
+ "left wing": "left wing",
+ "right wing": "right wing",
+ "left leg": "left leg",
+ "right leg": "right leg",
+ "forelegs": "forelegs",
+ "left foreleg": "left foreleg",
+ "right foreleg": "right foreleg",
+ "hindlegs": "hindlegs",
+ "left hindleg": "left hindleg",
+ "right hindleg": "right hindleg",
+ "left chainblade": "left chainblade",
+ "right chainblade": "right chainblade",
+ "left claw": "left claw",
+ "right claw": "right claw",
+ "abdominal iceplate": "abdominal iceplate",
+ "large iceplate(hidden)": "large iceplate(hidden)",
+ "large iceplate(exposed)": "large iceplate(exposed)",
+ "head (crystallized)": "head (crystallized)",
+ "left wingarm (crystallized)": "left wingarm (crystallized)",
+ "right wingarm (crystallized)": "right wingarm (crystallized)",
+ "back fin": "back fin",
+ "stinger": "stinger",
+ "mantle": "mantle",
+ "petals": "petals",
+ "tail": "tail",
+ "tail hair": "tail hair",
+ "rear": "rear",
+ "tail tip": "tail tip",
+ "flying wyvern": "flying wyvern",
+ "fanged beast": "fanged beast",
+ "construct": "construct",
+ "chatacabra": "chatacabra",
+ "quematrice": "quematrice",
+ "lala barina": "lala barina",
+ "congalala": "congalala",
+ "balahara": "balahara",
+ "doshaguma": "doshaguma",
+ "uth duna": "uth duna",
+ "rompopolo": "rompopolo",
+ "rey dau": "rey dau",
+ "nerscylla": "nerscylla",
+ "hirabami": "hirabami",
+ "ajarakan": "ajarakan",
+ "nu udra": "nu udra",
+ "jin dahaad": "jin dahaad",
+ "xu wu": "xu wu",
+ "zoh shia": "zoh shia",
+ "yian kut-ku": "yian kut-ku",
+ "gypceros": "gypceros",
+ "rathian": "rathian",
+ "rathalos": "rathalos",
+ "gravios": "gravios",
+ "blangonga": "blangonga",
+ "gore magala": "gore magala",
+ "arkveld": "arkveld",
+ "mizutsune": "mizutsune",
+ "guardian doshaguma": "guardian doshaguma",
+ "guardian rathalos": "guardian rathalos",
+ "guardian ebony odogaron": "guardian ebony odogaron",
+ "guardian arkveld": "guardian arkveld",
+ "guardian fulgur anjanath": "guardian fulgur anjanath",
+ "vigorwasp": "vigorwasp",
+ "giant vigorwasp": "giant vigorwasp",
+ "purewasp": "purewasp",
+ "vigormantle bug": "vigormantle bug",
+ "chillmantle bug": "chillmantle bug",
+ "heatmantle bug": "heatmantle bug",
+ "wiggly litchi": "wiggly litchi",
+ "paratoad": "paratoad",
+ "nitrotoad": "nitrotoad",
+ "sleeptoad": "sleeptoad",
+ "flashflies": "flashflies",
+ "dung beetle": "dung beetle",
+ "bomb beetle": "bomb beetle",
+ "rime beetle": "rime beetle",
+ "thunderbug": "thunderbug",
+ "great thunderbugs": "great thunderbugs",
+ "flashbug": "flashbug",
+ "godbug": "godbug",
+ "bitterbug": "bitterbug",
+ "dark hornet": "dark hornet",
+ "wedge beetle": "wedge beetle",
+ "windrustler": "windrustler",
+ "black windrustler": "black windrustler",
+ "nothpecker": "nothpecker",
+ "landlight shrimp": "landlight shrimp",
+ "amstrigian": "amstrigian",
+ "hymstrigian": "hymstrigian",
+ "rufflizard": "rufflizard",
+ "tracktail lizard": "tracktail lizard",
+ "pallbug": "pallbug",
+ "quatreflies": "quatreflies",
+ "emperor hopper": "emperor hopper",
+ "tyrant hopper": "tyrant hopper",
+ "sandstar": "sandstar",
+ "leaflugger ant": "leaflugger ant",
+ "florashell crab": "florashell crab",
+ "crudeshell crab": "crudeshell crab",
+ "curioshell crab": "curioshell crab",
+ "smokeshroud gekko": "smokeshroud gekko",
+ "dapperwing": "dapperwing",
+ "dazzlewing": "dazzlewing",
+ "mimiphyta": "mimiphyta",
+ "scarlet joyperch": "scarlet joyperch",
+ "starduster": "starduster",
+ "vaporonid": "vaporonid",
+ "omenfly": "omenfly",
+ "myriads": "myriads",
+ "jewel scarab": "jewel scarab",
+ "regal jewel scarab": "regal jewel scarab",
+ "pink landlight shrimp": "pink landlight shrimp",
+ "ember rufflizard": "ember rufflizard",
+ "azure rufflizard": "azure rufflizard",
+ "gloom gekko": "gloom gekko",
+ "scalebat": "scalebat",
+ "blink angler": "blink angler",
+ "sparklerjelly": "sparklerjelly",
+ "peony sparklerjelly": "peony sparklerjelly",
+ "nu yaya": "nu yaya",
+ "gawkie": "gawkie",
+ "solanaria": "solanaria",
+ "pillopod": "pillopod",
+ "gillopod": "gillopod",
+ "petalfly": "petalfly",
+ "xu yo": "xu yo",
+ "downy crake": "downy crake",
+ "hercudrome": "hercudrome",
+ "gold hercudrome": "gold hercudrome",
+ "prism hercudrome": "prism hercudrome",
+ "virid bowfin": "virid bowfin",
+ "sushifish": "sushifish",
+ "whetfish": "whetfish",
+ "goldenfish": "goldenfish",
+ "platinumfish": "platinumfish",
+ "burst arowana": "burst arowana",
+ "bomb arowana": "bomb arowana",
+ "goldenfry": "goldenfry",
+ "gunpowderfish": "gunpowderfish",
+ "gravid bowfin": "gravid bowfin",
+ "escunite": "escunite",
+ "grand escunite": "grand escunite",
+ "glass parexus": "glass parexus",
+ "blind perch": "blind perch",
+ "gastronome tuna": "gastronome tuna",
+ "goliath squid": "goliath squid",
+ "great trevally": "great trevally",
+ "gajau": "gajau",
+ "speartuna": "speartuna"
+}
diff --git a/website/public/data/mhwilds/i18n/fr.json b/website/public/data/mhwilds/i18n/fr.json
new file mode 100644
index 0000000..3426394
--- /dev/null
+++ b/website/public/data/mhwilds/i18n/fr.json
@@ -0,0 +1,217 @@
+{
+ "and": "et",
+ "or": "ou",
+ "reset": "réinitialiser",
+ "create checklist": "créer checklist",
+ "to be completed": "à compléter",
+ "monsters": "monstres",
+ "endemic life": "faune endémique",
+ "name": "nom",
+ "weaknesses": "faiblesses",
+ "locations": "localisations",
+ "ailments": "afflictions",
+ "cut": "tranchant",
+ "blunt": "contondant",
+ "ammo": "projectiles",
+ "windward plains": "plaines venteuses",
+ "scarlet forest": "forêt écarlate",
+ "ruins of wyveria": "ruines de wyveria",
+ "oilwell basin": "bassin pétrolier",
+ "iceshard cliffs": "falaises de glaces",
+ "dragon": "dragon",
+ "fire": "feu",
+ "ice": "glace",
+ "thunder": "foudre",
+ "water": "eau",
+ "dragonblight": "fléau-dragon",
+ "fireblight": "fléau-feu",
+ "iceblight": "fléau-glace",
+ "thunderblight": "fléau-foudre",
+ "waterblight": "fléau-eau",
+ "frostblight": "fléau-givre",
+ "bubbleblight": "fléau-bulles",
+ "stench": "puanteur",
+ "sleep": "sommeil",
+ "paralysis": "paralysie",
+ "blast": "explosion",
+ "poison": "poison",
+ "webbed": "toile",
+ "bleeding": "hémorragie",
+ "stun": "flash",
+ "frenzy virus": "furie",
+ "defense down": "baisse de défense",
+ "minor wind pressure": "bourrasque mineure",
+ "dragon wind pressure": "bourrasque draconique",
+ "minor tremor": "secousse mineure",
+ "weak roar": "rugissement faible",
+ "strong roar": "rugissement fort",
+ "mantle broken": "manteau brisé",
+ "head": "tête",
+ "nose": "nez",
+ "antenna": "antenne",
+ "neck": "cou",
+ "mouth": "bouche",
+ "torso": "torse",
+ "membrane": "membrane",
+ "tongue": "langue",
+ "chest": "poitrine",
+ "belly": "ventre",
+ "tentacle": "tentacule",
+ "back": "dos",
+ "left wingarm": "patte ailée G",
+ "right wingarm": "patte ailée D",
+ "front left arm": "patte av. G",
+ "front right arm": "patte av. D",
+ "middle left arm": "patte mid. G",
+ "middle right arm": "patte mid. D",
+ "rear left arm": "patte ar. G",
+ "rear right arm": "patte ar. D",
+ "left wing": "aile gauche",
+ "right wing": "aile droite",
+ "left leg": "patte gauche",
+ "right leg": "patte droite",
+ "forelegs": "pattes av.",
+ "left foreleg": "patte av. G",
+ "right foreleg": "patte av. D",
+ "hindlegs": "pattes ar.",
+ "left hindleg": "patte ar. G",
+ "right hindleg": "patte ar. D",
+ "left chainblade": "chaines G",
+ "right chainblade": "chaines D",
+ "left claw": "griffes G",
+ "right claw": "griffes D",
+ "abdominal iceplate": "plaque gelée(flancs)",
+ "large iceplate(hidden)": "gde plaque gelée (cachée)",
+ "large iceplate(exposed)": "gde plaque gelée (visible)",
+ "head (crystallized)": "tête (cristallisée)",
+ "left wingarm (crystallized)": "patte ailée G (cristallisée)",
+ "right wingarm (crystallized)": "patte ailée D (cristallisée)",
+ "back fin": "nageoire dorsale",
+ "stinger": "dard",
+ "mantle": "manteau",
+ "petals": "petales",
+ "tail": "queue",
+ "tail hair": "poils de queue",
+ "rear": "arrière",
+ "tail tip": "Bout de queue",
+ "flying wyvern": "wyverne volante",
+ "fanged beast": "bête à crocs",
+ "construct": "artificiel",
+ "chatacabra": "chatacabra",
+ "quematrice": "quematrice",
+ "lala barina": "lala barina",
+ "congalala": "congalala",
+ "balahara": "balahara",
+ "doshaguma": "doshaguma",
+ "uth duna": "uth duna",
+ "rompopolo": "rompopolo",
+ "rey dau": "rey dau",
+ "nerscylla": "nerscylla",
+ "hirabami": "hirabami",
+ "ajarakan": "ajarakan",
+ "nu udra": "nu udra",
+ "jin dahaad": "jin dahaad",
+ "xu wu": "xu wu",
+ "zoh shia": "zoh shia",
+ "yian kut-ku": "yian kut-ku",
+ "gypceros": "gypceros",
+ "rathian": "rathian",
+ "rathalos": "rathalos",
+ "gravios": "gravios",
+ "blangonga": "blangonga",
+ "gore magala": "gore magala",
+ "arkveld": "arkveld",
+ "mizutsune": "mizutsune",
+ "guardian doshaguma": "doshaguma gardien",
+ "guardian rathalos": "rathalos gardien",
+ "guardian ebony odogaron": "odogaron désastre gardien",
+ "guardian arkveld": "arkveld gardien",
+ "guardian fulgur anjanath": "anjanath fulgurant gardien",
+ "vigorwasp": "vitaguêpe",
+ "giant vigorwasp": "grande vitaguêpe",
+ "purewasp": "curaguêpe",
+ "vigormantle bug": "vitanille",
+ "chillmantle bug": "glacianille",
+ "heatmantle bug": "calonille",
+ "wiggly litchi": "chenille-litchi",
+ "paratoad": "paralycrapaud",
+ "nitrotoad": "nitrocrapaud",
+ "sleeptoad": "somnicrapaud",
+ "flashflies": "flashinsectes",
+ "dung beetle": "",
+ "bomb beetle": "scarabombe",
+ "rime beetle": "scarabée des neiges",
+ "thunderbug": "foudrinsectes",
+ "great thunderbugs": "grands foudrinsectes",
+ "flashbug": "scaralux",
+ "godbug": "insecte immortel",
+ "bitterbug": "amerinsecte",
+ "dark hornet": "frelon clair-obscur",
+ "wedge beetle": "scaragrappin",
+ "windrustler": "filovent",
+ "black windrustler": "filovent noir",
+ "nothpecker": "",
+ "landlight shrimp": "crevette terralux",
+ "amstrigian": "amstrigien",
+ "hymstrigian": "",
+ "rufflizard": "gonflézard",
+ "tracktail lizard": "lézard markoda",
+ "pallbug": "charoptère",
+ "quatreflies": "trèflémères",
+ "emperor hopper": "criquet empereur",
+ "tyrant hopper": "criquet tyran",
+ "sandstar": "étoile des sables",
+ "leaflugger ant": "fourmifolia",
+ "florashell crab": "floracrabe",
+ "crudeshell crab": "pétrocrabe",
+ "curioshell crab": "curiocrabe",
+ "smokeshroud gekko": "",
+ "dapperwing": "bellaile",
+ "dazzlewing": "",
+ "mimiphyta": "mimiflore",
+ "scarlet joyperch": "perche rampante",
+ "starduster": "stellardine",
+ "vaporonid": "",
+ "omenfly": "libellule divinatoire",
+ "myriads": "myriades",
+ "jewel scarab": "scarajoyau",
+ "regal jewel scarab": "scarajoyau royal",
+ "pink landlight shrimp": "crevette terralux rose",
+ "ember rufflizard": "gonflézard incandescent",
+ "azure rufflizard": "",
+ "gloom gekko": "gecko nocturne",
+ "scalebat": "chauve-souris à écailles",
+ "blink angler": "poisson cillant",
+ "sparklerjelly": "flaméduse",
+ "peony sparklerjelly": "",
+ "nu yaya": "nu yaya",
+ "gawkie": "zieuteur",
+ "solanaria": "solanaria",
+ "pillopod": "plalimace",
+ "gillopod": "glalimace",
+ "petalfly": "pétaluciole",
+ "xu yo": "",
+ "downy crake": "",
+ "hercudrome": "",
+ "gold hercudrome": "",
+ "prism hercudrome": "",
+ "virid bowfin": "amie émeraude",
+ "sushifish": "sushipoisson",
+ "whetfish": "poissaiguiseur",
+ "goldenfish": "poisson d'or",
+ "platinumfish": "poisson platine",
+ "burst arowana": "arowana explosif",
+ "bomb arowana": "arowana bombe",
+ "goldenfry": "poisson rouge",
+ "gunpowderfish": "poisson-poudre",
+ "gravid bowfin": "amie gravide",
+ "escunite": "escunite",
+ "grand escunite": "grande escunite",
+ "glass parexus": "parexus de verre",
+ "blind perch": "perche aveugle",
+ "gastronome tuna": "thon glouton",
+ "goliath squid": "calmar titan",
+ "great trevally": "",
+ "gajau": "gajau",
+ "speartuna": ""
+}
diff --git a/website/public/data/mhwilds/monsters.json b/website/public/data/mhwilds/monsters.json
new file mode 100644
index 0000000..e552fd0
--- /dev/null
+++ b/website/public/data/mhwilds/monsters.json
@@ -0,0 +1,4437 @@
+{
+ "monsters": [
+ {
+ "name": "chatacabra",
+ "type": "amphibian",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "none"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "ice",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "tongue"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "tongue",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "rear",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "quematrice",
+ "type": "brute wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "fireblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "neck"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "lala barina",
+ "type": "temnoceran",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "paralysis"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "tail"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left claw",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right claw",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "petals",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "congalala",
+ "type": "fanged beast",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "minor tremor",
+ "poison",
+ "paralysis",
+ "blast",
+ "stench"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "ice"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "back"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "balahara",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "waterblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "doshaguma",
+ "type": "fanged beast",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor tremor"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "belly"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail hair",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "uth duna",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "waterblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "rompopolo",
+ "type": "brute wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "poison"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "tongue"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "back",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "rey dau",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "thunderblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water",
+ "ice"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "head"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "nerscylla",
+ "type": "temnoceran",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "poison",
+ "sleep",
+ "webbed"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire"
+ ]
+ },
+ {
+ "condition": "mantle broken",
+ "values": [
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "claw"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left claw",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right claw",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "belly",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "stinger",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "mantle",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "hirabami",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "frostblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "ajarakan",
+ "type": "fanged beast",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor tremor",
+ "fireblight",
+ "blast"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water",
+ "ice"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "leg"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "belly",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "back",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail tip",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "nu udra",
+ "type": "cephalopod",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "fireblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "membrane",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "mouth",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tentacle",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "front left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "front right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "middle left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "middle right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "rear left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "rear right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "guardian doshaguma",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor tremor",
+ "defense down"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "ice",
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "foreleg"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "right foreleg",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "tail hair",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "guardian rathalos",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "fireblight",
+ "poison"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "leg",
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left leg",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right leg",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 0,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "jin dahaad",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "strong roar",
+ "iceblight",
+ "frostblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth",
+ "torso"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "abdominal iceplate",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "large iceplate(hidden)",
+ "cut": 1,
+ "blunt": 1,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "large iceplate(exposed)",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 2,
+ "ice": 0,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "guardian ebony odogaron",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "dragonblight",
+ "bleeding"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "foreleg",
+ "tail"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 3,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 2,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 2,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 2,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "right foreleg",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 2,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "back",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 2,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 2,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 2,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "tail tip",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ }
+ ]
+ },
+ {
+ "name": "xu wu",
+ "type": "cephalopod",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "none"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "ice"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": []
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "membrane",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "mouth",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 3,
+ "dragon": 0
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "tentacle",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "front left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "front right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "middle left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "middle right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "rear left arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "rear right arm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "guardian arkveld",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "dragonblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "chainblade"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left chainblade",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right chainblade",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "zoh shia",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "strong roar",
+ "dragon wind pressure",
+ "fireblight",
+ "thunderblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": []
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "head (crystallized)",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wingarm",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right wingarm",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left wingarm (crystallized)",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wingarm (crystallized)",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "yian kut-ku",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "minor wind pressure",
+ "fireblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water",
+ "ice",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "neck",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "torso",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left wing",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right wing",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 4,
+ "fire": 1,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 0
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 2,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "gypceros",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "minor wind pressure",
+ "poison",
+ "stun"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "ice"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "head"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 4,
+ "fire": 2,
+ "water": 1,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "rathian",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "fireblight",
+ "poison"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left leg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 0,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 0,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ }
+ ]
+ },
+ {
+ "name": "guardian fulgur anjanath",
+ "type": "construct",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "thunderblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water",
+ "ice",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "nose",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "left wing",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 1,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 0
+ },
+ {
+ "name": "tail",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 1,
+ "water": 2,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "rathalos",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "fireblight",
+ "poison"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left leg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 0,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 0,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ }
+ ]
+ },
+ {
+ "name": "gravios",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "strong roar",
+ "minor tremor",
+ "fireblight",
+ "poison",
+ "sleep"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "water",
+ "ice",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "head",
+ "back",
+ "belly",
+ "tail"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "belly",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "back",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 2,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ }
+ ]
+ },
+ {
+ "name": "blangonga",
+ "type": "fanged beast",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "iceblight",
+ "frostblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "back"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 0
+ }
+ ]
+ },
+ {
+ "name": "gore magala",
+ "type": "demi elder",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "strong roar",
+ "frenzy virus"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "antenna",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "neck",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wingarm",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wingarm",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "arkveld",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "minor wind pressure",
+ "dragonblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "chainblade"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left chainblade",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right chainblade",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "left leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right leg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "mizutsune",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "fireblight",
+ "waterblight",
+ "bubbleblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "ice",
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "mouth"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left claw",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right claw",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "back fin",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 1,
+ "water": 0,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "seregios",
+ "type": "flying wyvern",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "bleeding"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "ice",
+ "thunder"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "legs"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "right wing",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "right hindleg",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 2,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "lagiacrus",
+ "type": "leviathan",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "weak roar",
+ "thunderblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "ice",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": [
+ "head",
+ "back"
+ ]
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "neck",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "forelegs",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "back",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 1,
+ "fire": 3,
+ "water": 0,
+ "thunder": 0,
+ "ice": 2,
+ "dragon": 2
+ },
+ {
+ "name": "hindlegs",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 3,
+ "water": 0,
+ "thunder": 0,
+ "ice": 1,
+ "dragon": 1
+ }
+ ]
+ },
+ {
+ "name": "omega planetes",
+ "type": "???",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "fireblight",
+ "hp penalty"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "thunder",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": []
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 3
+ },
+ {
+ "name": "torso",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 1,
+ "thunder": 1,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 3
+ },
+ {
+ "name": "right foreleg",
+ "cut": 3,
+ "blunt": 4,
+ "ammo": 4,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 3
+ },
+ {
+ "name": "back",
+ "cut": 3,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "left hindleg",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "right hindleg",
+ "cut": 4,
+ "blunt": 3,
+ "ammo": 3,
+ "fire": 0,
+ "water": 1,
+ "thunder": 3,
+ "ice": 1,
+ "dragon": 2
+ },
+ {
+ "name": "back unity",
+ "cut": 4,
+ "blunt": 4,
+ "ammo": 1,
+ "fire": 0,
+ "water": 1,
+ "thunder": 2,
+ "ice": 1,
+ "dragon": 4
+ }
+ ]
+ },
+ {
+ "name": "gogmazios",
+ "type": "Elder Dragon",
+ "ailments": [
+ {
+ "condition": "default",
+ "values": [
+ "minor tremor",
+ "strong roar",
+ "fireblight"
+ ]
+ }
+ ],
+ "weaknesses": [
+ {
+ "condition": "default",
+ "values": [
+ "fire",
+ "dragon"
+ ]
+ }
+ ],
+ "weakpoints": [
+ {
+ "condition": "default",
+ "values": []
+ }
+ ],
+ "damage": [
+ {
+ "name": "head",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "chest",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right foreleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "belly",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 0,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "back",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 2,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left wingarm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "right wingarm",
+ "cut": 3,
+ "blunt": 3,
+ "ammo": 2,
+ "fire": 2,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "left hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "right hindleg",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 0
+ },
+ {
+ "name": "tail",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ },
+ {
+ "name": "tail tip",
+ "cut": 2,
+ "blunt": 2,
+ "ammo": 1,
+ "fire": 1,
+ "water": 0,
+ "thunder": 0,
+ "ice": 0,
+ "dragon": 1
+ }
+ ]
+ }
+ ]
+}
diff --git a/website/public/data/site.json b/website/public/data/site.json
new file mode 100644
index 0000000..3a0133f
--- /dev/null
+++ b/website/public/data/site.json
@@ -0,0 +1,92 @@
+{
+ "brand": {
+ "name": "Sokko G",
+ "homeAriaLabel": "Accueil Sokko G"
+ },
+ "navigation": {
+ "home": "Accueil",
+ "toolboxes": "Toolboxes",
+ "games": "Pages jeux",
+ "mobileGames": "Infos"
+ },
+ "sidebar": {
+ "badge": "Local only",
+ "note": "Données stockées dans ce navigateur."
+ },
+ "topbar": {
+ "dashboard": "Dashboard",
+ "toolbox": "Toolbox active",
+ "games": "Informations jeu"
+ },
+ "home": {
+ "hero": {
+ "eyebrow": "Session gaming efficace",
+ "title": "Sokko G",
+ "description": "Centralisez vos outils et repères de jeu dans une interface locale, rapide à consulter, pensée pour accompagner vos sessions sans interrompre l’action.",
+ "primaryAction": "Voir les toolboxes",
+ "secondaryAction": "Voir les jeux"
+ },
+ "stats": {
+ "toolboxSingular": "toolbox créée",
+ "toolboxPlural": "toolboxs créées",
+ "toolSingular": "outil disponible",
+ "toolPlural": "outils disponibles"
+ },
+ "origin": {
+ "eyebrow": "Origine du nom",
+ "title": "Pourquoi Sokko G ?",
+ "visualAlt": "Dragon Sokko G",
+ "dialogueAriaLabel": "Dialogue d’origine du nom Sokko G",
+ "caption": "\"G\" c'est pour Gaming",
+ "lines": [
+ {
+ "speaker": "user",
+ "text": "Yo !\nComment peut on traduire en un minimum de mots :\n\"faire qqch de manière efficace et rapide\" en japonais ?"
+ },
+ {
+ "speaker": "app",
+ "text": "Une traduction concise en japonais serait :\n効率よく素早くやる
(Kōritsu yoku subayaku yaru) \nCela signifie littéralement \"le faire efficacement et rapidement.\""
+ },
+ {
+ "speaker": "user",
+ "text": "En plus court stp"
+ },
+ {
+ "speaker": "app",
+ "text": "迅速効率
(Jinsoku Kōritsu) \nCela signifie \"rapidité et efficacité\" en un minimum de mots."
+ },
+ {
+ "speaker": "user",
+ "text": "Encore plus court !"
+ },
+ {
+ "speaker": "app",
+ "text": "速効
(Sokkō) \nCela signifie \"efficacité rapide\" ou \"effet immédiat,\" selon le contexte."
+ },
+ {
+ "speaker": "user",
+ "text": "Merci ! :)"
+ }
+ ]
+ }
+ },
+ "toolboxes": {
+ "eyebrow": "Données locales",
+ "title": "Toolboxes",
+ "newButton": "Nouvelle toolbox",
+ "importAll": "Importer tout",
+ "exportAll": "Exporter tout",
+ "importOne": "Importer une toolbox",
+ "storageHelp": {
+ "title": "Sauvegardes locales",
+ "text": "Vos toolboxes restent sur cet appareil, dans ce navigateur. Rien n’est envoyé sur un serveur.",
+ "items": [
+ "Un nettoyage du navigateur ou un changement d’appareil peut supprimer les données.",
+ "Surveillez le quota, surtout si vous ajoutez des screenshots.",
+ "Faites un export global régulier pour garder une sauvegarde."
+ ]
+ },
+ "emptyTitle": "Aucune toolbox",
+ "emptyText": "Créez une première toolbox pour stocker vos outils dans ce navigateur."
+ }
+}
diff --git a/website/public/data/toolbox-icons.json b/website/public/data/toolbox-icons.json
new file mode 100644
index 0000000..d239194
--- /dev/null
+++ b/website/public/data/toolbox-icons.json
@@ -0,0 +1,24 @@
+{
+ "icons": [
+ {
+ "id": "default",
+ "label": "Toolbox",
+ "src": "/static/img/toolbox-icons/default.svg"
+ },
+ {
+ "id": "controller",
+ "label": "Controller",
+ "src": "/static/img/toolbox-icons/controller.svg"
+ },
+ {
+ "id": "quest",
+ "label": "Quest",
+ "src": "/static/img/toolbox-icons/quest.svg"
+ },
+ {
+ "id": "target",
+ "label": "Target",
+ "src": "/static/img/toolbox-icons/target.svg"
+ }
+ ]
+}
diff --git a/website/public/favicon.ico b/website/public/favicon.ico
new file mode 100644
index 0000000..e0bfd7d
Binary files /dev/null and b/website/public/favicon.ico differ
diff --git a/website/public/index.html b/website/public/index.html
new file mode 100644
index 0000000..c0c10ee
--- /dev/null
+++ b/website/public/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
Sokko G
+
+
+
+
+
+
+
+
+
+
diff --git a/website/public/static/icons/checklist.svg b/website/public/static/icons/checklist.svg
new file mode 100644
index 0000000..071c68f
--- /dev/null
+++ b/website/public/static/icons/checklist.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/close.svg b/website/public/static/icons/close.svg
new file mode 100644
index 0000000..ef3f3eb
--- /dev/null
+++ b/website/public/static/icons/close.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/columns.svg b/website/public/static/icons/columns.svg
new file mode 100644
index 0000000..f12620f
--- /dev/null
+++ b/website/public/static/icons/columns.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/controller.svg b/website/public/static/icons/controller.svg
new file mode 100644
index 0000000..a93c9cd
--- /dev/null
+++ b/website/public/static/icons/controller.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website/public/static/icons/copy.svg b/website/public/static/icons/copy.svg
new file mode 100644
index 0000000..3bc3d0d
--- /dev/null
+++ b/website/public/static/icons/copy.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/edit.svg b/website/public/static/icons/edit.svg
new file mode 100644
index 0000000..54bc424
--- /dev/null
+++ b/website/public/static/icons/edit.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/export.svg b/website/public/static/icons/export.svg
new file mode 100644
index 0000000..912797c
--- /dev/null
+++ b/website/public/static/icons/export.svg
@@ -0,0 +1,29 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/home.svg b/website/public/static/icons/home.svg
new file mode 100644
index 0000000..b658535
--- /dev/null
+++ b/website/public/static/icons/home.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/import.svg b/website/public/static/icons/import.svg
new file mode 100644
index 0000000..a79ee9d
--- /dev/null
+++ b/website/public/static/icons/import.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/link.svg b/website/public/static/icons/link.svg
new file mode 100644
index 0000000..ff8dac1
--- /dev/null
+++ b/website/public/static/icons/link.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/notepad.svg b/website/public/static/icons/notepad.svg
new file mode 100644
index 0000000..91a45d5
--- /dev/null
+++ b/website/public/static/icons/notepad.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/open.svg b/website/public/static/icons/open.svg
new file mode 100644
index 0000000..86573cf
--- /dev/null
+++ b/website/public/static/icons/open.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/picture.svg b/website/public/static/icons/picture.svg
new file mode 100644
index 0000000..7c6810c
--- /dev/null
+++ b/website/public/static/icons/picture.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/rows.svg b/website/public/static/icons/rows.svg
new file mode 100644
index 0000000..5fb7975
--- /dev/null
+++ b/website/public/static/icons/rows.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/rubber.svg b/website/public/static/icons/rubber.svg
new file mode 100644
index 0000000..645d2f4
--- /dev/null
+++ b/website/public/static/icons/rubber.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/save.svg b/website/public/static/icons/save.svg
new file mode 100644
index 0000000..583bdb5
--- /dev/null
+++ b/website/public/static/icons/save.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/icons/toolbox.svg b/website/public/static/icons/toolbox.svg
new file mode 100644
index 0000000..536d39c
--- /dev/null
+++ b/website/public/static/icons/toolbox.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/website/public/static/icons/trashcan.svg b/website/public/static/icons/trashcan.svg
new file mode 100644
index 0000000..0df6d81
--- /dev/null
+++ b/website/public/static/icons/trashcan.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/website/public/static/img/dragon.png b/website/public/static/img/dragon.png
new file mode 100644
index 0000000..160cc68
Binary files /dev/null and b/website/public/static/img/dragon.png differ
diff --git a/website/public/static/img/mhwilds.png b/website/public/static/img/mhwilds.png
new file mode 100644
index 0000000..a79e300
Binary files /dev/null and b/website/public/static/img/mhwilds.png differ
diff --git a/website/public/static/img/mhwilds/0-stars.png b/website/public/static/img/mhwilds/0-stars.png
new file mode 100644
index 0000000..11dbab2
Binary files /dev/null and b/website/public/static/img/mhwilds/0-stars.png differ
diff --git a/website/public/static/img/mhwilds/1-stars.png b/website/public/static/img/mhwilds/1-stars.png
new file mode 100644
index 0000000..39cb4b4
Binary files /dev/null and b/website/public/static/img/mhwilds/1-stars.png differ
diff --git a/website/public/static/img/mhwilds/2-stars.png b/website/public/static/img/mhwilds/2-stars.png
new file mode 100644
index 0000000..df92a3d
Binary files /dev/null and b/website/public/static/img/mhwilds/2-stars.png differ
diff --git a/website/public/static/img/mhwilds/3-stars.png b/website/public/static/img/mhwilds/3-stars.png
new file mode 100644
index 0000000..6f17c63
Binary files /dev/null and b/website/public/static/img/mhwilds/3-stars.png differ
diff --git a/website/public/static/img/mhwilds/4-stars.png b/website/public/static/img/mhwilds/4-stars.png
new file mode 100644
index 0000000..95e3bfc
Binary files /dev/null and b/website/public/static/img/mhwilds/4-stars.png differ
diff --git a/website/public/static/img/mhwilds/ajarakan.png b/website/public/static/img/mhwilds/ajarakan.png
new file mode 100644
index 0000000..5a728d9
Binary files /dev/null and b/website/public/static/img/mhwilds/ajarakan.png differ
diff --git a/website/public/static/img/mhwilds/ammo.png b/website/public/static/img/mhwilds/ammo.png
new file mode 100644
index 0000000..1bf0f9d
Binary files /dev/null and b/website/public/static/img/mhwilds/ammo.png differ
diff --git a/website/public/static/img/mhwilds/amstrigian.png b/website/public/static/img/mhwilds/amstrigian.png
new file mode 100644
index 0000000..da92e9e
Binary files /dev/null and b/website/public/static/img/mhwilds/amstrigian.png differ
diff --git a/website/public/static/img/mhwilds/arkveld.png b/website/public/static/img/mhwilds/arkveld.png
new file mode 100644
index 0000000..07e9395
Binary files /dev/null and b/website/public/static/img/mhwilds/arkveld.png differ
diff --git a/website/public/static/img/mhwilds/azure rufflizard.png b/website/public/static/img/mhwilds/azure rufflizard.png
new file mode 100644
index 0000000..38b5d1e
Binary files /dev/null and b/website/public/static/img/mhwilds/azure rufflizard.png differ
diff --git a/website/public/static/img/mhwilds/balahara.png b/website/public/static/img/mhwilds/balahara.png
new file mode 100644
index 0000000..6c236bb
Binary files /dev/null and b/website/public/static/img/mhwilds/balahara.png differ
diff --git a/website/public/static/img/mhwilds/bitterbug.png b/website/public/static/img/mhwilds/bitterbug.png
new file mode 100644
index 0000000..2a125e0
Binary files /dev/null and b/website/public/static/img/mhwilds/bitterbug.png differ
diff --git a/website/public/static/img/mhwilds/black windrustler.png b/website/public/static/img/mhwilds/black windrustler.png
new file mode 100644
index 0000000..b86c5c1
Binary files /dev/null and b/website/public/static/img/mhwilds/black windrustler.png differ
diff --git a/website/public/static/img/mhwilds/blangonga.png b/website/public/static/img/mhwilds/blangonga.png
new file mode 100644
index 0000000..1575241
Binary files /dev/null and b/website/public/static/img/mhwilds/blangonga.png differ
diff --git a/website/public/static/img/mhwilds/blast.png b/website/public/static/img/mhwilds/blast.png
new file mode 100644
index 0000000..4d2ddfb
Binary files /dev/null and b/website/public/static/img/mhwilds/blast.png differ
diff --git a/website/public/static/img/mhwilds/bleeding.png b/website/public/static/img/mhwilds/bleeding.png
new file mode 100644
index 0000000..0b4dd4d
Binary files /dev/null and b/website/public/static/img/mhwilds/bleeding.png differ
diff --git a/website/public/static/img/mhwilds/blind perch.png b/website/public/static/img/mhwilds/blind perch.png
new file mode 100644
index 0000000..4cc1dfb
Binary files /dev/null and b/website/public/static/img/mhwilds/blind perch.png differ
diff --git a/website/public/static/img/mhwilds/blink angler.png b/website/public/static/img/mhwilds/blink angler.png
new file mode 100644
index 0000000..e0999df
Binary files /dev/null and b/website/public/static/img/mhwilds/blink angler.png differ
diff --git a/website/public/static/img/mhwilds/blunt.png b/website/public/static/img/mhwilds/blunt.png
new file mode 100644
index 0000000..66a20c6
Binary files /dev/null and b/website/public/static/img/mhwilds/blunt.png differ
diff --git a/website/public/static/img/mhwilds/bomb arowana.png b/website/public/static/img/mhwilds/bomb arowana.png
new file mode 100644
index 0000000..3c16dba
Binary files /dev/null and b/website/public/static/img/mhwilds/bomb arowana.png differ
diff --git a/website/public/static/img/mhwilds/bomb beetle.png b/website/public/static/img/mhwilds/bomb beetle.png
new file mode 100644
index 0000000..636e9fe
Binary files /dev/null and b/website/public/static/img/mhwilds/bomb beetle.png differ
diff --git a/website/public/static/img/mhwilds/bubbleblight.png b/website/public/static/img/mhwilds/bubbleblight.png
new file mode 100644
index 0000000..6f89e73
Binary files /dev/null and b/website/public/static/img/mhwilds/bubbleblight.png differ
diff --git a/website/public/static/img/mhwilds/burst arowana.png b/website/public/static/img/mhwilds/burst arowana.png
new file mode 100644
index 0000000..8ef7146
Binary files /dev/null and b/website/public/static/img/mhwilds/burst arowana.png differ
diff --git a/website/public/static/img/mhwilds/chatacabra.png b/website/public/static/img/mhwilds/chatacabra.png
new file mode 100644
index 0000000..49be268
Binary files /dev/null and b/website/public/static/img/mhwilds/chatacabra.png differ
diff --git a/website/public/static/img/mhwilds/chillmantle bug.png b/website/public/static/img/mhwilds/chillmantle bug.png
new file mode 100644
index 0000000..ffc1e69
Binary files /dev/null and b/website/public/static/img/mhwilds/chillmantle bug.png differ
diff --git a/website/public/static/img/mhwilds/congalala.png b/website/public/static/img/mhwilds/congalala.png
new file mode 100644
index 0000000..a9bffba
Binary files /dev/null and b/website/public/static/img/mhwilds/congalala.png differ
diff --git a/website/public/static/img/mhwilds/crudeshell crab.png b/website/public/static/img/mhwilds/crudeshell crab.png
new file mode 100644
index 0000000..62a324f
Binary files /dev/null and b/website/public/static/img/mhwilds/crudeshell crab.png differ
diff --git a/website/public/static/img/mhwilds/curioshell crab.png b/website/public/static/img/mhwilds/curioshell crab.png
new file mode 100644
index 0000000..033cd9e
Binary files /dev/null and b/website/public/static/img/mhwilds/curioshell crab.png differ
diff --git a/website/public/static/img/mhwilds/cut.png b/website/public/static/img/mhwilds/cut.png
new file mode 100644
index 0000000..0314727
Binary files /dev/null and b/website/public/static/img/mhwilds/cut.png differ
diff --git a/website/public/static/img/mhwilds/dapperwing.png b/website/public/static/img/mhwilds/dapperwing.png
new file mode 100644
index 0000000..c18c058
Binary files /dev/null and b/website/public/static/img/mhwilds/dapperwing.png differ
diff --git a/website/public/static/img/mhwilds/dark hornet.png b/website/public/static/img/mhwilds/dark hornet.png
new file mode 100644
index 0000000..4547ad8
Binary files /dev/null and b/website/public/static/img/mhwilds/dark hornet.png differ
diff --git a/website/public/static/img/mhwilds/dazzlewing.png b/website/public/static/img/mhwilds/dazzlewing.png
new file mode 100644
index 0000000..02fd79b
Binary files /dev/null and b/website/public/static/img/mhwilds/dazzlewing.png differ
diff --git a/website/public/static/img/mhwilds/defense down.png b/website/public/static/img/mhwilds/defense down.png
new file mode 100644
index 0000000..6e51f9c
Binary files /dev/null and b/website/public/static/img/mhwilds/defense down.png differ
diff --git a/website/public/static/img/mhwilds/doshaguma.png b/website/public/static/img/mhwilds/doshaguma.png
new file mode 100644
index 0000000..c20a2de
Binary files /dev/null and b/website/public/static/img/mhwilds/doshaguma.png differ
diff --git a/website/public/static/img/mhwilds/downy crake.png b/website/public/static/img/mhwilds/downy crake.png
new file mode 100644
index 0000000..94ea76a
Binary files /dev/null and b/website/public/static/img/mhwilds/downy crake.png differ
diff --git a/website/public/static/img/mhwilds/dragon wind pressure.png b/website/public/static/img/mhwilds/dragon wind pressure.png
new file mode 100644
index 0000000..bce37b2
Binary files /dev/null and b/website/public/static/img/mhwilds/dragon wind pressure.png differ
diff --git a/website/public/static/img/mhwilds/dragon.png b/website/public/static/img/mhwilds/dragon.png
new file mode 100644
index 0000000..3072357
Binary files /dev/null and b/website/public/static/img/mhwilds/dragon.png differ
diff --git a/website/public/static/img/mhwilds/dragonblight.png b/website/public/static/img/mhwilds/dragonblight.png
new file mode 100644
index 0000000..3072357
Binary files /dev/null and b/website/public/static/img/mhwilds/dragonblight.png differ
diff --git a/website/public/static/img/mhwilds/dung beetle.png b/website/public/static/img/mhwilds/dung beetle.png
new file mode 100644
index 0000000..d378df2
Binary files /dev/null and b/website/public/static/img/mhwilds/dung beetle.png differ
diff --git a/website/public/static/img/mhwilds/ember rufflizard.png b/website/public/static/img/mhwilds/ember rufflizard.png
new file mode 100644
index 0000000..a831048
Binary files /dev/null and b/website/public/static/img/mhwilds/ember rufflizard.png differ
diff --git a/website/public/static/img/mhwilds/emperor hopper.png b/website/public/static/img/mhwilds/emperor hopper.png
new file mode 100644
index 0000000..87c3c86
Binary files /dev/null and b/website/public/static/img/mhwilds/emperor hopper.png differ
diff --git a/website/public/static/img/mhwilds/escunite.png b/website/public/static/img/mhwilds/escunite.png
new file mode 100644
index 0000000..da44728
Binary files /dev/null and b/website/public/static/img/mhwilds/escunite.png differ
diff --git a/website/public/static/img/mhwilds/fire.png b/website/public/static/img/mhwilds/fire.png
new file mode 100644
index 0000000..1de9397
Binary files /dev/null and b/website/public/static/img/mhwilds/fire.png differ
diff --git a/website/public/static/img/mhwilds/fireblight.png b/website/public/static/img/mhwilds/fireblight.png
new file mode 100644
index 0000000..1de9397
Binary files /dev/null and b/website/public/static/img/mhwilds/fireblight.png differ
diff --git a/website/public/static/img/mhwilds/flashbug.png b/website/public/static/img/mhwilds/flashbug.png
new file mode 100644
index 0000000..3342a9f
Binary files /dev/null and b/website/public/static/img/mhwilds/flashbug.png differ
diff --git a/website/public/static/img/mhwilds/flashflies.png b/website/public/static/img/mhwilds/flashflies.png
new file mode 100644
index 0000000..7d7a071
Binary files /dev/null and b/website/public/static/img/mhwilds/flashflies.png differ
diff --git a/website/public/static/img/mhwilds/florashell crab.png b/website/public/static/img/mhwilds/florashell crab.png
new file mode 100644
index 0000000..c547401
Binary files /dev/null and b/website/public/static/img/mhwilds/florashell crab.png differ
diff --git a/website/public/static/img/mhwilds/frenzy virus.png b/website/public/static/img/mhwilds/frenzy virus.png
new file mode 100644
index 0000000..006a00b
Binary files /dev/null and b/website/public/static/img/mhwilds/frenzy virus.png differ
diff --git a/website/public/static/img/mhwilds/frostblight.png b/website/public/static/img/mhwilds/frostblight.png
new file mode 100644
index 0000000..5f0aa69
Binary files /dev/null and b/website/public/static/img/mhwilds/frostblight.png differ
diff --git a/website/public/static/img/mhwilds/gajau.png b/website/public/static/img/mhwilds/gajau.png
new file mode 100644
index 0000000..e97ab60
Binary files /dev/null and b/website/public/static/img/mhwilds/gajau.png differ
diff --git a/website/public/static/img/mhwilds/gastronome tuna.png b/website/public/static/img/mhwilds/gastronome tuna.png
new file mode 100644
index 0000000..5688a6c
Binary files /dev/null and b/website/public/static/img/mhwilds/gastronome tuna.png differ
diff --git a/website/public/static/img/mhwilds/gawkie.png b/website/public/static/img/mhwilds/gawkie.png
new file mode 100644
index 0000000..f574bdc
Binary files /dev/null and b/website/public/static/img/mhwilds/gawkie.png differ
diff --git a/website/public/static/img/mhwilds/giant vigorwasp.png b/website/public/static/img/mhwilds/giant vigorwasp.png
new file mode 100644
index 0000000..a4ad52a
Binary files /dev/null and b/website/public/static/img/mhwilds/giant vigorwasp.png differ
diff --git a/website/public/static/img/mhwilds/gillopod.png b/website/public/static/img/mhwilds/gillopod.png
new file mode 100644
index 0000000..b906829
Binary files /dev/null and b/website/public/static/img/mhwilds/gillopod.png differ
diff --git a/website/public/static/img/mhwilds/glass parexus.png b/website/public/static/img/mhwilds/glass parexus.png
new file mode 100644
index 0000000..5133d72
Binary files /dev/null and b/website/public/static/img/mhwilds/glass parexus.png differ
diff --git a/website/public/static/img/mhwilds/gloom gekko.png b/website/public/static/img/mhwilds/gloom gekko.png
new file mode 100644
index 0000000..6299b75
Binary files /dev/null and b/website/public/static/img/mhwilds/gloom gekko.png differ
diff --git a/website/public/static/img/mhwilds/godbug.png b/website/public/static/img/mhwilds/godbug.png
new file mode 100644
index 0000000..9da33ee
Binary files /dev/null and b/website/public/static/img/mhwilds/godbug.png differ
diff --git a/website/public/static/img/mhwilds/gogmazios.png b/website/public/static/img/mhwilds/gogmazios.png
new file mode 100644
index 0000000..1e5af82
Binary files /dev/null and b/website/public/static/img/mhwilds/gogmazios.png differ
diff --git a/website/public/static/img/mhwilds/gold hercudrome.png b/website/public/static/img/mhwilds/gold hercudrome.png
new file mode 100644
index 0000000..56faa47
Binary files /dev/null and b/website/public/static/img/mhwilds/gold hercudrome.png differ
diff --git a/website/public/static/img/mhwilds/goldenfish.png b/website/public/static/img/mhwilds/goldenfish.png
new file mode 100644
index 0000000..947d034
Binary files /dev/null and b/website/public/static/img/mhwilds/goldenfish.png differ
diff --git a/website/public/static/img/mhwilds/goldenfry.png b/website/public/static/img/mhwilds/goldenfry.png
new file mode 100644
index 0000000..80440b8
Binary files /dev/null and b/website/public/static/img/mhwilds/goldenfry.png differ
diff --git a/website/public/static/img/mhwilds/goliath squid.png b/website/public/static/img/mhwilds/goliath squid.png
new file mode 100644
index 0000000..993b612
Binary files /dev/null and b/website/public/static/img/mhwilds/goliath squid.png differ
diff --git a/website/public/static/img/mhwilds/gore magala.png b/website/public/static/img/mhwilds/gore magala.png
new file mode 100644
index 0000000..e43cd48
Binary files /dev/null and b/website/public/static/img/mhwilds/gore magala.png differ
diff --git a/website/public/static/img/mhwilds/grand escunite.png b/website/public/static/img/mhwilds/grand escunite.png
new file mode 100644
index 0000000..7e01459
Binary files /dev/null and b/website/public/static/img/mhwilds/grand escunite.png differ
diff --git a/website/public/static/img/mhwilds/gravid bowfin.png b/website/public/static/img/mhwilds/gravid bowfin.png
new file mode 100644
index 0000000..58f4463
Binary files /dev/null and b/website/public/static/img/mhwilds/gravid bowfin.png differ
diff --git a/website/public/static/img/mhwilds/gravios.png b/website/public/static/img/mhwilds/gravios.png
new file mode 100644
index 0000000..4c138a1
Binary files /dev/null and b/website/public/static/img/mhwilds/gravios.png differ
diff --git a/website/public/static/img/mhwilds/great thunderbugs.png b/website/public/static/img/mhwilds/great thunderbugs.png
new file mode 100644
index 0000000..8c8277a
Binary files /dev/null and b/website/public/static/img/mhwilds/great thunderbugs.png differ
diff --git a/website/public/static/img/mhwilds/great trevally.png b/website/public/static/img/mhwilds/great trevally.png
new file mode 100644
index 0000000..8808e1b
Binary files /dev/null and b/website/public/static/img/mhwilds/great trevally.png differ
diff --git a/website/public/static/img/mhwilds/guardian arkveld.png b/website/public/static/img/mhwilds/guardian arkveld.png
new file mode 100644
index 0000000..ab86324
Binary files /dev/null and b/website/public/static/img/mhwilds/guardian arkveld.png differ
diff --git a/website/public/static/img/mhwilds/guardian doshaguma.png b/website/public/static/img/mhwilds/guardian doshaguma.png
new file mode 100644
index 0000000..7d78ac6
Binary files /dev/null and b/website/public/static/img/mhwilds/guardian doshaguma.png differ
diff --git a/website/public/static/img/mhwilds/guardian ebony odogaron.png b/website/public/static/img/mhwilds/guardian ebony odogaron.png
new file mode 100644
index 0000000..412d166
Binary files /dev/null and b/website/public/static/img/mhwilds/guardian ebony odogaron.png differ
diff --git a/website/public/static/img/mhwilds/guardian fulgur anjanath.png b/website/public/static/img/mhwilds/guardian fulgur anjanath.png
new file mode 100644
index 0000000..119572b
Binary files /dev/null and b/website/public/static/img/mhwilds/guardian fulgur anjanath.png differ
diff --git a/website/public/static/img/mhwilds/guardian rathalos.png b/website/public/static/img/mhwilds/guardian rathalos.png
new file mode 100644
index 0000000..53ecf04
Binary files /dev/null and b/website/public/static/img/mhwilds/guardian rathalos.png differ
diff --git a/website/public/static/img/mhwilds/gunpowderfish.png b/website/public/static/img/mhwilds/gunpowderfish.png
new file mode 100644
index 0000000..65ce69a
Binary files /dev/null and b/website/public/static/img/mhwilds/gunpowderfish.png differ
diff --git a/website/public/static/img/mhwilds/gypceros.png b/website/public/static/img/mhwilds/gypceros.png
new file mode 100644
index 0000000..bb1ec6c
Binary files /dev/null and b/website/public/static/img/mhwilds/gypceros.png differ
diff --git a/website/public/static/img/mhwilds/heatmantle bug.png b/website/public/static/img/mhwilds/heatmantle bug.png
new file mode 100644
index 0000000..fee8ed8
Binary files /dev/null and b/website/public/static/img/mhwilds/heatmantle bug.png differ
diff --git a/website/public/static/img/mhwilds/hercudrome.png b/website/public/static/img/mhwilds/hercudrome.png
new file mode 100644
index 0000000..21d5043
Binary files /dev/null and b/website/public/static/img/mhwilds/hercudrome.png differ
diff --git a/website/public/static/img/mhwilds/hirabami.png b/website/public/static/img/mhwilds/hirabami.png
new file mode 100644
index 0000000..39921fd
Binary files /dev/null and b/website/public/static/img/mhwilds/hirabami.png differ
diff --git a/website/public/static/img/mhwilds/hp penalty.png b/website/public/static/img/mhwilds/hp penalty.png
new file mode 100644
index 0000000..8f96a10
Binary files /dev/null and b/website/public/static/img/mhwilds/hp penalty.png differ
diff --git a/website/public/static/img/mhwilds/hymstrigian.png b/website/public/static/img/mhwilds/hymstrigian.png
new file mode 100644
index 0000000..0c71509
Binary files /dev/null and b/website/public/static/img/mhwilds/hymstrigian.png differ
diff --git a/website/public/static/img/mhwilds/ice.png b/website/public/static/img/mhwilds/ice.png
new file mode 100644
index 0000000..bc82dfe
Binary files /dev/null and b/website/public/static/img/mhwilds/ice.png differ
diff --git a/website/public/static/img/mhwilds/iceblight.png b/website/public/static/img/mhwilds/iceblight.png
new file mode 100644
index 0000000..bc82dfe
Binary files /dev/null and b/website/public/static/img/mhwilds/iceblight.png differ
diff --git a/website/public/static/img/mhwilds/iceshard cliffs.png b/website/public/static/img/mhwilds/iceshard cliffs.png
new file mode 100644
index 0000000..edf4640
Binary files /dev/null and b/website/public/static/img/mhwilds/iceshard cliffs.png differ
diff --git a/website/public/static/img/mhwilds/jewel scarab.png b/website/public/static/img/mhwilds/jewel scarab.png
new file mode 100644
index 0000000..d24ab85
Binary files /dev/null and b/website/public/static/img/mhwilds/jewel scarab.png differ
diff --git a/website/public/static/img/mhwilds/jin dahaad.png b/website/public/static/img/mhwilds/jin dahaad.png
new file mode 100644
index 0000000..9e72088
Binary files /dev/null and b/website/public/static/img/mhwilds/jin dahaad.png differ
diff --git a/website/public/static/img/mhwilds/lagiacrus.png b/website/public/static/img/mhwilds/lagiacrus.png
new file mode 100644
index 0000000..a63f4dd
Binary files /dev/null and b/website/public/static/img/mhwilds/lagiacrus.png differ
diff --git a/website/public/static/img/mhwilds/lala barina.png b/website/public/static/img/mhwilds/lala barina.png
new file mode 100644
index 0000000..0dcf326
Binary files /dev/null and b/website/public/static/img/mhwilds/lala barina.png differ
diff --git a/website/public/static/img/mhwilds/landlight shrimp.png b/website/public/static/img/mhwilds/landlight shrimp.png
new file mode 100644
index 0000000..072dade
Binary files /dev/null and b/website/public/static/img/mhwilds/landlight shrimp.png differ
diff --git a/website/public/static/img/mhwilds/leaflugger ant.png b/website/public/static/img/mhwilds/leaflugger ant.png
new file mode 100644
index 0000000..5a9409d
Binary files /dev/null and b/website/public/static/img/mhwilds/leaflugger ant.png differ
diff --git a/website/public/static/img/mhwilds/mimiphyta.png b/website/public/static/img/mhwilds/mimiphyta.png
new file mode 100644
index 0000000..0a4400a
Binary files /dev/null and b/website/public/static/img/mhwilds/mimiphyta.png differ
diff --git a/website/public/static/img/mhwilds/minor tremor.png b/website/public/static/img/mhwilds/minor tremor.png
new file mode 100644
index 0000000..3356091
Binary files /dev/null and b/website/public/static/img/mhwilds/minor tremor.png differ
diff --git a/website/public/static/img/mhwilds/minor wind pressure.png b/website/public/static/img/mhwilds/minor wind pressure.png
new file mode 100644
index 0000000..9bee2e7
Binary files /dev/null and b/website/public/static/img/mhwilds/minor wind pressure.png differ
diff --git a/website/public/static/img/mhwilds/mizutsune.png b/website/public/static/img/mhwilds/mizutsune.png
new file mode 100644
index 0000000..b36b2f9
Binary files /dev/null and b/website/public/static/img/mhwilds/mizutsune.png differ
diff --git a/website/public/static/img/mhwilds/myriads.png b/website/public/static/img/mhwilds/myriads.png
new file mode 100644
index 0000000..032c832
Binary files /dev/null and b/website/public/static/img/mhwilds/myriads.png differ
diff --git a/website/public/static/img/mhwilds/nerscylla.png b/website/public/static/img/mhwilds/nerscylla.png
new file mode 100644
index 0000000..06f16da
Binary files /dev/null and b/website/public/static/img/mhwilds/nerscylla.png differ
diff --git a/website/public/static/img/mhwilds/neutral.png b/website/public/static/img/mhwilds/neutral.png
new file mode 100644
index 0000000..09df12e
Binary files /dev/null and b/website/public/static/img/mhwilds/neutral.png differ
diff --git a/website/public/static/img/mhwilds/nitrotoad.png b/website/public/static/img/mhwilds/nitrotoad.png
new file mode 100644
index 0000000..18ee96b
Binary files /dev/null and b/website/public/static/img/mhwilds/nitrotoad.png differ
diff --git a/website/public/static/img/mhwilds/nothpecker.png b/website/public/static/img/mhwilds/nothpecker.png
new file mode 100644
index 0000000..369ed7f
Binary files /dev/null and b/website/public/static/img/mhwilds/nothpecker.png differ
diff --git a/website/public/static/img/mhwilds/nu udra.png b/website/public/static/img/mhwilds/nu udra.png
new file mode 100644
index 0000000..44ffc55
Binary files /dev/null and b/website/public/static/img/mhwilds/nu udra.png differ
diff --git a/website/public/static/img/mhwilds/nu yaya.png b/website/public/static/img/mhwilds/nu yaya.png
new file mode 100644
index 0000000..928bc4f
Binary files /dev/null and b/website/public/static/img/mhwilds/nu yaya.png differ
diff --git a/website/public/static/img/mhwilds/oilwell basin.png b/website/public/static/img/mhwilds/oilwell basin.png
new file mode 100644
index 0000000..173111e
Binary files /dev/null and b/website/public/static/img/mhwilds/oilwell basin.png differ
diff --git a/website/public/static/img/mhwilds/omega planetes.png b/website/public/static/img/mhwilds/omega planetes.png
new file mode 100644
index 0000000..6b857ed
Binary files /dev/null and b/website/public/static/img/mhwilds/omega planetes.png differ
diff --git a/website/public/static/img/mhwilds/omenfly.png b/website/public/static/img/mhwilds/omenfly.png
new file mode 100644
index 0000000..e4a9c24
Binary files /dev/null and b/website/public/static/img/mhwilds/omenfly.png differ
diff --git a/website/public/static/img/mhwilds/pallbug.png b/website/public/static/img/mhwilds/pallbug.png
new file mode 100644
index 0000000..2561cbe
Binary files /dev/null and b/website/public/static/img/mhwilds/pallbug.png differ
diff --git a/website/public/static/img/mhwilds/paralysis.png b/website/public/static/img/mhwilds/paralysis.png
new file mode 100644
index 0000000..cb424c1
Binary files /dev/null and b/website/public/static/img/mhwilds/paralysis.png differ
diff --git a/website/public/static/img/mhwilds/paratoad.png b/website/public/static/img/mhwilds/paratoad.png
new file mode 100644
index 0000000..dcdf5a7
Binary files /dev/null and b/website/public/static/img/mhwilds/paratoad.png differ
diff --git a/website/public/static/img/mhwilds/peony sparklerjelly.png b/website/public/static/img/mhwilds/peony sparklerjelly.png
new file mode 100644
index 0000000..be882ae
Binary files /dev/null and b/website/public/static/img/mhwilds/peony sparklerjelly.png differ
diff --git a/website/public/static/img/mhwilds/petalfly.png b/website/public/static/img/mhwilds/petalfly.png
new file mode 100644
index 0000000..7d29cbc
Binary files /dev/null and b/website/public/static/img/mhwilds/petalfly.png differ
diff --git a/website/public/static/img/mhwilds/pillopod.png b/website/public/static/img/mhwilds/pillopod.png
new file mode 100644
index 0000000..a2389a6
Binary files /dev/null and b/website/public/static/img/mhwilds/pillopod.png differ
diff --git a/website/public/static/img/mhwilds/pink landlight shrimp.png b/website/public/static/img/mhwilds/pink landlight shrimp.png
new file mode 100644
index 0000000..b06cb7e
Binary files /dev/null and b/website/public/static/img/mhwilds/pink landlight shrimp.png differ
diff --git a/website/public/static/img/mhwilds/platinumfish.png b/website/public/static/img/mhwilds/platinumfish.png
new file mode 100644
index 0000000..c43fd4a
Binary files /dev/null and b/website/public/static/img/mhwilds/platinumfish.png differ
diff --git a/website/public/static/img/mhwilds/poison.png b/website/public/static/img/mhwilds/poison.png
new file mode 100644
index 0000000..aef6039
Binary files /dev/null and b/website/public/static/img/mhwilds/poison.png differ
diff --git a/website/public/static/img/mhwilds/prism hercudrome.png b/website/public/static/img/mhwilds/prism hercudrome.png
new file mode 100644
index 0000000..0adeafc
Binary files /dev/null and b/website/public/static/img/mhwilds/prism hercudrome.png differ
diff --git a/website/public/static/img/mhwilds/purewasp.png b/website/public/static/img/mhwilds/purewasp.png
new file mode 100644
index 0000000..a2710fc
Binary files /dev/null and b/website/public/static/img/mhwilds/purewasp.png differ
diff --git a/website/public/static/img/mhwilds/quatreflies.png b/website/public/static/img/mhwilds/quatreflies.png
new file mode 100644
index 0000000..b25e0b7
Binary files /dev/null and b/website/public/static/img/mhwilds/quatreflies.png differ
diff --git a/website/public/static/img/mhwilds/quematrice.png b/website/public/static/img/mhwilds/quematrice.png
new file mode 100644
index 0000000..ecdbae9
Binary files /dev/null and b/website/public/static/img/mhwilds/quematrice.png differ
diff --git a/website/public/static/img/mhwilds/rathalos.png b/website/public/static/img/mhwilds/rathalos.png
new file mode 100644
index 0000000..2b71bdf
Binary files /dev/null and b/website/public/static/img/mhwilds/rathalos.png differ
diff --git a/website/public/static/img/mhwilds/rathian.png b/website/public/static/img/mhwilds/rathian.png
new file mode 100644
index 0000000..1bfef8d
Binary files /dev/null and b/website/public/static/img/mhwilds/rathian.png differ
diff --git a/website/public/static/img/mhwilds/regal jewel scarab.png b/website/public/static/img/mhwilds/regal jewel scarab.png
new file mode 100644
index 0000000..1febdc2
Binary files /dev/null and b/website/public/static/img/mhwilds/regal jewel scarab.png differ
diff --git a/website/public/static/img/mhwilds/rey dau.png b/website/public/static/img/mhwilds/rey dau.png
new file mode 100644
index 0000000..983784f
Binary files /dev/null and b/website/public/static/img/mhwilds/rey dau.png differ
diff --git a/website/public/static/img/mhwilds/rime beetle.png b/website/public/static/img/mhwilds/rime beetle.png
new file mode 100644
index 0000000..9d38e15
Binary files /dev/null and b/website/public/static/img/mhwilds/rime beetle.png differ
diff --git a/website/public/static/img/mhwilds/rompopolo.png b/website/public/static/img/mhwilds/rompopolo.png
new file mode 100644
index 0000000..24f1b6c
Binary files /dev/null and b/website/public/static/img/mhwilds/rompopolo.png differ
diff --git a/website/public/static/img/mhwilds/rufflizard.png b/website/public/static/img/mhwilds/rufflizard.png
new file mode 100644
index 0000000..996f485
Binary files /dev/null and b/website/public/static/img/mhwilds/rufflizard.png differ
diff --git a/website/public/static/img/mhwilds/ruins of wyveria.png b/website/public/static/img/mhwilds/ruins of wyveria.png
new file mode 100644
index 0000000..3ba6598
Binary files /dev/null and b/website/public/static/img/mhwilds/ruins of wyveria.png differ
diff --git a/website/public/static/img/mhwilds/sandstar.png b/website/public/static/img/mhwilds/sandstar.png
new file mode 100644
index 0000000..280ae0f
Binary files /dev/null and b/website/public/static/img/mhwilds/sandstar.png differ
diff --git a/website/public/static/img/mhwilds/scalebat.png b/website/public/static/img/mhwilds/scalebat.png
new file mode 100644
index 0000000..3821d9b
Binary files /dev/null and b/website/public/static/img/mhwilds/scalebat.png differ
diff --git a/website/public/static/img/mhwilds/scarlet forest.png b/website/public/static/img/mhwilds/scarlet forest.png
new file mode 100644
index 0000000..996ddc3
Binary files /dev/null and b/website/public/static/img/mhwilds/scarlet forest.png differ
diff --git a/website/public/static/img/mhwilds/scarlet joyperch.png b/website/public/static/img/mhwilds/scarlet joyperch.png
new file mode 100644
index 0000000..4fdd946
Binary files /dev/null and b/website/public/static/img/mhwilds/scarlet joyperch.png differ
diff --git a/website/public/static/img/mhwilds/seregios.png b/website/public/static/img/mhwilds/seregios.png
new file mode 100644
index 0000000..eef3fad
Binary files /dev/null and b/website/public/static/img/mhwilds/seregios.png differ
diff --git a/website/public/static/img/mhwilds/sleep.png b/website/public/static/img/mhwilds/sleep.png
new file mode 100644
index 0000000..bf363b2
Binary files /dev/null and b/website/public/static/img/mhwilds/sleep.png differ
diff --git a/website/public/static/img/mhwilds/sleeptoad.png b/website/public/static/img/mhwilds/sleeptoad.png
new file mode 100644
index 0000000..c8e77e2
Binary files /dev/null and b/website/public/static/img/mhwilds/sleeptoad.png differ
diff --git a/website/public/static/img/mhwilds/smokeshroud gekko.png b/website/public/static/img/mhwilds/smokeshroud gekko.png
new file mode 100644
index 0000000..5b1db43
Binary files /dev/null and b/website/public/static/img/mhwilds/smokeshroud gekko.png differ
diff --git a/website/public/static/img/mhwilds/solanaria.png b/website/public/static/img/mhwilds/solanaria.png
new file mode 100644
index 0000000..db0c6bf
Binary files /dev/null and b/website/public/static/img/mhwilds/solanaria.png differ
diff --git a/website/public/static/img/mhwilds/sparklerjelly.png b/website/public/static/img/mhwilds/sparklerjelly.png
new file mode 100644
index 0000000..3c68659
Binary files /dev/null and b/website/public/static/img/mhwilds/sparklerjelly.png differ
diff --git a/website/public/static/img/mhwilds/speartuna.png b/website/public/static/img/mhwilds/speartuna.png
new file mode 100644
index 0000000..276e99e
Binary files /dev/null and b/website/public/static/img/mhwilds/speartuna.png differ
diff --git a/website/public/static/img/mhwilds/starduster.png b/website/public/static/img/mhwilds/starduster.png
new file mode 100644
index 0000000..62bf3e8
Binary files /dev/null and b/website/public/static/img/mhwilds/starduster.png differ
diff --git a/website/public/static/img/mhwilds/stench.png b/website/public/static/img/mhwilds/stench.png
new file mode 100644
index 0000000..eeb9c9f
Binary files /dev/null and b/website/public/static/img/mhwilds/stench.png differ
diff --git a/website/public/static/img/mhwilds/strong roar.png b/website/public/static/img/mhwilds/strong roar.png
new file mode 100644
index 0000000..4b81586
Binary files /dev/null and b/website/public/static/img/mhwilds/strong roar.png differ
diff --git a/website/public/static/img/mhwilds/stun.png b/website/public/static/img/mhwilds/stun.png
new file mode 100644
index 0000000..1b5d483
Binary files /dev/null and b/website/public/static/img/mhwilds/stun.png differ
diff --git a/website/public/static/img/mhwilds/sushifish.png b/website/public/static/img/mhwilds/sushifish.png
new file mode 100644
index 0000000..bd59deb
Binary files /dev/null and b/website/public/static/img/mhwilds/sushifish.png differ
diff --git a/website/public/static/img/mhwilds/thunder.png b/website/public/static/img/mhwilds/thunder.png
new file mode 100644
index 0000000..6193a6b
Binary files /dev/null and b/website/public/static/img/mhwilds/thunder.png differ
diff --git a/website/public/static/img/mhwilds/thunderblight.png b/website/public/static/img/mhwilds/thunderblight.png
new file mode 100644
index 0000000..6193a6b
Binary files /dev/null and b/website/public/static/img/mhwilds/thunderblight.png differ
diff --git a/website/public/static/img/mhwilds/thunderbug.png b/website/public/static/img/mhwilds/thunderbug.png
new file mode 100644
index 0000000..0b1cef1
Binary files /dev/null and b/website/public/static/img/mhwilds/thunderbug.png differ
diff --git a/website/public/static/img/mhwilds/tracktail lizard.png b/website/public/static/img/mhwilds/tracktail lizard.png
new file mode 100644
index 0000000..7e377ac
Binary files /dev/null and b/website/public/static/img/mhwilds/tracktail lizard.png differ
diff --git a/website/public/static/img/mhwilds/tyrant hopper.png b/website/public/static/img/mhwilds/tyrant hopper.png
new file mode 100644
index 0000000..789c853
Binary files /dev/null and b/website/public/static/img/mhwilds/tyrant hopper.png differ
diff --git a/website/public/static/img/mhwilds/unknown.png b/website/public/static/img/mhwilds/unknown.png
new file mode 100644
index 0000000..f2d789f
Binary files /dev/null and b/website/public/static/img/mhwilds/unknown.png differ
diff --git a/website/public/static/img/mhwilds/uth duna.png b/website/public/static/img/mhwilds/uth duna.png
new file mode 100644
index 0000000..83038ac
Binary files /dev/null and b/website/public/static/img/mhwilds/uth duna.png differ
diff --git a/website/public/static/img/mhwilds/vaporonid.png b/website/public/static/img/mhwilds/vaporonid.png
new file mode 100644
index 0000000..6ea7fb3
Binary files /dev/null and b/website/public/static/img/mhwilds/vaporonid.png differ
diff --git a/website/public/static/img/mhwilds/vigormantle bug.png b/website/public/static/img/mhwilds/vigormantle bug.png
new file mode 100644
index 0000000..d87c849
Binary files /dev/null and b/website/public/static/img/mhwilds/vigormantle bug.png differ
diff --git a/website/public/static/img/mhwilds/vigorwasp.png b/website/public/static/img/mhwilds/vigorwasp.png
new file mode 100644
index 0000000..c9944c4
Binary files /dev/null and b/website/public/static/img/mhwilds/vigorwasp.png differ
diff --git a/website/public/static/img/mhwilds/virid bowfin.png b/website/public/static/img/mhwilds/virid bowfin.png
new file mode 100644
index 0000000..6db6cf6
Binary files /dev/null and b/website/public/static/img/mhwilds/virid bowfin.png differ
diff --git a/website/public/static/img/mhwilds/water.png b/website/public/static/img/mhwilds/water.png
new file mode 100644
index 0000000..71fe658
Binary files /dev/null and b/website/public/static/img/mhwilds/water.png differ
diff --git a/website/public/static/img/mhwilds/waterblight.png b/website/public/static/img/mhwilds/waterblight.png
new file mode 100644
index 0000000..71fe658
Binary files /dev/null and b/website/public/static/img/mhwilds/waterblight.png differ
diff --git a/website/public/static/img/mhwilds/weak roar.png b/website/public/static/img/mhwilds/weak roar.png
new file mode 100644
index 0000000..ec6f398
Binary files /dev/null and b/website/public/static/img/mhwilds/weak roar.png differ
diff --git a/website/public/static/img/mhwilds/webbed.png b/website/public/static/img/mhwilds/webbed.png
new file mode 100644
index 0000000..3d6972e
Binary files /dev/null and b/website/public/static/img/mhwilds/webbed.png differ
diff --git a/website/public/static/img/mhwilds/wedge beetle.png b/website/public/static/img/mhwilds/wedge beetle.png
new file mode 100644
index 0000000..336b7a9
Binary files /dev/null and b/website/public/static/img/mhwilds/wedge beetle.png differ
diff --git a/website/public/static/img/mhwilds/whetfish.png b/website/public/static/img/mhwilds/whetfish.png
new file mode 100644
index 0000000..f2a9c7f
Binary files /dev/null and b/website/public/static/img/mhwilds/whetfish.png differ
diff --git a/website/public/static/img/mhwilds/wiggly litchi.png b/website/public/static/img/mhwilds/wiggly litchi.png
new file mode 100644
index 0000000..9ddf9fa
Binary files /dev/null and b/website/public/static/img/mhwilds/wiggly litchi.png differ
diff --git a/website/public/static/img/mhwilds/windrustler.png b/website/public/static/img/mhwilds/windrustler.png
new file mode 100644
index 0000000..a475696
Binary files /dev/null and b/website/public/static/img/mhwilds/windrustler.png differ
diff --git a/website/public/static/img/mhwilds/windward plains.png b/website/public/static/img/mhwilds/windward plains.png
new file mode 100644
index 0000000..723e24f
Binary files /dev/null and b/website/public/static/img/mhwilds/windward plains.png differ
diff --git a/website/public/static/img/mhwilds/xu wu.png b/website/public/static/img/mhwilds/xu wu.png
new file mode 100644
index 0000000..253fa47
Binary files /dev/null and b/website/public/static/img/mhwilds/xu wu.png differ
diff --git a/website/public/static/img/mhwilds/xu yo.png b/website/public/static/img/mhwilds/xu yo.png
new file mode 100644
index 0000000..81b75bb
Binary files /dev/null and b/website/public/static/img/mhwilds/xu yo.png differ
diff --git a/website/public/static/img/mhwilds/yian kut-ku.png b/website/public/static/img/mhwilds/yian kut-ku.png
new file mode 100644
index 0000000..eda14f5
Binary files /dev/null and b/website/public/static/img/mhwilds/yian kut-ku.png differ
diff --git a/website/public/static/img/mhwilds/zoh shia.png b/website/public/static/img/mhwilds/zoh shia.png
new file mode 100644
index 0000000..10f226e
Binary files /dev/null and b/website/public/static/img/mhwilds/zoh shia.png differ
diff --git a/website/public/static/img/toolbox-icons/controller.svg b/website/public/static/img/toolbox-icons/controller.svg
new file mode 100644
index 0000000..de7a7aa
--- /dev/null
+++ b/website/public/static/img/toolbox-icons/controller.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/website/public/static/img/toolbox-icons/default.svg b/website/public/static/img/toolbox-icons/default.svg
new file mode 100644
index 0000000..5b6da01
--- /dev/null
+++ b/website/public/static/img/toolbox-icons/default.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/website/public/static/img/toolbox-icons/quest.svg b/website/public/static/img/toolbox-icons/quest.svg
new file mode 100644
index 0000000..e11806c
--- /dev/null
+++ b/website/public/static/img/toolbox-icons/quest.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/website/public/static/img/toolbox-icons/target.svg b/website/public/static/img/toolbox-icons/target.svg
new file mode 100644
index 0000000..40f378f
--- /dev/null
+++ b/website/public/static/img/toolbox-icons/target.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/website/src/app.js b/website/src/app.js
new file mode 100644
index 0000000..1f282b3
--- /dev/null
+++ b/website/src/app.js
@@ -0,0 +1,2300 @@
+const STORAGE_KEYS = {
+ registry: "sokkog:toolboxes",
+ links: "sokkog:game-toolbox-links",
+ drawerWidth: "sokkog:drawer-width"
+};
+const APP_STORAGE_PREFIX = "sokkog:";
+const APP_STORAGE_LIMIT_BYTES = 5 * 1024 * 1024;
+const APP_STORAGE_WARNING_RATIO = 0.85;
+
+const MODULES = {
+ notepad: { label: "Bloc notes", icon: "notepad" },
+ checklist: { label: "Checklist", icon: "checklist" },
+ screenshots: { label: "Screenshots", icon: "picture" }
+};
+
+const DEFAULT_SITE_CONTENT = {
+ brand: { name: "Sokko G", homeAriaLabel: "Accueil Sokko G" },
+ navigation: { home: "Accueil", toolboxes: "Toolboxes", games: "Pages jeux", mobileGames: "Infos" },
+ sidebar: { badge: "Local only", note: "Données stockées dans ce navigateur." },
+ topbar: { dashboard: "Dashboard", toolbox: "Toolbox active", games: "Informations jeu" },
+ home: {
+ hero: {
+ eyebrow: "Session gaming efficace",
+ title: "Sokko G",
+ description: "Centralisez vos outils et repères de jeu dans une interface locale, rapide à consulter, pensée pour accompagner vos sessions sans interrompre l’action.",
+ primaryAction: "Voir les toolboxes",
+ secondaryAction: "Voir les jeux"
+ },
+ stats: {
+ toolboxSingular: "toolbox créée",
+ toolboxPlural: "toolboxs créées",
+ toolSingular: "outil disponible",
+ toolPlural: "outils disponibles"
+ },
+ origin: {
+ eyebrow: "Origine du nom",
+ title: "Pourquoi Sokko G ?",
+ visualAlt: "Dragon Sokko G",
+ dialogueAriaLabel: "Dialogue d’origine du nom Sokko G",
+ caption: "\"G\" c'est pour Gaming",
+ lines: []
+ }
+ },
+ toolboxes: {
+ eyebrow: "Données locales",
+ title: "Toolboxes",
+ newButton: "Nouvelle toolbox",
+ importAll: "Importer tout",
+ exportAll: "Exporter tout",
+ importOne: "Importer une toolbox",
+ storageHelp: {
+ title: "Sauvegardes locales",
+ text: "Vos toolboxes restent sur cet appareil, dans ce navigateur. Rien n’est envoyé sur un serveur.",
+ items: [
+ "Un nettoyage du navigateur ou un changement d’appareil peut supprimer les données.",
+ "Surveillez le quota, surtout si vous ajoutez des screenshots.",
+ "Faites un export global régulier pour garder une sauvegarde."
+ ]
+ },
+ emptyTitle: "Aucune toolbox",
+ emptyText: "Créez une première toolbox pour stocker vos outils dans ce navigateur."
+ }
+};
+
+const app = document.querySelector("#app");
+const MHWILDS_IMG_PATH = "/static/img/mhwilds";
+const siteState = {
+ loaded: false,
+ loading: false,
+ content: DEFAULT_SITE_CONTENT
+};
+const gamesState = {
+ loaded: false,
+ loading: false,
+ error: "",
+ games: []
+};
+const mhwildsState = {
+ loaded: false,
+ loading: false,
+ error: "",
+ translations: {},
+ monsters: [],
+ endemic: [],
+ filters: {
+ monsters: { name: "", weaknesses: [], logic: "and" },
+ endemic: { name: "", locations: [], logic: "and" }
+ }
+};
+let draggedModule = null;
+
+const ID_PREFIXES = {
+ tbx: "t",
+ mod: "m",
+ item: "i",
+ shot: "s"
+};
+const ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+function randomToken(length = 6) {
+ const bytes = new Uint8Array(length);
+ if (globalThis.crypto?.getRandomValues) {
+ globalThis.crypto.getRandomValues(bytes);
+ return [...bytes].map((byte) => ID_ALPHABET[byte % ID_ALPHABET.length]).join("");
+ }
+
+ return Math.random().toString(36).slice(2, 2 + length).padEnd(length, "0");
+}
+
+function uid(prefix) {
+ return `${ID_PREFIXES[prefix] || "x"}${randomToken()}`;
+}
+
+function readJson(key, fallback) {
+ try {
+ const value = localStorage.getItem(key);
+ return value ? JSON.parse(value) : fallback;
+ } catch {
+ return fallback;
+ }
+}
+
+function writeJson(key, value) {
+ return writeStorageValue(key, JSON.stringify(value));
+}
+
+function stringStorageBytes(value) {
+ return String(value || "").length * 2;
+}
+
+function getAppStorageUsage(projected = {}) {
+ let used = 0;
+ for (let index = 0; index < localStorage.length; index += 1) {
+ const key = localStorage.key(index);
+ if (!key?.startsWith(APP_STORAGE_PREFIX) || Object.prototype.hasOwnProperty.call(projected, key)) continue;
+ used += stringStorageBytes(key) + stringStorageBytes(localStorage.getItem(key));
+ }
+
+ Object.entries(projected).forEach(([key, value]) => {
+ if (!key.startsWith(APP_STORAGE_PREFIX) || value == null) return;
+ used += stringStorageBytes(key) + stringStorageBytes(value);
+ });
+
+ return {
+ used,
+ limit: APP_STORAGE_LIMIT_BYTES,
+ ratio: Math.min(1, used / APP_STORAGE_LIMIT_BYTES)
+ };
+}
+
+function formatBytes(bytes) {
+ if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1).replace(".", ",")} Mio`;
+ if (bytes >= 1024) return `${Math.ceil(bytes / 1024)} Kio`;
+ return `${bytes} o`;
+}
+
+function renderStorageQuota() {
+ const usage = getAppStorageUsage();
+ const percent = Math.round(usage.ratio * 100);
+ const state = usage.ratio >= 1 ? "danger" : usage.ratio >= APP_STORAGE_WARNING_RATIO ? "warning" : "ok";
+
+ return `
+
+
+ Stockage local
+ ${formatBytes(usage.used)} / ${formatBytes(usage.limit)}
+
+
+
+
+
+ `;
+}
+
+function refreshStorageQuotaIndicators() {
+ document.querySelectorAll(".storage-quota").forEach((quota) => {
+ quota.outerHTML = renderStorageQuota();
+ });
+}
+
+function showStorageQuotaModal(usage) {
+ if (document.querySelector(".storage-quota-modal")) return;
+ queueMicrotask(() => {
+ showConfirmModal({
+ title: "Quota local atteint",
+ message: `Sokko G utilise ${formatBytes(usage.used)} sur ${formatBytes(usage.limit)}. Supprimez des outils, des screenshots ou des toolboxes avant d'ajouter de nouvelles données.`,
+ confirmLabel: "Compris",
+ cancelLabel: "Fermer",
+ danger: true,
+ className: "storage-quota-modal"
+ });
+ });
+}
+
+function writeStorageValue(key, value) {
+ const projectedUsage = getAppStorageUsage({ [key]: value });
+ if (projectedUsage.used > APP_STORAGE_LIMIT_BYTES) {
+ showStorageQuotaModal(projectedUsage);
+ return false;
+ }
+
+ try {
+ localStorage.setItem(key, value);
+ if (key !== STORAGE_KEYS.drawerWidth) refreshStorageQuotaIndicators();
+ return true;
+ } catch (error) {
+ if (error?.name === "QuotaExceededError" || error?.code === 22) {
+ showStorageQuotaModal(projectedUsage);
+ return false;
+ }
+ throw error;
+ }
+}
+
+function getDefaultModuleTitle(type) {
+ return MODULES[type]?.label || "Outil";
+}
+
+function normalizeToolboxModule(module) {
+ if (!module || typeof module !== "object" || !module.type) return null;
+ const title = String(module.title || "").trim();
+ const normalized = {
+ id: module.id || uid("mod"),
+ type: module.type
+ };
+
+ if (title && title !== getDefaultModuleTitle(module.type)) {
+ normalized.title = title;
+ }
+
+ return normalized;
+}
+
+function normalizeToolbox(toolbox) {
+ if (!toolbox || typeof toolbox !== "object") return null;
+ return {
+ id: toolbox.id || uid("tbx"),
+ name: String(toolbox.name || "Nouvelle toolbox").trim() || "Nouvelle toolbox",
+ moduleColumns: Number(toolbox.moduleColumns) === 1 ? 1 : 2,
+ modules: (Array.isArray(toolbox.modules) ? toolbox.modules : []).map(normalizeToolboxModule).filter(Boolean),
+ updatedAt: toolbox.updatedAt || new Date().toISOString()
+ };
+}
+
+function normalizeToolboxes(toolboxes) {
+ return (Array.isArray(toolboxes) ? toolboxes : []).map(normalizeToolbox).filter(Boolean);
+}
+
+function compactToolboxForStorage(toolbox) {
+ const normalized = normalizeToolbox(toolbox);
+ if (!normalized) return null;
+
+ const compact = {
+ id: normalized.id,
+ name: normalized.name,
+ modules: normalized.modules,
+ updatedAt: normalized.updatedAt
+ };
+
+ if (normalized.moduleColumns === 1) compact.moduleColumns = 1;
+
+ return compact;
+}
+
+function compactToolboxesForStorage(toolboxes) {
+ return (Array.isArray(toolboxes) ? toolboxes : []).map(compactToolboxForStorage).filter(Boolean);
+}
+
+function getToolboxes() {
+ return normalizeToolboxes(readJson(STORAGE_KEYS.registry, []));
+}
+
+function saveToolboxes(toolboxes) {
+ return writeJson(STORAGE_KEYS.registry, compactToolboxesForStorage(toolboxes));
+}
+
+function getLinks() {
+ return readJson(STORAGE_KEYS.links, {});
+}
+
+function saveLinks(links) {
+ return writeJson(STORAGE_KEYS.links, links);
+}
+
+function moduleStorageKey(toolboxId, moduleId) {
+ return `sokkog:toolbox:${toolboxId}:module:${moduleId}`;
+}
+
+function globalModuleKey(toolboxId, moduleId) {
+ return `${toolboxId}:${moduleId}`;
+}
+
+function downloadJson(payload, filename) {
+ const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" });
+ const link = document.createElement("a");
+ link.href = URL.createObjectURL(blob);
+ link.download = filename;
+ link.click();
+ URL.revokeObjectURL(link.href);
+}
+
+function getModuleData(toolboxId, moduleId, fallback) {
+ const value = readJson(moduleStorageKey(toolboxId, moduleId), undefined);
+ return value == null ? fallback : value;
+}
+
+function getToolboxModule(toolboxId, moduleId) {
+ return getToolboxes()
+ .find((toolbox) => toolbox.id === toolboxId)
+ ?.modules.find((module) => module.id === moduleId);
+}
+
+function compactChecklistItemForStorage(item) {
+ const normalized = normalizeChecklistItem(item);
+ const compact = {
+ id: normalized.id,
+ label: normalized.label
+ };
+
+ if (normalized.qtyTarget !== 1) compact.qtyTarget = normalized.qtyTarget;
+ if (normalized.qtyCurrent !== 0) compact.qtyCurrent = normalized.qtyCurrent;
+
+ return compact;
+}
+
+function compactModuleDataForStorage(type, value) {
+ if (type === "notepad") {
+ const text = String(value?.text || "");
+ return text ? { text } : null;
+ }
+
+ if (type === "checklist") {
+ const items = normalizeChecklistData(value).items.map(compactChecklistItemForStorage);
+ return items.length ? { items } : null;
+ }
+
+ if (type === "screenshots") {
+ const shots = (Array.isArray(value?.shots) ? value.shots : [])
+ .filter((shot) => shot?.dataUrl)
+ .map((shot) => ({
+ id: shot.id || uid("shot"),
+ dataUrl: shot.dataUrl
+ }));
+ return shots.length ? { shots } : null;
+ }
+
+ return value;
+}
+
+function createExportIdFactory() {
+ const counts = {};
+ return (prefix) => {
+ counts[prefix] = (counts[prefix] || 0) + 1;
+ return `${ID_PREFIXES[prefix] || "x"}${counts[prefix].toString(36)}`;
+ };
+}
+
+function remapModuleDataForExport(type, data, nextId) {
+ const compact = compactModuleDataForStorage(type, data);
+ if (!compact) return null;
+
+ if (type === "checklist") {
+ return {
+ items: compact.items.map((item) => ({
+ ...item,
+ id: nextId("item")
+ }))
+ };
+ }
+
+ if (type === "screenshots") {
+ return {
+ shots: compact.shots.map((shot) => ({
+ ...shot,
+ id: nextId("shot")
+ }))
+ };
+ }
+
+ return compact;
+}
+
+function createToolboxExportPayload(toolbox) {
+ const source = normalizeToolbox(toolbox);
+ const nextId = createExportIdFactory();
+ const moduleIdMap = new Map();
+ const exportedToolbox = compactToolboxForStorage({
+ ...source,
+ id: nextId("tbx"),
+ modules: source.modules.map((module) => {
+ const id = nextId("mod");
+ moduleIdMap.set(module.id, id);
+ return { ...module, id };
+ })
+ });
+ const modules = Object.fromEntries(source.modules
+ .map((module) => [
+ moduleIdMap.get(module.id),
+ remapModuleDataForExport(module.type, getModuleData(source.id, module.id, null), nextId)
+ ])
+ .filter(([, data]) => data != null));
+
+ return { toolbox: exportedToolbox, modules };
+}
+
+function createGlobalExportPayload() {
+ const toolboxes = getToolboxes();
+ const modules = {};
+
+ toolboxes.forEach((toolbox) => {
+ toolbox.modules.forEach((module) => {
+ const data = compactModuleDataForStorage(module.type, getModuleData(toolbox.id, module.id, null));
+ if (data) modules[globalModuleKey(toolbox.id, module.id)] = data;
+ });
+ });
+
+ return {
+ version: 1,
+ exportedAt: new Date().toISOString(),
+ toolboxes: compactToolboxesForStorage(toolboxes),
+ modules,
+ links: getLinks()
+ };
+}
+
+function setModuleData(toolboxId, moduleId, value) {
+ const module = getToolboxModule(toolboxId, moduleId);
+ const compact = compactModuleDataForStorage(module?.type, value);
+ const key = moduleStorageKey(toolboxId, moduleId);
+
+ if (compact == null) {
+ localStorage.removeItem(key);
+ refreshStorageQuotaIndicators();
+ return true;
+ }
+
+ return writeJson(key, compact);
+}
+
+function parsePositiveInt(value, fallback = 1) {
+ const parsed = Number.parseInt(value, 10);
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
+}
+
+function clampQty(value, target) {
+ const parsed = Number.parseInt(value, 10);
+ const safeValue = Number.isFinite(parsed) ? parsed : 0;
+ return Math.min(Math.max(safeValue, 0), Math.max(1, target));
+}
+
+function normalizeChecklistItem(item) {
+ const qtyTarget = Math.max(1, parsePositiveInt(item?.qtyTarget, 1));
+ const qtyCurrent = clampQty(item?.qtyCurrent, qtyTarget);
+
+ return {
+ id: item?.id || uid("item"),
+ label: String(item?.label || "").trim(),
+ qtyTarget,
+ qtyCurrent
+ };
+}
+
+function normalizeChecklistData(data) {
+ return {
+ items: (data?.items || [])
+ .map(normalizeChecklistItem)
+ .filter((item) => item.label)
+ };
+}
+
+function isChecklistItemDone(item) {
+ return clampQty(item.qtyCurrent, item.qtyTarget) >= item.qtyTarget;
+}
+
+function getGames() {
+ return gamesState.games;
+}
+
+function getGame(gameId) {
+ return getGames().find((item) => item.id === gameId);
+}
+
+function getToolboxGameId(toolbox) {
+ const links = getLinks();
+ return Object.entries(links).find(([, toolboxId]) => toolboxId === toolbox?.id)?.[0] || "";
+}
+
+function getToolboxGame(toolbox) {
+ return getGame(getToolboxGameId(toolbox));
+}
+
+async function loadGames() {
+ if (gamesState.loaded || gamesState.loading) return;
+ gamesState.loading = true;
+ gamesState.error = "";
+
+ try {
+ const response = await fetch("/data/games.json");
+ if (!response.ok) throw new Error("Impossible de charger la liste des jeux.");
+
+ const payload = await response.json();
+ gamesState.games = Array.isArray(payload.games) ? payload.games : [];
+ gamesState.loaded = true;
+ } catch (error) {
+ gamesState.error = error.message;
+ gamesState.games = [];
+ gamesState.loaded = true;
+ } finally {
+ gamesState.loading = false;
+ }
+}
+
+async function loadSiteContent() {
+ if (siteState.loaded || siteState.loading) return;
+ siteState.loading = true;
+
+ try {
+ const response = await fetch("/data/site.json");
+ if (!response.ok) throw new Error("Impossible de charger le contenu du site.");
+
+ const payload = await response.json();
+ siteState.content = mergeContent(DEFAULT_SITE_CONTENT, payload);
+ } catch {
+ siteState.content = DEFAULT_SITE_CONTENT;
+ } finally {
+ siteState.loaded = true;
+ siteState.loading = false;
+ }
+}
+
+function getDrawerWidth() {
+ const value = Number(localStorage.getItem(STORAGE_KEYS.drawerWidth));
+ if (!Number.isFinite(value) || value <= 0) return "";
+
+ const maxWidth = Math.floor(window.innerWidth * 0.94);
+ return Math.min(Math.max(value, 360), maxWidth);
+}
+
+function escapeHtml(value) {
+ return String(value).replace(/[&<>"']/g, (char) => ({
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ "\"": """,
+ "'": "'"
+ })[char]);
+}
+
+function escapeAttr(value) {
+ return escapeHtml(value).replace(/`/g, "`");
+}
+
+function assetPath(name) {
+ return encodeURI(`${MHWILDS_IMG_PATH}/${name}.png`);
+}
+
+function t(key, { capitalize = false } = {}) {
+ const value = mhwildsState.translations[key] || key;
+ if (!capitalize) return value;
+ return value.charAt(0).toUpperCase() + value.slice(1);
+}
+
+function mergeContent(defaults, overrides) {
+ if (!overrides || typeof overrides !== "object" || Array.isArray(overrides)) return defaults;
+ return Object.fromEntries(Object.entries(defaults).map(([key, value]) => {
+ const override = overrides[key];
+ if (Array.isArray(value)) return [key, Array.isArray(override) ? override : value];
+ if (value && typeof value === "object") return [key, mergeContent(value, override)];
+ return [key, override ?? value];
+ }));
+}
+
+function siteContent() {
+ return siteState.content;
+}
+
+function formatContentText(value) {
+ return escapeHtml(value).replace(/<i>(.+?)<\/i>/g, "
$1 ").replace(/\n/g, "
");
+}
+
+function formatDate(value) {
+ return new Intl.DateTimeFormat("fr-FR", { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
+}
+
+function navigate(path) {
+ location.hash = path;
+}
+
+function currentRoute() {
+ const hashRoute = location.hash.replace(/^#/, "");
+ if (hashRoute) return hashRoute;
+
+ const path = location.pathname.replace(/\/+$/, "") || "/";
+ if (path === "/mhwilds") return "/games/mhwilds";
+ if (path === "/mhwilds/monsters") return "/games/mhwilds/monsters";
+ if (path === "/mhwilds/endemic") return "/games/mhwilds/endemic";
+ if (path === "/toolboxes") return "/toolboxes";
+ if (path === "/games") return "/games";
+ if (path === "/games/mhwilds") return "/games/mhwilds";
+ if (path === "/games/mhwilds/monsters") return "/games/mhwilds/monsters";
+ if (path === "/games/mhwilds/endemic") return "/games/mhwilds/endemic";
+
+ return "/";
+}
+
+function getRouteGameId(route) {
+ const [, section, gameId] = route.split("/");
+ return section === "games" ? gameId || "" : "";
+}
+
+function renderTopbarActions(route) {
+ const gameId = getRouteGameId(route);
+ const game = getGame(gameId);
+ if (!game) return "";
+
+ const links = getLinks();
+ const linkedToolbox = getToolboxes().find((item) => item.id === links[game.id]);
+ const label = linkedToolbox
+ ? `Ouvrir la toolbox ${linkedToolbox.name}`
+ : "Associer une toolbox";
+
+ return `
+
+
+
+
+
+ `;
+}
+
+function shell(content) {
+ const route = currentRoute();
+ const contentConfig = siteContent();
+ const topbarLabel = route.startsWith("/toolbox")
+ ? contentConfig.topbar.toolbox
+ : route.startsWith("/games")
+ ? contentConfig.topbar.games
+ : contentConfig.topbar.dashboard;
+ app.innerHTML = `
+
+ `;
+}
+
+function createToolbox({ name }) {
+ const now = new Date().toISOString();
+ const toolbox = {
+ id: uid("tbx"),
+ name: name.trim() || "Nouvelle toolbox",
+ updatedAt: now,
+ modules: [
+ { id: uid("mod"), type: "notepad", title: "Notes rapides" },
+ { id: uid("mod"), type: "checklist" }
+ ]
+ };
+ return saveToolboxes([toolbox, ...getToolboxes()]) ? toolbox : null;
+}
+
+function updateToolbox(toolbox) {
+ toolbox.updatedAt = new Date().toISOString();
+ return saveToolboxes(getToolboxes().map((item) => item.id === toolbox.id ? toolbox : item));
+}
+
+function moveToolboxModule(toolboxId, fromModuleId, toModuleId, placement = "before") {
+ if (!fromModuleId || !toModuleId || fromModuleId === toModuleId) return false;
+
+ const toolbox = getToolboxes().find((item) => item.id === toolboxId);
+ if (!toolbox) return false;
+
+ const modules = [...toolbox.modules];
+ const fromIndex = modules.findIndex((module) => module.id === fromModuleId);
+ const toIndex = modules.findIndex((module) => module.id === toModuleId);
+ if (fromIndex < 0 || toIndex < 0) return false;
+
+ const [moved] = modules.splice(fromIndex, 1);
+ const targetIndex = modules.findIndex((module) => module.id === toModuleId);
+ const insertIndex = placement === "after" ? targetIndex + 1 : targetIndex;
+ modules.splice(insertIndex, 0, moved);
+ toolbox.modules = modules;
+ updateToolbox(toolbox);
+ return true;
+}
+
+function deleteToolbox(id) {
+ const toolbox = getToolboxes().find((item) => item.id === id);
+ if (toolbox) {
+ toolbox.modules.forEach((module) => localStorage.removeItem(moduleStorageKey(id, module.id)));
+ }
+ saveToolboxes(getToolboxes().filter((item) => item.id !== id));
+ const links = getLinks();
+ Object.entries(links).forEach(([gameId, toolboxId]) => {
+ if (toolboxId === id) delete links[gameId];
+ });
+ saveLinks(links);
+}
+
+function linkToolboxToGame(gameId, toolboxId) {
+ const previousLinks = getLinks();
+ const previousToolboxId = previousLinks[gameId] || "";
+ const links = getLinks();
+ if (toolboxId) links[gameId] = toolboxId;
+ else delete links[gameId];
+ saveLinks(links);
+
+ const touchedToolboxIds = new Set([previousToolboxId, toolboxId].filter(Boolean));
+ const now = new Date().toISOString();
+ const nextToolboxes = getToolboxes().map((toolbox) => {
+ return touchedToolboxIds.has(toolbox.id) ? { ...toolbox, updatedAt: now } : toolbox;
+ });
+ saveToolboxes(nextToolboxes);
+}
+
+function renderHome() {
+ const toolboxes = getToolboxes();
+ const toolCount = Object.keys(MODULES).length;
+ const content = siteContent().home;
+ const dialogue = content.origin.lines.map((line) => `
+
${formatContentText(line.text || "")}
+ `).join("");
+
+ shell(`
+
+
+
${escapeHtml(content.hero.eyebrow)}
+
${escapeHtml(content.hero.title)}
+
${escapeHtml(content.hero.description)}
+
+
+
+
+ ${toolboxes.length}
+ ${escapeHtml(toolboxes.length > 1 ? content.stats.toolboxPlural : content.stats.toolboxSingular)}
+
+
+ ${toolCount}
+ ${escapeHtml(toolCount > 1 ? content.stats.toolPlural : content.stats.toolSingular)}
+
+
+
+
+
+
${escapeHtml(content.origin.eyebrow)}
+
${escapeHtml(content.origin.title)}
+
+ ${dialogue}
+ ${escapeHtml(content.origin.caption)}
+
+
+
+
+
+
+ `);
+}
+
+function renderToolboxes() {
+ const toolboxes = getToolboxes();
+ const content = siteContent().toolboxes;
+ shell(`
+
+
+
+
${escapeHtml(content.eyebrow)}
+
${escapeHtml(content.title)}
+
+
+ ${escapeHtml(content.newButton)}
+
+ ${escapeHtml(content.importOne)}
+
+
+
+
+
+
+ ${storageHelpCard(content.storageHelp)}
+ ${toolboxes.length ? toolboxes.map(toolboxCard).join("") : `
+
+
${escapeHtml(content.emptyTitle)}
+
${escapeHtml(content.emptyText)}
+
+ `}
+
+ ${renderStorageQuota()}
+
+ `);
+}
+
+function storageHelpCard(help) {
+ return `
+
+
+
+
+
+
LocalStorage
+
${escapeHtml(help.title)}
+
+
+
${escapeHtml(help.text)}
+
+ ${help.items.map((item, index) => `
+
+ ${index + 1}
+ ${escapeHtml(item)}
+
+ `).join("")}
+
+
+
+ `;
+}
+
+function toolboxCard(toolbox) {
+ const game = getToolboxGame(toolbox);
+ return `
+
+
+ ${game?.image ? `
` : ""}
+
+
+
${game ? escapeHtml(game.title) : "Toolbox libre"}
+
${escapeHtml(toolbox.name)}
+
Modifiée le ${formatDate(toolbox.updatedAt)}
+
+
+
+ `;
+}
+
+function renderToolbox(id, { embedded = false } = {}) {
+ const toolbox = getToolboxes().find((item) => item.id === id);
+ if (!toolbox) {
+ if (embedded) return `
`;
+ shell(`
`);
+ return;
+ }
+
+ const moduleColumns = Number(toolbox.moduleColumns) === 1 ? 1 : 2;
+ const content = `
+
+
+ ${embedded ? "" : `
+
+ `}
+
+ ${renderToolboxModules(toolbox, moduleColumns)}
+
+ ${embedded ? "" : renderStorageQuota()}
+
+ `;
+
+ if (embedded) return content;
+ shell(content);
+}
+
+function renderModuleLayoutSwitch(toolbox, moduleColumns) {
+ return `
+
+
+
+
+
+
+
+
+ `;
+}
+
+function renderToolboxModules(toolbox, moduleColumns) {
+ if (moduleColumns === 1) {
+ return toolbox.modules.map((module) => renderModule(toolbox, module)).join("");
+ }
+
+ const columns = [[], []];
+ toolbox.modules.forEach((module, index) => {
+ columns[index % 2].push(module);
+ });
+
+ return columns.map((modules) => `
+
+ ${modules.map((module) => renderModule(toolbox, module)).join("")}
+
+ `).join("");
+}
+
+function renderModule(toolbox, module) {
+ const label = MODULES[module.type]?.label || module.type;
+ return `
+
+
+ ${module.type === "notepad" ? renderNotepad(toolbox.id, module.id) : ""}
+ ${module.type === "checklist" ? renderChecklist(toolbox.id, module.id) : ""}
+ ${module.type === "screenshots" ? renderScreenshots(toolbox.id, module.id) : ""}
+
+ `;
+}
+
+function renderNotepad(toolboxId, moduleId) {
+ const data = getModuleData(toolboxId, moduleId, { text: "" });
+ return `
`;
+}
+
+function renderChecklist(toolboxId, moduleId) {
+ const data = normalizeChecklistData(getModuleData(toolboxId, moduleId, { items: [] }));
+ return `
+
+
+ ${data.items.map((item) => renderChecklistItem(toolboxId, moduleId, item)).join("")}
+
+ `;
+}
+
+function renderChecklistItem(toolboxId, moduleId, item) {
+ const done = isChecklistItemDone(item);
+ return `
+
+
+ ${item.qtyTarget === 1 ? `
+
+ ` : `
+
+ -
+ ${clampQty(item.qtyCurrent, item.qtyTarget)}/${item.qtyTarget}
+ +
+
+ `}
+
${escapeHtml(item.label)}
+
+ ×
+
+ `;
+}
+
+function renderScreenshots(toolboxId, moduleId) {
+ const data = getModuleData(toolboxId, moduleId, { shots: [] });
+ return `
+
+
+ Ajouter des screenshots
+
+
Coller une image ici
+
+ ${data.shots.map((shot) => `
+
+
+
+
+
+
+
+
+ `).join("")}
+
+ `;
+}
+
+function renderGames() {
+ const games = getGames();
+
+ shell(`
+
+
+
Pages informatives
+
Jeux disponibles
+
Choisissez un jeu pour consulter ses données maintenues et associer une toolbox locale.
+
+
+
+ ${games.length ? games.map((game) => `
+
+
+
+
+
+
${escapeHtml(game.eyebrow || "Guide de jeu")}
+
${escapeHtml(game.title)}
+
${escapeHtml(game.summary)}
+
+
+
+ `).join("") : `
+
+
Aucun jeu disponible
+
${escapeHtml(gamesState.error || "Ajoutez des entrées dans /data/games.json.")}
+
+ `}
+
+ `);
+}
+
+function renderGame(gameId) {
+ const game = getGame(gameId);
+ if (!game) {
+ renderGames();
+ return;
+ }
+
+ if (game.id === "mhwilds") {
+ renderMhwilds(currentRoute().split("/")[3] || "");
+ return;
+ }
+
+ shell(`
+
+
+
${escapeHtml(game.eyebrow || "Guide de jeu")}
+
${escapeHtml(game.title)}
+
${escapeHtml(game.summary)}
+
+
+
+ ${game.sections.map((section) => `
+
+ ${escapeHtml(section.title)}
+ ${section.items.map((item) => `${escapeHtml(item)} `).join("")}
+
+ `).join("")}
+
+
+ `);
+}
+
+async function loadMhwildsData() {
+ if (mhwildsState.loaded || mhwildsState.loading) return;
+ mhwildsState.loading = true;
+ mhwildsState.error = "";
+
+ try {
+ const [monstersResponse, endemicResponse, translationsResponse] = await Promise.all([
+ fetch("/data/mhwilds/monsters.json"),
+ fetch("/data/mhwilds/endemic_life.json"),
+ fetch("/data/mhwilds/i18n/fr.json")
+ ]);
+
+ if (!monstersResponse.ok || !endemicResponse.ok || !translationsResponse.ok) {
+ throw new Error("Impossible de charger les données Monster Hunter Wilds.");
+ }
+
+ const [monstersJson, endemicJson, translations] = await Promise.all([
+ monstersResponse.json(),
+ endemicResponse.json(),
+ translationsResponse.json()
+ ]);
+
+ mhwildsState.monsters = monstersJson.monsters || [];
+ mhwildsState.endemic = [
+ ...(endemicJson.endemicLife || []),
+ ...(endemicJson.aquaticLife || [])
+ ];
+ mhwildsState.translations = translations;
+ mhwildsState.loaded = true;
+ } catch (error) {
+ mhwildsState.error = error.message;
+ } finally {
+ mhwildsState.loading = false;
+ }
+}
+
+function renderMhwilds(category) {
+ const activeCategory = category === "monsters" || category === "endemic" ? category : "";
+
+ if (!mhwildsState.loaded) {
+ shell(`
+
+
+
Monster Hunter Wilds
+
Monster Hunter: Wilds
+
Chargement des données de chasse, faune endémique et filtres associés.
+
+
+
Chargement Préparation des données locales...
+ `);
+ loadMhwildsData().then(rerender);
+ return;
+ }
+
+ if (mhwildsState.error) {
+ shell(`
+
+ Impossible de charger MH Wilds
+ ${escapeHtml(mhwildsState.error)}
+ Réessayer
+
+ `);
+ return;
+ }
+
+ if (!activeCategory) {
+ renderMhwildsOverview();
+ return;
+ }
+
+ renderMhwildsListing(activeCategory);
+}
+
+function renderMhwildsOverview() {
+ shell(`
+
+
+
Guide de jeu
+
Monster Hunter: Wilds
+
Consultez rapidement les monstres, faiblesses, afflictions, hitzones et emplacements de faune endémique.
+
+
+
+
+ `);
+}
+
+function renderMhwildsListing(category) {
+ const isMonsters = category === "monsters";
+ const label = isMonsters ? t("monsters", { capitalize: true }) : t("endemic life", { capitalize: true });
+ const filterKey = isMonsters ? "weaknesses" : "locations";
+ const options = getUniqueConditionValues(isMonsters ? mhwildsState.monsters : mhwildsState.endemic, filterKey);
+ const total = isMonsters ? mhwildsState.monsters.length : mhwildsState.endemic.length;
+ const visible = getFilteredMhwildsItems(category).length;
+
+ shell(`
+
+
+
Monster Hunter Wilds
+
+
${escapeHtml(label)}
+ ${visible} / ${total}
+
+
${isMonsters ? "Filtrez les monstres par nom et faiblesses, puis consultez leurs dégâts détaillés." : "Filtrez la faune par nom et zones d'apparition."}
+
+
+
+
+
+ ${renderMhwildsFilters(category, filterKey, options)}
+
+
+ ${renderMhwildsResults(category)}
+
+
+
+ `);
+}
+
+function renderMhwildsFilters(category, filterKey, options) {
+ const filters = mhwildsState.filters[category];
+ const selected = new Set(filters[filterKey]);
+ const logicLabel = filters.logic === "or" ? t("or", { capitalize: true }) : t("and", { capitalize: true });
+
+ return `
+
+
+
+
Filtres
+
${category === "monsters" ? t("weaknesses", { capitalize: true }) : t("locations", { capitalize: true })}
+
+
+
+
+
+
+ ${t("name", { capitalize: true })}
+
+
+
+ Correspondance
+ ${logicLabel}
+
+
+
+ `;
+}
+
+function renderMhwildsResults(category) {
+ const items = getFilteredMhwildsItems(category);
+
+ return `
+
+ ${items.length ? items.map((item) => category === "monsters" ? renderMonsterCard(item) : renderEndemicCard(item)).join("") : `
+
+
Aucun résultat
+
Ajustez la recherche ou réinitialisez les filtres actifs.
+
+ `}
+
+ `;
+}
+
+function refreshMhwildsResults(category) {
+ const results = document.querySelector(".mhwilds-results");
+ if (results) results.innerHTML = renderMhwildsResults(category);
+ const count = document.querySelector("[data-mhwilds-count]");
+ if (count) {
+ const total = category === "monsters" ? mhwildsState.monsters.length : mhwildsState.endemic.length;
+ count.textContent = `${getFilteredMhwildsItems(category).length} / ${total}`;
+ }
+}
+
+function renderMonsterCard(monster) {
+ const weaknesses = getConditionValues(monster.weaknesses);
+ const ailments = getConditionValues(monster.ailments).filter((value) => value !== "none");
+
+ return `
+
+
+
+
+
+
+
+
${escapeHtml(t(monster.type, { capitalize: true }))}
+
${escapeHtml(t(monster.name, { capitalize: true }))}
+ ${renderIconRow(t("weaknesses", { capitalize: true }), weaknesses)}
+ ${renderIconRow(t("ailments", { capitalize: true }), ailments.length ? ailments : ["none"])}
+
+
+
+
+
Détails
+
${escapeHtml(t(monster.name, { capitalize: true }))}
+
+ ${renderDamageTable(monster.damage || [])}
+
+
+
+ `;
+}
+
+function renderEndemicCard(item) {
+ const locations = getConditionValues(item.locations);
+ const description = t(item.description);
+ const hasDescription = normalizeText(description) && normalizeText(description) !== normalizeText("à compléter");
+
+ return `
+
+
+
+
+
+
${escapeHtml(t(item.name, { capitalize: true }))}
+ ${renderIconRow(t("locations", { capitalize: true }), locations)}
+ ${hasDescription ? `
${escapeHtml(description)}
` : ""}
+
+
+ `;
+}
+
+function renderIconRow(label, values) {
+ return `
+
+
${escapeHtml(label)}
+
+ ${values.map((value) => value === "none" ? `
- ` : `
+
+ `).join("")}
+
+
+ `;
+}
+
+function renderDamageTable(rows) {
+ if (!rows.length) return "";
+ const columns = Object.keys(rows[0]);
+ return `
+
+ `;
+}
+
+function getFilteredMhwildsItems(category) {
+ const items = category === "monsters" ? mhwildsState.monsters : mhwildsState.endemic;
+ const filters = mhwildsState.filters[category];
+ const filterKey = category === "monsters" ? "weaknesses" : "locations";
+ const selected = filters[filterKey];
+ const search = normalizeText(filters.name);
+
+ return items.filter((item) => {
+ const nameMatches = !search || normalizeText(t(item.name)).includes(search) || normalizeText(item.name).includes(search);
+ if (!nameMatches) return false;
+ if (!selected.length) return true;
+
+ const values = getConditionValues(item[filterKey]);
+ if (filters.logic === "or" && selected.length >= 2) {
+ return selected.some((value) => values.includes(value));
+ }
+
+ return selected.every((value) => values.includes(value));
+ });
+}
+
+function getConditionValues(conditions = []) {
+ return [...new Set(conditions.flatMap((condition) => condition.values || []))];
+}
+
+function getUniqueConditionValues(items, property) {
+ return [...new Set(items.flatMap((item) => getConditionValues(item[property])))]
+ .filter((value) => value !== "none")
+ .sort((a, b) => t(a).localeCompare(t(b), "fr"));
+}
+
+function normalizeText(value) {
+ return String(value || "").trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, " ");
+}
+
+function openDrawer(gameId) {
+ const drawer = document.querySelector("#toolbox-drawer");
+ const toolboxes = getToolboxes();
+ const links = getLinks();
+ const selectedId = links[gameId] || "";
+ const drawerWidth = getDrawerWidth();
+ drawer.innerHTML = `
+
+
+ `;
+ drawer.dataset.gameId = gameId;
+ drawer.setAttribute("aria-hidden", "false");
+}
+
+function closeDrawer() {
+ const drawer = document.querySelector("#toolbox-drawer");
+ if (drawer) {
+ drawer.setAttribute("aria-hidden", "true");
+ drawer.innerHTML = "";
+ delete drawer.dataset.gameId;
+ }
+}
+
+function refreshToolboxView(sourceElement = null) {
+ const drawer = sourceElement?.closest?.("#toolbox-drawer");
+ if (drawer?.dataset.gameId) {
+ openDrawer(drawer.dataset.gameId);
+ return;
+ }
+
+ rerender();
+}
+
+function showToolboxCreateModal({ gameId = "" } = {}) {
+ return new Promise((resolve) => {
+ const host = document.createElement("div");
+ host.className = "confirm-modal-root";
+ host.innerHTML = `
+
+
+ `;
+
+ const previousFocus = document.activeElement;
+ document.body.appendChild(host);
+ const input = host.querySelector("input[name='name']");
+
+ function close(result) {
+ host.remove();
+ document.removeEventListener("keydown", onKeydown);
+ previousFocus?.focus?.();
+ resolve(result);
+ }
+
+ function onKeydown(event) {
+ if (event.key === "Escape") close(null);
+ }
+
+ host.addEventListener("click", (event) => {
+ if (event.target.closest("[data-toolbox-create-result='cancel']")) close(null);
+ });
+
+ host.querySelector("form").addEventListener("submit", (event) => {
+ event.preventDefault();
+ const name = new FormData(event.currentTarget).get("name")?.trim();
+ if (!name) return;
+
+ const toolbox = createToolbox({ name });
+ if (!toolbox) return;
+ if (gameId) {
+ const links = getLinks();
+ links[gameId] = toolbox.id;
+ saveLinks(links);
+ }
+ close(toolbox);
+ });
+
+ document.addEventListener("keydown", onKeydown);
+ input.focus();
+ });
+}
+
+function showToolboxLinkModal(gameId) {
+ return new Promise((resolve) => {
+ const toolboxes = getToolboxes();
+ const selectedId = getLinks()[gameId] || "";
+ const host = document.createElement("div");
+ host.className = "confirm-modal-root";
+ host.innerHTML = `
+
+
+ `;
+
+ const previousFocus = document.activeElement;
+ document.body.appendChild(host);
+ const select = host.querySelector("select");
+
+ function close(result) {
+ host.remove();
+ document.removeEventListener("keydown", onKeydown);
+ previousFocus?.focus?.();
+ resolve(result);
+ }
+
+ function onKeydown(event) {
+ if (event.key === "Escape") close(null);
+ }
+
+ host.addEventListener("click", (event) => {
+ if (event.target.closest("[data-toolbox-link-result='cancel']")) close(null);
+ });
+
+ host.querySelector("form").addEventListener("submit", (event) => {
+ event.preventDefault();
+ close(new FormData(event.currentTarget).get("toolboxId") || "");
+ });
+
+ document.addEventListener("keydown", onKeydown);
+ select.focus();
+ });
+}
+
+async function compressImage(file) {
+ const bitmap = await createImageBitmap(file);
+ const maxSide = 1400;
+ const ratio = Math.min(1, maxSide / Math.max(bitmap.width, bitmap.height));
+ const canvas = document.createElement("canvas");
+ canvas.width = Math.round(bitmap.width * ratio);
+ canvas.height = Math.round(bitmap.height * ratio);
+ canvas.getContext("2d").drawImage(bitmap, 0, 0, canvas.width, canvas.height);
+ return canvas.toDataURL("image/jpeg", 0.78);
+}
+
+async function addScreenshotFiles(toolboxId, moduleId, files) {
+ const imageFiles = [...files].filter((file) => file?.type?.startsWith("image/"));
+ if (!imageFiles.length) return false;
+
+ const data = getModuleData(toolboxId, moduleId, { shots: [] });
+ for (const file of imageFiles) {
+ data.shots.unshift({
+ id: uid("shot"),
+ dataUrl: await compressImage(file)
+ });
+ }
+ return setModuleData(toolboxId, moduleId, data);
+}
+
+function exportToolbox(id) {
+ const toolbox = normalizeToolbox(getToolboxes().find((item) => item.id === id));
+ if (!toolbox) return;
+ const payload = createToolboxExportPayload(toolbox);
+ downloadJson(payload, `${toolbox.name.toLowerCase().replace(/[^a-z0-9]+/gi, "-")}.sokkog.json`);
+}
+
+function exportAllToolboxes() {
+ downloadJson(createGlobalExportPayload(), `sokkog-global-${new Date().toISOString().slice(0, 10)}.json`);
+}
+
+async function importToolbox(file) {
+ const payload = JSON.parse(await file.text());
+ if (!payload.toolbox?.modules) throw new Error("Format d'outils invalide");
+ const imported = normalizeToolbox({ ...payload.toolbox, id: uid("tbx"), updatedAt: new Date().toISOString() });
+ const moduleIdMap = new Map();
+ imported.modules = imported.modules.map((module) => {
+ const nextId = uid("mod");
+ moduleIdMap.set(module.id, nextId);
+ return { ...module, id: nextId };
+ });
+ saveToolboxes([imported, ...getToolboxes()]);
+ Object.entries(payload.modules || {}).forEach(([oldId, data]) => {
+ const nextId = moduleIdMap.get(oldId);
+ if (nextId) setModuleData(imported.id, nextId, data);
+ });
+ return imported;
+}
+
+async function importAllToolboxes(file) {
+ const payload = JSON.parse(await file.text());
+ if (!Array.isArray(payload.toolboxes) || !payload.modules || typeof payload.modules !== "object") {
+ throw new Error("Format d'import global invalide");
+ }
+
+ const toolboxIdMap = new Map();
+ const moduleIdMap = new Map();
+ const projected = {};
+ const importedToolboxes = payload.toolboxes.map((toolbox) => {
+ const nextToolboxId = uid("tbx");
+ toolboxIdMap.set(toolbox.id, nextToolboxId);
+ const modules = (toolbox.modules || []).map((module) => {
+ const nextModuleId = uid("mod");
+ moduleIdMap.set(globalModuleKey(toolbox.id, module.id), nextModuleId);
+ return { ...module, id: nextModuleId };
+ });
+
+ return normalizeToolbox({
+ ...toolbox,
+ id: nextToolboxId,
+ name: `${toolbox.name || "Toolbox"} (import)`,
+ modules,
+ updatedAt: new Date().toISOString()
+ });
+ });
+
+ const nextToolboxes = [...importedToolboxes, ...getToolboxes()];
+ const importedToolboxMap = new Map(importedToolboxes.map((toolbox) => [toolbox.id, toolbox]));
+ projected[STORAGE_KEYS.registry] = JSON.stringify(compactToolboxesForStorage(nextToolboxes));
+
+ Object.entries(payload.modules).forEach(([key, data]) => {
+ const [oldToolboxId] = key.split(":");
+ const nextToolboxId = toolboxIdMap.get(oldToolboxId);
+ const nextModuleId = moduleIdMap.get(key);
+ const toolbox = importedToolboxMap.get(nextToolboxId);
+ const module = toolbox?.modules.find((item) => item.id === nextModuleId);
+ const compact = compactModuleDataForStorage(module?.type, data);
+ if (nextToolboxId && nextModuleId && compact) {
+ projected[moduleStorageKey(nextToolboxId, nextModuleId)] = JSON.stringify(compact);
+ }
+ });
+
+ const links = getLinks();
+ Object.entries(payload.links || {}).forEach(([gameId, oldToolboxId]) => {
+ const nextToolboxId = toolboxIdMap.get(oldToolboxId);
+ if (nextToolboxId) links[gameId] = nextToolboxId;
+ });
+ projected[STORAGE_KEYS.links] = JSON.stringify(links);
+
+ const projectedUsage = getAppStorageUsage(projected);
+ if (projectedUsage.used > APP_STORAGE_LIMIT_BYTES) {
+ showStorageQuotaModal(projectedUsage);
+ return false;
+ }
+
+ Object.entries(projected).forEach(([key, value]) => writeStorageValue(key, value));
+ return true;
+}
+
+function showConfirmModal({ title, message, confirmLabel = "Confirmer", cancelLabel = "Annuler", danger = false, className = "" }) {
+ return new Promise((resolve) => {
+ const host = document.createElement("div");
+ host.className = ["confirm-modal-root", className].filter(Boolean).join(" ");
+ host.innerHTML = `
+
+
+
+ ${escapeHtml(message)}
+
+ ${escapeHtml(cancelLabel)}
+ ${escapeHtml(confirmLabel)}
+
+
+ `;
+
+ const previousFocus = document.activeElement;
+ document.body.appendChild(host);
+
+ const cancelButton = host.querySelector('[data-confirm-result="cancel"]');
+ const confirmButton = host.querySelector('[data-confirm-result="confirm"]');
+
+ function close(result) {
+ host.remove();
+ document.removeEventListener("keydown", onKeydown);
+ previousFocus?.focus?.();
+ resolve(result);
+ }
+
+ function onKeydown(event) {
+ if (event.key === "Escape") close(false);
+ if (event.key !== "Tab") return;
+
+ const focusable = [cancelButton, confirmButton];
+ const currentIndex = focusable.indexOf(document.activeElement);
+ const nextIndex = event.shiftKey
+ ? (currentIndex <= 0 ? focusable.length - 1 : currentIndex - 1)
+ : (currentIndex === focusable.length - 1 ? 0 : currentIndex + 1);
+
+ event.preventDefault();
+ focusable[nextIndex].focus();
+ }
+
+ host.addEventListener("click", (event) => {
+ const result = event.target.closest("[data-confirm-result]")?.dataset.confirmResult;
+ if (!result) return;
+ close(result === "confirm");
+ });
+
+ document.addEventListener("keydown", onKeydown);
+ confirmButton.focus();
+ });
+}
+
+function showScreenshotViewer(shot) {
+ const host = document.createElement("div");
+ host.className = "screenshot-viewer-root";
+ host.innerHTML = `
+
+
+
+
+
+ `;
+
+ document.body.appendChild(host);
+
+ function close() {
+ host.remove();
+ document.removeEventListener("keydown", onKeydown);
+ }
+
+ function onKeydown(event) {
+ if (event.key === "Escape") close();
+ }
+
+ host.addEventListener("click", (event) => {
+ if (event.target.closest("[data-action='close-screenshot-viewer']")) close();
+ });
+ document.addEventListener("keydown", onKeydown);
+}
+
+function rerender() {
+ if (!siteState.loaded) {
+ shell(`
+
+ Chargement
+ Préparation du contenu...
+
+ `);
+ loadSiteContent().then(rerender);
+ return;
+ }
+
+ if (!gamesState.loaded) {
+ shell(`
+
+ Chargement
+ Préparation des jeux disponibles...
+
+ `);
+ loadGames().then(rerender);
+ return;
+ }
+
+ const route = currentRoute();
+ if (route === "/") renderHome();
+ else if (route === "/toolboxes") renderToolboxes();
+ else if (route.startsWith("/toolbox/")) renderToolbox(route.split("/")[2]);
+ else if (route === "/games") renderGames();
+ else if (route.startsWith("/games/")) renderGame(route.split("/")[2]);
+ else navigate("/");
+}
+
+document.addEventListener("click", async (event) => {
+ const target = event.target.closest("[data-action]");
+ if (!target) return;
+ const action = target.dataset.action;
+
+ if (action === "flip-monster-card") {
+ target.classList.toggle("is-flipped");
+ target.setAttribute("aria-pressed", target.classList.contains("is-flipped") ? "true" : "false");
+ return;
+ }
+
+ if (action === "new-toolbox") {
+ const toolbox = await showToolboxCreateModal();
+ if (toolbox) navigate(`/toolbox/${toolbox.id}`);
+ }
+ if (action === "delete-toolbox") {
+ const toolbox = getToolboxes().find((item) => item.id === target.dataset.id);
+ const confirmed = await showConfirmModal({
+ title: "Supprimer la toolbox",
+ message: `Supprimer "${toolbox?.name || "cette toolbox"}" et ses données locales ?`,
+ confirmLabel: "Supprimer",
+ danger: true
+ });
+
+ if (confirmed) {
+ deleteToolbox(target.dataset.id);
+ rerender();
+ }
+ }
+ if (action === "export-toolbox") exportToolbox(target.dataset.id);
+ if (action === "export-all-toolboxes") exportAllToolboxes();
+ if (action === "open-link-toolbox-modal") {
+ const toolboxId = await showToolboxLinkModal(target.dataset.gameId);
+ if (toolboxId == null) return;
+ linkToolboxToGame(target.dataset.gameId, toolboxId);
+ openDrawer(target.dataset.gameId);
+ }
+ if (action === "set-module-layout") {
+ const toolbox = getToolboxes().find((item) => item.id === target.dataset.id);
+ if (toolbox) {
+ toolbox.moduleColumns = Number(target.dataset.columns) === 1 ? 1 : 2;
+ updateToolbox(toolbox);
+ refreshToolboxView(target);
+ }
+ }
+ if (action === "view-screenshot") {
+ const data = getModuleData(target.dataset.toolboxId, target.dataset.moduleId, { shots: [] });
+ const shot = data.shots.find((item) => item.id === target.dataset.shotId);
+ if (shot) showScreenshotViewer(shot);
+ }
+ if (action === "close-screenshot-viewer") {
+ target.closest(".screenshot-viewer-root")?.remove();
+ }
+ if (action === "delete-module") {
+ const toolbox = getToolboxes().find((item) => item.id === target.dataset.toolboxId);
+ const module = toolbox?.modules.find((item) => item.id === target.dataset.moduleId);
+ const confirmed = await showConfirmModal({
+ title: "Retirer l'outil",
+ message: `Retirer "${module?.title || "cet outil"}" de la toolbox ?`,
+ confirmLabel: "Retirer",
+ danger: true
+ });
+
+ if (confirmed && toolbox) {
+ toolbox.modules = toolbox.modules.filter((item) => item.id !== target.dataset.moduleId);
+ localStorage.removeItem(moduleStorageKey(toolbox.id, target.dataset.moduleId));
+ updateToolbox(toolbox);
+ refreshToolboxView(target);
+ }
+ }
+ if (action === "open-drawer") openDrawer(target.dataset.gameId);
+ if (action === "close-drawer") closeDrawer();
+ if (action === "new-toolbox-for-game") {
+ const toolbox = await showToolboxCreateModal({ gameId: target.dataset.gameId });
+ if (toolbox) openDrawer(target.dataset.gameId);
+ }
+ if (action === "retry-mhwilds") {
+ mhwildsState.loaded = false;
+ mhwildsState.loading = false;
+ mhwildsState.error = "";
+ rerender();
+ }
+ if (action === "reset-mhwilds-filters") {
+ const category = target.dataset.category;
+ const filterKey = category === "monsters" ? "weaknesses" : "locations";
+ mhwildsState.filters[category] = { name: "", [filterKey]: [], logic: "and" };
+ rerender();
+ }
+ if (action === "toggle-mhwilds-logic") {
+ const category = target.dataset.category;
+ const filters = mhwildsState.filters[category];
+ filters.logic = filters.logic === "and" ? "or" : "and";
+ rerender();
+ }
+ if (action === "delete-check-item") {
+ const data = normalizeChecklistData(getModuleData(target.dataset.toolboxId, target.dataset.moduleId, { items: [] }));
+ data.items = data.items.filter((item) => item.id !== target.dataset.itemId);
+ setModuleData(target.dataset.toolboxId, target.dataset.moduleId, data);
+ refreshToolboxView(target);
+ }
+ if (action === "adjust-check-qty") {
+ const data = normalizeChecklistData(getModuleData(target.dataset.toolboxId, target.dataset.moduleId, { items: [] }));
+ const item = data.items.find((entry) => entry.id === target.dataset.itemId);
+ if (item) {
+ const delta = Number.parseInt(target.dataset.delta, 10) || 0;
+ item.qtyCurrent = clampQty(item.qtyCurrent + delta, item.qtyTarget);
+ setModuleData(target.dataset.toolboxId, target.dataset.moduleId, data);
+ refreshToolboxView(target);
+ }
+ }
+ if (action === "delete-screenshot") {
+ const data = getModuleData(target.dataset.toolboxId, target.dataset.moduleId, { shots: [] });
+ data.shots = data.shots.filter((shot) => shot.id !== target.dataset.shotId);
+ setModuleData(target.dataset.toolboxId, target.dataset.moduleId, data);
+ refreshToolboxView(target);
+ }
+});
+
+document.addEventListener("pointerdown", (event) => {
+ const handle = event.target.closest(".drawer-resize-handle");
+ if (!handle) return;
+
+ const panel = handle.closest(".drawer-panel");
+ if (!panel) return;
+
+ event.preventDefault();
+ const startX = event.clientX;
+ const startWidth = panel.getBoundingClientRect().width;
+ const minWidth = 360;
+ const maxWidth = Math.floor(window.innerWidth * 0.94);
+
+ document.body.classList.add("is-resizing-drawer");
+
+ function resizeDrawer(moveEvent) {
+ const nextWidth = Math.min(Math.max(startWidth + startX - moveEvent.clientX, minWidth), maxWidth);
+ panel.style.width = `${nextWidth}px`;
+ writeStorageValue(STORAGE_KEYS.drawerWidth, String(Math.round(nextWidth)));
+ }
+
+ function stopResize() {
+ document.body.classList.remove("is-resizing-drawer");
+ window.removeEventListener("pointermove", resizeDrawer);
+ window.removeEventListener("pointerup", stopResize);
+ window.removeEventListener("pointercancel", stopResize);
+ }
+
+ window.addEventListener("pointermove", resizeDrawer);
+ window.addEventListener("pointerup", stopResize);
+ window.addEventListener("pointercancel", stopResize);
+});
+
+document.addEventListener("focusin", (event) => {
+ const pasteTarget = event.target.closest("[data-action='paste-screenshot']");
+ if (pasteTarget && pasteTarget.textContent.trim() === "Coller une image ici") {
+ pasteTarget.textContent = "";
+ return;
+ }
+
+ const title = event.target.closest("[data-action='edit-module-title'], [data-action='edit-toolbox-title']");
+ if (!title) return;
+
+ title.dataset.previousTitle = title.textContent.trim();
+});
+
+document.addEventListener("focusout", (event) => {
+ const pasteTarget = event.target.closest("[data-action='paste-screenshot']");
+ if (pasteTarget && !pasteTarget.textContent.trim()) {
+ pasteTarget.textContent = "Coller une image ici";
+ return;
+ }
+
+ const title = event.target.closest("[data-action='edit-module-title'], [data-action='edit-toolbox-title']");
+ if (!title) return;
+
+ if (title.dataset.action === "edit-toolbox-title") {
+ const toolbox = getToolboxes().find((item) => item.id === title.dataset.id);
+ if (!toolbox) return;
+
+ const nextTitle = title.textContent.trim() || "Nouvelle toolbox";
+ title.textContent = nextTitle;
+
+ if (nextTitle !== toolbox.name) {
+ toolbox.name = nextTitle;
+ updateToolbox(toolbox);
+ }
+ return;
+ }
+
+ const toolbox = getToolboxes().find((item) => item.id === title.dataset.toolboxId);
+ const module = toolbox?.modules.find((item) => item.id === title.dataset.moduleId);
+ if (!toolbox || !module) return;
+
+ const fallback = MODULES[module.type]?.label || "Outil";
+ const nextTitle = title.textContent.trim() || fallback;
+ title.textContent = nextTitle;
+
+ if (nextTitle !== module.title) {
+ module.title = nextTitle;
+ updateToolbox(toolbox);
+ }
+});
+
+document.addEventListener("dragstart", (event) => {
+ const moduleElement = event.target.closest(".module[draggable='true']");
+ if (!moduleElement) return;
+
+ if (event.target.closest("button, input, select, textarea, [contenteditable='true']")) {
+ event.preventDefault();
+ return;
+ }
+
+ draggedModule = {
+ toolboxId: moduleElement.dataset.toolboxId,
+ moduleId: moduleElement.dataset.moduleId
+ };
+ moduleElement.classList.add("is-dragging");
+ event.dataTransfer.effectAllowed = "move";
+ event.dataTransfer.setData("text/plain", draggedModule.moduleId);
+});
+
+document.addEventListener("dragover", (event) => {
+ const dropzone = event.target.closest("[data-action='drop-screenshot']");
+ if (dropzone) {
+ event.preventDefault();
+ event.dataTransfer.dropEffect = "copy";
+ dropzone.classList.add("is-drag-over");
+ return;
+ }
+
+ const moduleElement = event.target.closest(".module[draggable='true']");
+ if (!moduleElement || !draggedModule || moduleElement.dataset.toolboxId !== draggedModule.toolboxId) return;
+
+ event.preventDefault();
+ event.dataTransfer.dropEffect = "move";
+ document.querySelectorAll(".module.is-drop-target").forEach((item) => item.classList.remove("is-drop-target", "drop-after"));
+ const rect = moduleElement.getBoundingClientRect();
+ moduleElement.classList.add("is-drop-target");
+ moduleElement.classList.toggle("drop-after", event.clientY > rect.top + rect.height / 2);
+});
+
+document.addEventListener("dragleave", (event) => {
+ const dropzone = event.target.closest("[data-action='drop-screenshot']");
+ if (!dropzone || dropzone.contains(event.relatedTarget)) return;
+ dropzone.classList.remove("is-drag-over");
+});
+
+document.addEventListener("drop", async (event) => {
+ const dropzone = event.target.closest("[data-action='drop-screenshot']");
+ if (dropzone) {
+ event.preventDefault();
+ dropzone.classList.remove("is-drag-over");
+ if (await addScreenshotFiles(dropzone.dataset.toolboxId, dropzone.dataset.moduleId, event.dataTransfer.files)) {
+ refreshToolboxView(dropzone);
+ }
+ return;
+ }
+
+ const moduleElement = event.target.closest(".module[draggable='true']");
+ if (!moduleElement || !draggedModule || moduleElement.dataset.toolboxId !== draggedModule.toolboxId) return;
+
+ event.preventDefault();
+ const rect = moduleElement.getBoundingClientRect();
+ const placement = event.clientY > rect.top + rect.height / 2 ? "after" : "before";
+ if (moveToolboxModule(draggedModule.toolboxId, draggedModule.moduleId, moduleElement.dataset.moduleId, placement)) {
+ refreshToolboxView(moduleElement);
+ }
+});
+
+document.addEventListener("dragend", () => {
+ draggedModule = null;
+ document.querySelectorAll(".module.is-dragging, .module.is-drop-target").forEach((item) => {
+ item.classList.remove("is-dragging", "is-drop-target", "drop-after");
+ });
+});
+
+document.addEventListener("keydown", (event) => {
+ const editableTitle = event.target.closest("[data-action='edit-module-title'], [data-action='edit-toolbox-title']");
+ if (editableTitle && event.key === "Enter") {
+ event.preventDefault();
+ editableTitle.blur();
+ return;
+ }
+
+ if (editableTitle && event.key === "Escape") {
+ event.preventDefault();
+ editableTitle.textContent = editableTitle.dataset.previousTitle || editableTitle.textContent;
+ editableTitle.blur();
+ return;
+ }
+
+ const target = event.target.closest("[data-action='flip-monster-card']");
+ if (!target || (event.key !== "Enter" && event.key !== " ")) return;
+
+ event.preventDefault();
+ target.classList.toggle("is-flipped");
+ target.setAttribute("aria-pressed", target.classList.contains("is-flipped") ? "true" : "false");
+});
+
+document.addEventListener("change", async (event) => {
+ const target = event.target.closest("[data-action]");
+ if (!target) return;
+ if (target.dataset.action === "add-module" && target.value) {
+ const toolbox = getToolboxes().find((item) => item.id === target.dataset.id);
+ toolbox.modules.push({ id: uid("mod"), type: target.value });
+ updateToolbox(toolbox);
+ refreshToolboxView(target);
+ }
+ if (target.dataset.action === "toggle-check-item") {
+ const data = normalizeChecklistData(getModuleData(target.dataset.toolboxId, target.dataset.moduleId, { items: [] }));
+ const item = data.items.find((entry) => entry.id === target.dataset.itemId);
+ if (item) {
+ item.qtyTarget = 1;
+ item.qtyCurrent = target.checked ? 1 : 0;
+ }
+ setModuleData(target.dataset.toolboxId, target.dataset.moduleId, data);
+ target.closest(".checklist-item")?.classList.toggle("is-complete", target.checked);
+ }
+ if (target.dataset.action === "add-screenshot") {
+ if (await addScreenshotFiles(target.dataset.toolboxId, target.dataset.moduleId, target.files)) {
+ refreshToolboxView(target);
+ }
+ }
+ if (target.dataset.action === "link-toolbox") {
+ linkToolboxToGame(target.dataset.gameId, target.value);
+ openDrawer(target.dataset.gameId);
+ }
+ if (target.dataset.action === "toggle-mhwilds-option") {
+ const { category, filterKey, value } = target.dataset;
+ const values = new Set(mhwildsState.filters[category][filterKey]);
+ if (target.checked) values.add(value);
+ else values.delete(value);
+ mhwildsState.filters[category][filterKey] = [...values];
+ target.closest(".filter-chip")?.classList.toggle("active", target.checked);
+ refreshMhwildsResults(category);
+ }
+ if (target.dataset.action === "import-toolbox" && target.files[0]) {
+ try {
+ const imported = await importToolbox(target.files[0]);
+ if (target.dataset.gameId && imported) {
+ linkToolboxToGame(target.dataset.gameId, imported.id);
+ openDrawer(target.dataset.gameId);
+ } else {
+ rerender();
+ }
+ } catch (error) {
+ showConfirmModal({
+ title: "Import impossible",
+ message: error.message,
+ confirmLabel: "Compris",
+ cancelLabel: "Fermer",
+ danger: true
+ });
+ }
+ }
+ if (target.dataset.action === "import-all-toolboxes" && target.files[0]) {
+ try {
+ if (await importAllToolboxes(target.files[0])) rerender();
+ } catch (error) {
+ showConfirmModal({
+ title: "Import global impossible",
+ message: error.message,
+ confirmLabel: "Compris",
+ cancelLabel: "Fermer",
+ danger: true
+ });
+ }
+ }
+});
+
+document.addEventListener("paste", async (event) => {
+ const target = event.target.closest("[data-action='paste-screenshot']");
+ if (!target) return;
+
+ const files = [...(event.clipboardData?.items || [])]
+ .filter((item) => item.type.startsWith("image/"))
+ .map((item) => item.getAsFile())
+ .filter(Boolean);
+
+ if (!files.length) return;
+
+ event.preventDefault();
+ target.textContent = "Coller une image ici";
+ if (await addScreenshotFiles(target.dataset.toolboxId, target.dataset.moduleId, files)) {
+ refreshToolboxView(target);
+ }
+});
+
+document.addEventListener("submit", (event) => {
+ const form = event.target.closest("[data-action='add-check-item']");
+ if (!form) return;
+ event.preventDefault();
+ const label = new FormData(form).get("label")?.trim();
+ if (!label) return;
+ const qtyTarget = parsePositiveInt(new FormData(form).get("qty"), 1);
+ const data = normalizeChecklistData(getModuleData(form.dataset.toolboxId, form.dataset.moduleId, { items: [] }));
+ data.items.push({ id: uid("item"), label, qtyTarget, qtyCurrent: 0 });
+ setModuleData(form.dataset.toolboxId, form.dataset.moduleId, data);
+ form.reset();
+ refreshToolboxView(form);
+});
+
+document.addEventListener("input", (event) => {
+ const mhwildsNameInput = event.target.closest("[data-action='set-mhwilds-name']");
+ if (mhwildsNameInput) {
+ const category = mhwildsNameInput.dataset.category;
+ mhwildsState.filters[category].name = mhwildsNameInput.value;
+ refreshMhwildsResults(category);
+ return;
+ }
+
+ const target = event.target.closest("[data-action='save-note']");
+ if (!target) return;
+ setModuleData(target.dataset.toolboxId, target.dataset.moduleId, { text: target.value });
+});
+
+window.addEventListener("hashchange", rerender);
+rerender();
diff --git a/website/src/styles.css b/website/src/styles.css
new file mode 100644
index 0000000..7c6ef23
--- /dev/null
+++ b/website/src/styles.css
@@ -0,0 +1,2345 @@
+:root {
+ color-scheme: dark;
+
+ --color-bg-page: #070913;
+ --color-bg-deep: #050711;
+ --color-bg-sidebar: #0b0e1b;
+ --color-bg-surface: #101426;
+ --color-bg-surface-alt: #151a30;
+ --color-bg-elevated: #1a2038;
+ --color-bg-hover: #202745;
+
+ --color-primary: #8b5cf6;
+ --color-primary-hover: #9f7aea;
+ --color-primary-active: #7347dc;
+ --color-primary-soft: rgba(139, 92, 246, 0.14);
+ --color-primary-border: rgba(139, 92, 246, 0.45);
+
+ --color-secondary: #3b82f6;
+ --color-secondary-soft: rgba(59, 130, 246, 0.14);
+ --color-accent-cyan: #22d3ee;
+ --color-accent-pink: #d946ef;
+ --color-accent-indigo: #6366f1;
+
+ --color-text-primary: #f5f7ff;
+ --color-text-secondary: #b4bdd3;
+ --color-text-muted: #7d879f;
+ --color-text-disabled: #555e73;
+ --color-text-inverse: #080a13;
+
+ --color-border: rgba(150, 165, 205, 0.14);
+ --color-border-hover: rgba(150, 165, 205, 0.28);
+ --color-border-strong: rgba(167, 139, 250, 0.42);
+
+ --color-success: #34d399;
+ --color-success-soft: rgba(52, 211, 153, 0.13);
+ --color-warning: #fbbf24;
+ --color-warning-soft: rgba(251, 191, 36, 0.13);
+ --color-danger: #fb7185;
+ --color-danger-soft: rgba(251, 113, 133, 0.13);
+ --color-info: #38bdf8;
+ --color-info-soft: rgba(56, 189, 248, 0.13);
+
+ --gradient-brand: linear-gradient(135deg, #8b5cf6 0%, #6366f1 45%, #3b82f6 100%);
+ --gradient-nebula: linear-gradient(
+ 135deg,
+ rgba(139, 92, 246, 0.28),
+ rgba(59, 130, 246, 0.18),
+ rgba(217, 70, 239, 0.12)
+ );
+ --gradient-page:
+ radial-gradient(circle at 20% 10%, rgba(124, 58, 237, 0.16), transparent 34%),
+ radial-gradient(circle at 85% 20%, rgba(37, 99, 235, 0.12), transparent 30%),
+ radial-gradient(circle at 55% 90%, rgba(217, 70, 239, 0.08), transparent 35%),
+ #070913;
+
+ --font-size-xs: 0.75rem;
+ --font-size-sm: 0.875rem;
+ --font-size-base: 1rem;
+ --font-size-lg: 1.125rem;
+ --font-size-xl: 1.25rem;
+ --font-size-2xl: 1.5rem;
+ --font-size-3xl: 2rem;
+ --font-size-4xl: 2.5rem;
+
+ --space-2: 0.5rem;
+ --space-3: 0.75rem;
+ --space-4: 1rem;
+ --space-5: 1.25rem;
+ --space-6: 1.5rem;
+ --space-8: 2rem;
+ --space-10: 2.5rem;
+ --space-12: 3rem;
+
+ --radius-sm: 6px;
+ --radius-md: 10px;
+ --radius-lg: 14px;
+ --radius-xl: 18px;
+ --radius-pill: 999px;
+
+ --shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.22);
+ --shadow-md: 0 12px 30px rgba(0, 0, 0, 0.3);
+ --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.42);
+ --shadow-primary: 0 0 28px rgba(139, 92, 246, 0.22);
+ --shadow-secondary: 0 0 28px rgba(59, 130, 246, 0.18);
+
+ --duration-fast: 120ms;
+ --duration-normal: 180ms;
+ --ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ min-height: 100%;
+ background: var(--color-bg-page);
+}
+
+body {
+ min-height: 100vh;
+ margin: 0;
+ color: var(--color-text-primary);
+ background: var(--gradient-page);
+ font-family: Inter, "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
+ line-height: 1.55;
+}
+
+body::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ z-index: -1;
+ pointer-events: none;
+ opacity: 0.23;
+ background-image:
+ radial-gradient(circle, rgba(255, 255, 255, 0.52) 1px, transparent 1px),
+ radial-gradient(circle, rgba(139, 92, 246, 0.38) 1px, transparent 1px);
+ background-position: 0 0, 35px 60px;
+ background-size: 90px 90px, 140px 140px;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+button,
+.button,
+select,
+input,
+textarea,
+.import-button {
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(21, 26, 48, 0.92);
+ color: var(--color-text-primary);
+ font: inherit;
+ transition:
+ transform var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ background-color var(--duration-fast) var(--ease-standard),
+ box-shadow var(--duration-fast) var(--ease-standard);
+}
+
+button,
+.button,
+.import-button {
+ display: inline-flex;
+ min-height: 42px;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 0 18px;
+ cursor: pointer;
+}
+
+button:hover,
+.button:hover,
+.import-button:hover {
+ border-color: var(--color-border-hover);
+ background: var(--color-bg-hover);
+}
+
+button:active,
+.button:active,
+.import-button:active {
+ transform: translateY(0);
+}
+
+:focus-visible {
+ outline: 2px solid var(--color-accent-cyan);
+ outline-offset: 3px;
+}
+
+.filter-options::-webkit-scrollbar,
+.drawer-panel::-webkit-scrollbar,
+.damage-table-wrap::-webkit-scrollbar,
+.legacy-scrollbar::-webkit-scrollbar {
+ background-color: transparent;
+ width: 6px;
+ height: 6px;
+ border-radius: 0;
+}
+
+.filter-options::-webkit-scrollbar-track,
+.drawer-panel::-webkit-scrollbar-track,
+.damage-table-wrap::-webkit-scrollbar-track,
+.legacy-scrollbar::-webkit-scrollbar-track {
+ background-color: transparent;
+ border-radius: 0;
+ box-shadow: none;
+}
+
+.filter-options::-webkit-scrollbar-thumb,
+.drawer-panel::-webkit-scrollbar-thumb,
+.damage-table-wrap::-webkit-scrollbar-thumb,
+.legacy-scrollbar::-webkit-scrollbar-thumb {
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.5, rgb(79, 26, 114)), color-stop(1, rgb(44, 1, 135)));
+ border-radius: 10px;
+}
+
+.primary {
+ border-color: transparent;
+ background: var(--gradient-brand);
+ box-shadow: 0 8px 22px rgba(99, 102, 241, 0.22);
+ color: #fff;
+ font-weight: 700;
+}
+
+.primary:hover {
+ border-color: transparent;
+ filter: brightness(1.08);
+ transform: translateY(-1px);
+ box-shadow: 0 10px 28px rgba(139, 92, 246, 0.3);
+}
+
+.ghost {
+ border-color: transparent;
+ background: transparent;
+ color: var(--color-text-secondary);
+}
+
+.danger {
+ color: var(--color-danger);
+}
+
+.danger:hover {
+ border-color: rgba(251, 113, 133, 0.32);
+ background: var(--color-danger-soft);
+ color: #fff;
+}
+
+.app-shell {
+ display: grid;
+ grid-template-columns: 248px minmax(0, 1fr);
+ min-height: 100vh;
+}
+
+.sidebar {
+ position: sticky;
+ top: 0;
+ display: flex;
+ height: 100vh;
+ flex-direction: column;
+ gap: var(--space-5);
+ padding: var(--space-5);
+ border-right: 1px solid var(--color-border);
+ background: rgba(11, 14, 27, 0.82);
+ backdrop-filter: blur(18px);
+ box-shadow: var(--shadow-md);
+}
+
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ font-size: var(--font-size-lg);
+ font-weight: 800;
+}
+
+.brand-mark {
+ display: block;
+ width: 34px;
+ height: 34px;
+ flex: 0 0 auto;
+ background: var(--gradient-brand);
+ filter: drop-shadow(0 0 16px rgba(139, 92, 246, 0.28));
+ mask: url("/static/icons/controller.svg") center / contain no-repeat;
+ -webkit-mask: url("/static/icons/controller.svg") center / contain no-repeat;
+ transition: transform 0.8s var(--ease-standard), filter var(--duration-normal) var(--ease-standard);
+}
+
+.brand:hover .brand-mark {
+ filter: drop-shadow(0 0 22px rgba(139, 92, 246, 0.42));
+ transform: rotate(360deg);
+}
+
+.nav {
+ display: grid;
+ gap: 8px;
+}
+
+.nav-item {
+ display: flex;
+ min-height: 42px;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 12px;
+ border: 1px solid transparent;
+ border-radius: var(--radius-md);
+ color: var(--color-text-secondary);
+ transition: var(--duration-normal) var(--ease-standard);
+}
+
+.nav-icon {
+ display: block;
+ width: 24px;
+ height: 24px;
+ flex: 0 0 auto;
+ background: var(--color-accent-cyan);
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 20px 20px;
+ -webkit-mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-size: 20px 20px;
+}
+
+.nav-icon-home {
+ mask-image: url("/static/icons/home.svg");
+ -webkit-mask-image: url("/static/icons/home.svg");
+}
+
+.nav-icon-toolbox {
+ mask-image: url("/static/icons/toolbox.svg");
+ -webkit-mask-image: url("/static/icons/toolbox.svg");
+}
+
+.nav-icon-controller {
+ mask-image: url("/static/icons/controller.svg");
+ -webkit-mask-image: url("/static/icons/controller.svg");
+}
+
+.nav-item strong {
+ color: inherit;
+ font-size: var(--font-size-sm);
+ font-weight: 700;
+}
+
+.nav-item:hover {
+ background: var(--color-bg-hover);
+ color: var(--color-text-primary);
+}
+
+.nav-item.active {
+ border-color: var(--color-primary-border);
+ background: var(--color-primary-soft);
+ box-shadow: inset 3px 0 0 var(--color-primary);
+ color: var(--color-text-primary);
+}
+
+.sidebar-note {
+ margin-top: auto;
+ padding: var(--space-4);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.62);
+}
+
+.sidebar-note p {
+ margin: 10px 0 0;
+ font-size: var(--font-size-sm);
+}
+
+.sidebar-storage-actions {
+ display: flex;
+ gap: var(--space-2);
+ margin-top: var(--space-4);
+}
+
+.sidebar-action-button {
+ display: inline-flex;
+ width: 40px;
+ min-width: 40px;
+ min-height: 40px;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(21, 26, 48, 0.92);
+ color: var(--color-text-primary);
+ cursor: pointer;
+}
+
+.sidebar-action-button:hover {
+ border-color: var(--color-border-hover);
+ background: var(--color-bg-hover);
+}
+
+.content-shell {
+ display: flex;
+ min-height: 100vh;
+ min-width: 0;
+ flex-direction: column;
+}
+
+.topbar {
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ display: flex;
+ min-height: 68px;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-4);
+ padding: 0 var(--space-8);
+ border-bottom: 1px solid var(--color-border);
+ background: rgba(7, 9, 19, 0.78);
+ backdrop-filter: blur(18px);
+}
+
+.topbar strong {
+ font-size: var(--font-size-lg);
+}
+
+.topbar .eyebrow {
+ margin-bottom: 2px;
+}
+
+.topbar-actions {
+ display: flex;
+ gap: 10px;
+}
+
+.toolbox-icon-button {
+ width: 42px;
+ min-width: 42px;
+ padding: 0;
+}
+
+.toolbox-icon-button img {
+ width: 21px;
+ height: 21px;
+ object-fit: contain;
+}
+
+main {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ width: min(1600px, calc(100% - 64px));
+ margin: 0 auto;
+ padding: var(--space-8) 0 var(--space-12);
+}
+
+.hero,
+.game-hero {
+ position: relative;
+ display: grid;
+ min-height: 360px;
+ align-items: end;
+ gap: var(--space-6);
+ overflow: hidden;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ box-shadow: var(--shadow-md);
+ padding: var(--space-10);
+}
+
+.hero::after,
+.game-hero::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ background:
+ linear-gradient(135deg, rgba(5, 7, 17, 0.1), rgba(5, 7, 17, 0.52)),
+ radial-gradient(circle at 82% 16%, rgba(34, 211, 238, 0.18), transparent 30%);
+}
+
+.hero > *,
+.game-hero > * {
+ position: relative;
+ z-index: 1;
+}
+
+.hero {
+ grid-template-columns: minmax(0, 1fr) minmax(360px, 480px);
+ background:
+ var(--gradient-nebula),
+ linear-gradient(135deg, rgba(16, 20, 38, 0.98), rgba(5, 7, 17, 0.96));
+}
+
+.game-hero {
+ grid-template-columns: 1fr auto;
+ color: white;
+}
+
+h1,
+h2,
+p {
+ margin-top: 0;
+}
+
+h1 {
+ max-width: 820px;
+ margin-bottom: 14px;
+ font-size: clamp(2rem, 4vw, var(--font-size-4xl));
+ line-height: 1.05;
+}
+
+h2 {
+ margin-bottom: 10px;
+ font-size: var(--font-size-xl);
+}
+
+p,
+li,
+small,
+span {
+ color: var(--color-text-secondary);
+}
+
+.eyebrow {
+ margin-bottom: 10px;
+ color: var(--color-accent-cyan);
+ font-size: var(--font-size-xs);
+ font-weight: 800;
+ letter-spacing: 0;
+ text-transform: uppercase;
+}
+
+.actions,
+.card-actions,
+.toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+
+.toolbar-stack {
+ align-items: flex-start;
+ flex-direction: column;
+}
+
+.toolbar-stack > div {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+
+.hero-panel {
+ padding: var(--space-5);
+ border: 1px solid rgba(165, 180, 252, 0.14);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.72);
+ backdrop-filter: blur(18px);
+}
+
+.hero-panel span {
+ display: block;
+ background: var(--gradient-brand);
+ background-clip: text;
+ color: transparent;
+ font-size: 56px;
+ font-weight: 800;
+ line-height: 1;
+}
+
+.home-visual {
+ display: grid;
+ align-self: center;
+ justify-self: stretch;
+ width: 100%;
+ height: 100%;
+ min-height: 320px;
+ place-items: center;
+}
+
+.home-visual img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ max-height: 520px;
+ object-fit: cover;
+ border-radius: var(--radius-lg);
+ filter: drop-shadow(0 22px 36px rgba(0, 0, 0, 0.34));
+}
+
+.origin-section {
+ display: grid;
+ grid-template-columns: minmax(0, 1.1fr) minmax(300px, 0.65fr);
+ gap: var(--space-6);
+ margin-top: var(--space-6);
+ padding: var(--space-6);
+ border: 1px solid rgba(165, 180, 252, 0.14);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.42);
+ box-shadow: var(--shadow-sm);
+}
+
+.origin-copy {
+ min-width: 0;
+ padding-right: var(--space-6);
+ border-right: 2px solid rgba(34, 211, 238, 0.66);
+}
+
+.home-dialogue {
+ position: relative;
+ display: grid;
+ gap: 8px;
+ margin-top: var(--space-4);
+}
+
+.dialogue-line {
+ width: fit-content;
+ max-width: 100%;
+ margin: 0;
+ padding: 8px 11px;
+ border: 1px solid rgba(165, 180, 252, 0.14);
+ border-radius: 8px;
+ color: var(--color-text-primary);
+ font-size: var(--font-size-sm);
+ line-height: 1.35;
+}
+
+.dialogue-line-user {
+ justify-self: end;
+ background: linear-gradient(135deg, rgba(124, 58, 237, 0.28), rgba(37, 99, 235, 0.18));
+}
+
+.dialogue-line-app {
+ justify-self: start;
+ background: rgba(7, 10, 24, 0.48);
+}
+
+.dialogue-line i {
+ color: var(--color-text-muted);
+ font-style: normal;
+}
+
+.dialogue-caption {
+ display: block;
+ margin-top: 4px;
+ color: var(--color-text-muted);
+ font-size: var(--font-size-xs);
+ font-style: italic;
+ text-align: right;
+}
+
+.home-stats {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+ align-self: start;
+}
+
+.hero-stats {
+ align-self: center;
+ justify-self: end;
+ width: min(420px, 100%);
+}
+
+.home-stats article {
+ min-height: 118px;
+ padding: var(--space-4);
+ border: 1px solid rgba(165, 180, 252, 0.14);
+ border-radius: var(--radius-md);
+ background:
+ linear-gradient(145deg, rgba(34, 211, 238, 0.08), transparent 52%),
+ rgba(7, 10, 24, 0.52);
+}
+
+.home-stats strong {
+ display: block;
+ margin-bottom: 10px;
+ background: var(--gradient-brand);
+ background-clip: text;
+ color: transparent;
+ font-size: 44px;
+ font-weight: 900;
+ line-height: 0.95;
+}
+
+.home-stats span {
+ display: block;
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-sm);
+ font-weight: 700;
+ line-height: 1.35;
+}
+
+.section-grid,
+.cards,
+.info-grid,
+.modules {
+ display: grid;
+ gap: var(--space-4);
+ margin-top: var(--space-6);
+}
+
+.section-grid,
+.info-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.cards {
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+}
+
+.feature,
+.info-panel,
+.module,
+.empty,
+.card {
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.88);
+ box-shadow: var(--shadow-sm);
+}
+
+.feature,
+.info-panel,
+.empty {
+ padding: var(--space-5);
+}
+
+.feature,
+.card,
+.module,
+.info-panel {
+ transition:
+ transform var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ background-color var(--duration-fast) var(--ease-standard);
+}
+
+.feature:hover,
+.card:hover,
+.module:hover,
+.info-panel:hover {
+ transform: translateY(-2px);
+ border-color: var(--color-border-hover);
+ background: rgba(21, 26, 48, 0.96);
+}
+
+.feature {
+ display: grid;
+ gap: 8px;
+}
+
+.feature strong {
+ color: var(--color-text-primary);
+}
+
+.page-heading,
+.toolbox-head {
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ gap: var(--space-5);
+}
+
+.card {
+ overflow: hidden;
+}
+
+.card-cover {
+ min-height: 124px;
+ border-bottom: 1px solid var(--color-border);
+}
+
+.card-body {
+ padding: var(--space-5);
+}
+
+.card-actions {
+ margin-top: var(--space-5);
+}
+
+.toolbox-card {
+ display: flex;
+ min-height: 292px;
+ flex-direction: column;
+}
+
+.toolbox-card .card-cover {
+ flex: 0 0 124px;
+ height: 124px;
+ min-height: 124px;
+}
+
+.toolbox-card .card-body {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+.toolbox-card .card-actions {
+ margin-top: auto;
+ padding-top: var(--space-5);
+}
+
+.toolbox-page {
+ display: flex;
+ min-height: calc(100vh - 68px - var(--space-8) - var(--space-12));
+ flex: 1;
+ flex-direction: column;
+ gap: var(--space-4);
+}
+
+.toolbox-embedded {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-4);
+}
+
+.storage-help-card {
+ position: relative;
+ min-height: 292px;
+ overflow: hidden;
+ border-color: rgba(34, 211, 238, 0.22);
+ background:
+ linear-gradient(135deg, rgba(34, 211, 238, 0.1), transparent 38%),
+ rgba(10, 13, 29, 0.84);
+}
+
+.storage-help-card::after {
+ content: "";
+ position: absolute;
+ inset: 0 auto 0 0;
+ width: 3px;
+ background: var(--gradient-brand);
+}
+
+.storage-help-card .card-body {
+ display: flex;
+ min-height: 100%;
+ flex-direction: column;
+ padding: 18px;
+}
+
+.storage-help-heading {
+ display: grid;
+ grid-template-columns: 36px minmax(0, 1fr);
+ gap: 10px;
+ align-items: center;
+ margin-bottom: 12px;
+}
+
+.storage-help-mark {
+ display: grid;
+ width: 36px;
+ height: 36px;
+ place-items: center;
+ border: 1px solid rgba(34, 211, 238, 0.32);
+ border-radius: var(--radius-md);
+ background: rgba(34, 211, 238, 0.1);
+ color: var(--color-accent-cyan);
+ box-shadow: 0 0 22px rgba(34, 211, 238, 0.12);
+}
+
+.storage-help-mark::before {
+ content: "";
+ width: 19px;
+ height: 19px;
+ background: currentColor;
+ mask: url("/static/icons/save.svg") center / contain no-repeat;
+ -webkit-mask: url("/static/icons/save.svg") center / contain no-repeat;
+}
+
+.storage-help-card h2 {
+ margin: 0;
+ font-size: var(--font-size-lg);
+ line-height: 1.2;
+}
+
+.storage-help-card .eyebrow {
+ color: var(--color-accent-cyan);
+}
+
+.storage-help-intro {
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-xs);
+ line-height: 1.45;
+}
+
+.storage-help-card p,
+.storage-help-card ul {
+ margin: 0;
+}
+
+.storage-help-list {
+ display: grid;
+ gap: 7px;
+ margin-top: 18px;
+ padding: 10px 0 0;
+ list-style: none;
+}
+
+.storage-help-list li {
+ display: grid;
+ grid-template-columns: 22px minmax(0, 1fr);
+ gap: 8px;
+ align-items: start;
+ padding: 8px 9px;
+ border: 1px solid rgba(150, 165, 205, 0.12);
+ border-radius: var(--radius-md);
+ background: rgba(7, 10, 24, 0.45);
+}
+
+.storage-help-list span {
+ display: grid;
+ width: 18px;
+ height: 18px;
+ place-items: center;
+ border-radius: var(--radius-sm);
+ background: rgba(139, 92, 246, 0.18);
+ color: var(--color-text-primary);
+ font-size: var(--font-size-xs);
+ font-weight: 800;
+}
+
+.storage-help-list p {
+ align-self: center;
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-xs);
+ line-height: 1.32;
+}
+
+.storage-quota {
+ display: grid;
+ gap: var(--space-3);
+ margin-top: auto;
+ padding: var(--space-4);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(10, 13, 29, 0.78);
+ box-shadow: var(--shadow-sm);
+}
+
+.toolbox-page > .storage-quota,
+.drawer-content > .storage-quota {
+ margin-top: auto;
+}
+
+.storage-quota > div:first-child {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-4);
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-sm);
+}
+
+.storage-quota strong {
+ color: var(--color-text-primary);
+ font-size: var(--font-size-sm);
+}
+
+.storage-quota-track {
+ width: 100%;
+ height: 9px;
+ overflow: hidden;
+ border: 1px solid rgba(150, 165, 205, 0.14);
+ border-radius: var(--radius-pill);
+ background: rgba(5, 7, 17, 0.82);
+}
+
+.storage-quota-track span {
+ display: block;
+ height: 100%;
+ border-radius: inherit;
+ background: var(--gradient-brand);
+ box-shadow: 0 0 18px rgba(99, 102, 241, 0.32);
+ transition: width var(--duration-normal) var(--ease-standard);
+}
+
+.storage-quota-warning {
+ border-color: rgba(251, 191, 36, 0.34);
+}
+
+.storage-quota-warning .storage-quota-track span {
+ background: linear-gradient(135deg, #fbbf24, #f97316);
+}
+
+.storage-quota-danger {
+ border-color: rgba(251, 113, 133, 0.42);
+}
+
+.storage-quota-danger .storage-quota-track span {
+ background: linear-gradient(135deg, #fb7185, #d946ef);
+}
+
+.card-icon-button {
+ width: 42px;
+ min-width: 42px;
+ padding: 0;
+}
+
+.ui-icon {
+ display: block;
+ width: 20px;
+ height: 20px;
+ background: currentColor;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ -webkit-mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-size: contain;
+}
+
+.ui-icon-open {
+ mask-image: url("/static/icons/open.svg");
+ -webkit-mask-image: url("/static/icons/open.svg");
+}
+
+.ui-icon-save {
+ mask-image: url("/static/icons/save.svg");
+ -webkit-mask-image: url("/static/icons/save.svg");
+}
+
+.ui-icon-export {
+ mask-image: url("/static/icons/export.svg");
+ -webkit-mask-image: url("/static/icons/export.svg");
+}
+
+.ui-icon-import {
+ mask-image: url("/static/icons/import.svg");
+ -webkit-mask-image: url("/static/icons/import.svg");
+}
+
+.ui-icon-link {
+ mask-image: url("/static/icons/link.svg");
+ -webkit-mask-image: url("/static/icons/link.svg");
+}
+
+.ui-icon-rows {
+ mask-image: url("/static/icons/rows.svg");
+ -webkit-mask-image: url("/static/icons/rows.svg");
+}
+
+.ui-icon-columns {
+ mask-image: url("/static/icons/columns.svg");
+ -webkit-mask-image: url("/static/icons/columns.svg");
+}
+
+.ui-icon-close {
+ mask-image: url("/static/icons/close.svg");
+ -webkit-mask-image: url("/static/icons/close.svg");
+}
+
+.ui-icon-rubber {
+ mask-image: url("/static/icons/rubber.svg");
+ -webkit-mask-image: url("/static/icons/rubber.svg");
+}
+
+.ui-icon-trash {
+ mask-image: url("/static/icons/trashcan.svg");
+ -webkit-mask-image: url("/static/icons/trashcan.svg");
+}
+
+.game-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: var(--space-4);
+ margin-top: var(--space-6);
+}
+
+.game-card .card-cover {
+ min-height: 170px;
+}
+
+.game-card-cover {
+ position: relative;
+ overflow: hidden;
+ background:
+ var(--game-cover),
+ rgba(5, 7, 17, 0.72);
+}
+
+.toolbox-card-cover {
+ position: relative;
+ overflow: hidden;
+ background:
+ var(--game-cover),
+ rgba(5, 7, 17, 0.72);
+}
+
+.game-card-cover img,
+.toolbox-card-cover img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ min-height: inherit;
+ object-fit: cover;
+}
+
+.badge {
+ display: inline-flex;
+ min-height: 24px;
+ align-items: center;
+ gap: 6px;
+ border-radius: var(--radius-pill);
+ background: var(--color-primary-soft);
+ color: #b69cff;
+ font-size: var(--font-size-xs);
+ font-weight: 700;
+ padding: 3px 9px;
+}
+
+.toolbox-head {
+ padding: var(--space-6);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: rgba(16, 20, 38, 0.76);
+ backdrop-filter: blur(18px);
+}
+
+.toolbox-title {
+ width: fit-content;
+ max-width: 100%;
+ padding: 3px 6px;
+ border-radius: var(--radius-sm);
+ cursor: text;
+}
+
+.toolbox-title:focus {
+ background: rgba(7, 10, 24, 0.72);
+ outline: 1px solid rgba(34, 211, 238, 0.72);
+ outline-offset: 3px;
+}
+
+.modules-toolbar {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: var(--space-4);
+}
+
+.modules {
+ align-items: start;
+}
+
+.modules[data-layout-cols="1"] {
+ grid-template-columns: 1fr;
+}
+
+.modules[data-layout-cols="2"] {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.module-column {
+ display: grid;
+ gap: var(--space-4);
+ align-content: start;
+}
+
+.module {
+ overflow: hidden;
+}
+
+.module[draggable="true"] {
+ cursor: grab;
+}
+
+.module.is-dragging {
+ cursor: grabbing;
+ opacity: 0.58;
+ transform: scale(0.99);
+}
+
+.module.is-drop-target {
+ border-color: rgba(34, 211, 238, 0.72);
+ box-shadow:
+ var(--shadow-sm),
+ inset 0 3px 0 rgba(34, 211, 238, 0.8);
+}
+
+.module.is-drop-target.drop-after {
+ box-shadow:
+ var(--shadow-sm),
+ inset 0 -3px 0 rgba(34, 211, 238, 0.8);
+}
+
+.module header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-3);
+ padding: var(--space-4);
+ border-bottom: 1px solid var(--color-border);
+}
+
+.module header > div {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.module header h2 {
+ margin: 0;
+ font-size: 17px;
+}
+
+.layout-switch {
+ display: inline-grid;
+ grid-template-columns: repeat(2, 38px);
+ gap: 4px;
+ padding: 4px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(5, 7, 17, 0.48);
+}
+
+.layout-switch button {
+ min-height: 34px;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border-color: transparent;
+ background: transparent;
+ color: var(--color-text-muted);
+ font-weight: 900;
+}
+
+.layout-switch button.active {
+ background: var(--gradient-brand);
+ color: white;
+ box-shadow: var(--shadow-primary);
+}
+
+.module-drag-handle {
+ display: grid;
+ width: 18px;
+ height: 34px;
+ flex: 0 0 18px;
+ place-items: center;
+ cursor: grab;
+ opacity: 0.62;
+}
+
+.module-drag-handle::before {
+ content: "";
+ width: 4px;
+ height: 20px;
+ background:
+ radial-gradient(circle, currentColor 1.6px, transparent 1.8px) 0 0 / 4px 6px,
+ radial-gradient(circle, currentColor 1.6px, transparent 1.8px) 8px 0 / 4px 6px;
+ color: var(--color-text-muted);
+}
+
+.module:hover .module-drag-handle,
+.module:focus-within .module-drag-handle {
+ opacity: 1;
+}
+
+.module-title {
+ min-width: 80px;
+ max-width: 100%;
+ padding: 4px 6px;
+ border-radius: var(--radius-sm);
+ cursor: text;
+}
+
+.module-title:focus {
+ background: rgba(7, 10, 24, 0.72);
+ outline: 1px solid rgba(34, 211, 238, 0.72);
+ outline-offset: 2px;
+}
+
+.module-delete-button {
+ width: 38px;
+ min-width: 38px;
+ padding: 0;
+}
+
+.module-icon {
+ display: grid;
+ width: 34px;
+ height: 34px;
+ place-items: center;
+ border-radius: var(--radius-md);
+ background: var(--gradient-brand);
+ box-shadow: var(--shadow-primary);
+ color: white;
+}
+
+.module-icon-svg {
+ display: block;
+ width: 19px;
+ height: 19px;
+ background: white;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ -webkit-mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-size: contain;
+}
+
+.module-icon-notepad {
+ mask-image: url("/static/icons/notepad.svg");
+ -webkit-mask-image: url("/static/icons/notepad.svg");
+}
+
+.module-icon-checklist {
+ mask-image: url("/static/icons/checklist.svg");
+ -webkit-mask-image: url("/static/icons/checklist.svg");
+}
+
+.module-icon-picture {
+ mask-image: url("/static/icons/picture.svg");
+ -webkit-mask-image: url("/static/icons/picture.svg");
+}
+
+.notepad {
+ display: block;
+ width: calc(100% - 32px);
+ min-height: 240px;
+ margin: var(--space-4);
+ padding: var(--space-4);
+ resize: vertical;
+ line-height: 1.6;
+ background: rgba(5, 7, 17, 0.56);
+}
+
+.inline-form,
+.field {
+ display: grid;
+ gap: 10px;
+ padding: var(--space-4);
+}
+
+.inline-form {
+ grid-template-columns: 1fr auto;
+}
+
+.checklist-add-form {
+ grid-template-columns: minmax(0, 1fr) 76px auto;
+}
+
+.checklist-qty-input {
+ padding-inline: 10px;
+ text-align: center;
+}
+
+input,
+select,
+textarea {
+ min-height: 44px;
+ padding: 0 14px;
+ outline: none;
+}
+
+textarea {
+ padding-block: 14px;
+}
+
+input::placeholder,
+textarea::placeholder {
+ color: var(--color-text-muted);
+}
+
+input:focus,
+select:focus,
+textarea:focus {
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16);
+}
+
+.checklist {
+ display: grid;
+ gap: 8px;
+ margin: 0;
+ padding: 0 var(--space-4) var(--space-4);
+ list-style: none;
+}
+
+.checklist-item {
+ display: grid;
+ grid-template-columns: 1fr 42px;
+ gap: 8px;
+ align-items: center;
+}
+
+.checklist-item-main {
+ display: flex;
+ min-height: 42px;
+ align-items: center;
+ gap: 10px;
+ padding: 0 12px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(5, 7, 17, 0.44);
+}
+
+.checklist input[type="checkbox"] {
+ flex: 0 0 auto;
+ width: 20px;
+ min-height: 20px;
+ height: 20px;
+ accent-color: var(--color-primary);
+}
+
+.checklist-item.is-complete .checklist-item-main > span {
+ color: var(--color-text-muted);
+ text-decoration: line-through;
+}
+
+.checklist-qty-controls {
+ display: inline-flex;
+ flex: 0 0 auto;
+ align-items: center;
+ gap: 6px;
+}
+
+.checklist-qty-controls button {
+ width: 28px;
+ min-width: 28px;
+ min-height: 28px;
+ padding: 0;
+ line-height: 1;
+}
+
+.checklist-qty-controls small {
+ min-width: 42px;
+ color: var(--color-text-secondary);
+ text-align: center;
+}
+
+.dropzone {
+ display: grid;
+ min-height: 74px;
+ margin: var(--space-4);
+ place-items: center;
+ border: 1px dashed rgba(139, 92, 246, 0.52);
+ border-radius: var(--radius-lg);
+ background: var(--color-primary-soft);
+ color: var(--color-text-secondary);
+ cursor: pointer;
+}
+
+.dropzone:hover {
+ border-color: var(--color-accent-cyan);
+ background: rgba(34, 211, 238, 0.1);
+ box-shadow: 0 0 30px rgba(34, 211, 238, 0.12);
+}
+
+.dropzone.is-drag-over {
+ border-color: var(--color-accent-cyan);
+ background: rgba(34, 211, 238, 0.14);
+ box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.12);
+}
+
+.paste-target {
+ min-height: 46px;
+ margin: 0 var(--space-4) var(--space-4);
+ padding: 12px 14px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(5, 7, 17, 0.44);
+ color: var(--color-text-muted);
+}
+
+.paste-target:focus {
+ border-color: var(--color-primary);
+ color: var(--color-text-secondary);
+ outline: none;
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16);
+}
+
+.shots {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+ gap: var(--space-3);
+ padding: 0 var(--space-4) var(--space-4);
+}
+
+.shots figure {
+ position: relative;
+ margin: 0;
+ padding: 8px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(5, 7, 17, 0.38);
+}
+
+.shot-preview {
+ display: block;
+ width: 100%;
+ min-height: 0;
+ padding: 0;
+ border: 0;
+ border-radius: var(--radius-md);
+ background: transparent;
+}
+
+.shot-preview:hover {
+ transform: none;
+ box-shadow: 0 0 0 2px rgba(34, 211, 238, 0.28);
+}
+
+.shots img {
+ display: block;
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ object-fit: cover;
+ border-radius: var(--radius-md);
+ background: var(--color-bg-deep);
+}
+
+.shot-delete-button {
+ width: 38px;
+ min-width: 38px;
+ padding: 0;
+}
+
+.screenshot-viewer-root {
+ position: fixed;
+ inset: 0;
+ z-index: 110;
+ display: grid;
+ place-items: center;
+ padding: var(--space-5);
+}
+
+.screenshot-viewer-backdrop {
+ position: absolute;
+ inset: 0;
+ background: rgba(2, 3, 9, 0.64);
+ backdrop-filter: blur(4px);
+}
+
+.screenshot-viewer {
+ position: relative;
+ display: grid;
+ width: min(1120px, calc(100vw - 32px));
+ max-height: calc(100vh - 48px);
+ gap: var(--space-4);
+ padding: var(--space-4);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: rgba(16, 20, 38, 0.96);
+ box-shadow: var(--shadow-lg);
+}
+
+.screenshot-viewer header {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: var(--space-4);
+}
+
+.screenshot-viewer img {
+ display: block;
+ max-width: 100%;
+ max-height: calc(100vh - 170px);
+ justify-self: center;
+ border-radius: var(--radius-md);
+ object-fit: contain;
+}
+
+.drawer[aria-hidden="true"] {
+ display: none;
+}
+
+.drawer-backdrop {
+ position: fixed;
+ inset: 0;
+ z-index: 40;
+ background: rgba(2, 3, 9, 0.42);
+ backdrop-filter: blur(2px);
+}
+
+.drawer-panel {
+ position: fixed;
+ inset: 0 0 0 auto;
+ z-index: 50;
+ width: min(720px, 94vw);
+ min-width: 360px;
+ max-width: 94vw;
+ overflow: auto;
+ border-left: 1px solid var(--color-border);
+ background: rgba(7, 9, 19, 0.96);
+ box-shadow: var(--shadow-lg);
+ padding: var(--space-5);
+}
+
+.drawer-content {
+ position: relative;
+ display: flex;
+ min-height: 100%;
+ flex-direction: column;
+ gap: var(--space-4);
+}
+
+.drawer-resize-handle {
+ position: absolute;
+ top: 50%;
+ left: -18px;
+ width: 14px;
+ height: 72px;
+ border-radius: var(--radius-pill);
+ cursor: ew-resize;
+ transform: translateY(-50%);
+}
+
+.drawer-resize-handle::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 5px;
+ width: 4px;
+ height: 100%;
+ border-radius: inherit;
+ background: var(--gradient-brand);
+ opacity: 0.72;
+}
+
+body.is-resizing-drawer,
+body.is-resizing-drawer * {
+ cursor: ew-resize !important;
+ user-select: none;
+}
+
+.drawer-panel > .drawer-content > header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: var(--space-4);
+ margin-bottom: var(--space-3);
+}
+
+.drawer-toolbox-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-2);
+ margin-top: var(--space-3);
+}
+
+.drawer-action-button {
+ display: inline-flex;
+ width: 40px;
+ min-width: 40px;
+ min-height: 40px;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(21, 26, 48, 0.92);
+ color: var(--color-text-primary);
+ cursor: pointer;
+}
+
+.drawer-action-button:hover {
+ border-color: var(--color-border-hover);
+ background: var(--color-bg-hover);
+}
+
+.drawer-action-button:disabled {
+ color: var(--color-text-disabled);
+ cursor: not-allowed;
+ opacity: 0.56;
+}
+
+.drawer-close-button {
+ width: 40px;
+ min-width: 40px;
+ padding: 0;
+}
+
+.drawer-panel .modules {
+ grid-template-columns: 1fr;
+}
+
+.confirm-modal-root {
+ position: fixed;
+ inset: 0;
+ z-index: 100;
+ display: grid;
+ place-items: center;
+ padding: var(--space-5);
+}
+
+.confirm-backdrop {
+ position: absolute;
+ inset: 0;
+ background: rgba(2, 3, 9, 0.62);
+ backdrop-filter: blur(6px);
+}
+
+.confirm-modal {
+ position: relative;
+ width: min(520px, calc(100vw - 32px));
+ max-height: calc(100vh - 48px);
+ overflow: auto;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: rgba(16, 20, 38, 0.96);
+ box-shadow: var(--shadow-lg);
+ padding: var(--space-5);
+}
+
+.confirm-modal h2 {
+ margin-bottom: var(--space-3);
+}
+
+.confirm-modal p {
+ margin-bottom: var(--space-6);
+}
+
+.confirm-modal footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+}
+
+.toolbox-create-modal form,
+.toolbox-link-modal form {
+ display: grid;
+ gap: var(--space-4);
+}
+
+.toolbox-create-modal .field,
+.toolbox-link-modal .field {
+ padding: 0;
+}
+
+.confirm-danger {
+ border-color: rgba(251, 113, 133, 0.34);
+ background: var(--color-danger);
+ color: #fff;
+ font-weight: 700;
+}
+
+.mhwilds-hero {
+ background:
+ linear-gradient(135deg, rgba(139, 92, 246, 0.86), rgba(99, 102, 241, 0.76), rgba(34, 211, 238, 0.58)),
+ var(--color-bg-surface);
+}
+
+.mhwilds-home-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(240px, 380px));
+ justify-content: center;
+ gap: var(--space-4);
+ margin-top: var(--space-6);
+}
+
+.mhwilds-home-card {
+ overflow: hidden;
+ padding: 0;
+ min-height: 230px;
+}
+
+.mhwilds-home-card img {
+ display: block;
+ width: 100%;
+ height: 120px;
+ object-fit: contain;
+ padding: var(--space-4);
+ border-bottom: 1px solid var(--color-border);
+ background: rgba(5, 7, 17, 0.28);
+}
+
+.mhwilds-home-card strong,
+.mhwilds-home-card span {
+ margin-inline: var(--space-5);
+}
+
+.mhwilds-home-card strong {
+ margin-top: var(--space-4);
+}
+
+.mhwilds-home-card span {
+ margin-bottom: var(--space-5);
+}
+
+.mhwilds-heading p {
+ max-width: 70ch;
+}
+
+.mhwilds-title-row {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 12px;
+}
+
+.mhwilds-title-row h1 {
+ margin-bottom: 0;
+}
+
+.results-count {
+ display: inline-flex;
+ min-height: 28px;
+ align-items: center;
+ padding: 4px 10px;
+ border: 1px solid rgba(165, 180, 252, 0.16);
+ border-radius: var(--radius-pill);
+ background: rgba(5, 7, 17, 0.34);
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-sm);
+ font-weight: 800;
+}
+
+.mhwilds-layout {
+ display: grid;
+ grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
+ gap: var(--space-5);
+ margin-top: var(--space-6);
+ align-items: start;
+}
+
+.mhwilds-filters {
+ position: sticky;
+ top: 92px;
+}
+
+.filter-panel {
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: rgba(16, 20, 38, 0.72);
+ box-shadow: var(--shadow-sm);
+ backdrop-filter: blur(18px);
+ padding: var(--space-4);
+}
+
+.filter-panel-head,
+.filter-logic {
+ display: flex;
+ justify-content: space-between;
+ gap: var(--space-3);
+}
+
+.filter-panel-head {
+ align-items: flex-start;
+}
+
+.filter-logic {
+ align-items: center;
+}
+
+.filter-panel-head h2 {
+ margin-bottom: 0;
+ font-size: var(--font-size-lg);
+}
+
+.filter-reset-button {
+ width: 40px;
+ min-width: 40px;
+ min-height: 40px;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(16, 20, 38, 0.78);
+ color: var(--color-text-secondary);
+ box-shadow: var(--shadow-sm);
+}
+
+.filter-reset-button:hover {
+ border-color: var(--color-border-hover);
+ background: rgba(21, 26, 48, 0.96);
+ color: var(--color-text-primary);
+}
+
+.field.compact {
+ padding: var(--space-4) 0;
+}
+
+.filter-logic {
+ min-height: 42px;
+ margin-bottom: var(--space-4);
+ padding: 8px 10px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+ background: rgba(5, 7, 17, 0.36);
+}
+
+.filter-logic button {
+ min-height: 30px;
+ padding: 0 12px;
+ background: var(--color-primary-soft);
+ color: var(--color-text-primary);
+ font-size: var(--font-size-sm);
+ font-weight: 800;
+ text-transform: uppercase;
+}
+
+.filter-options {
+ display: grid;
+ gap: 8px;
+ max-height: calc(100vh - 360px);
+ overflow: auto;
+ margin-right: -6px;
+ padding-right: 12px;
+}
+
+.filter-chip {
+ display: grid;
+ grid-template-columns: 22px 24px 1fr;
+ min-height: 40px;
+ align-items: center;
+ gap: 8px;
+ padding: 7px 9px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-pill);
+ background: rgba(5, 7, 17, 0.32);
+ color: var(--color-text-secondary);
+ cursor: pointer;
+}
+
+.filter-chip:hover,
+.filter-chip.active {
+ border-color: var(--color-primary-border);
+ background: var(--color-primary-soft);
+ color: var(--color-text-primary);
+}
+
+.filter-chip input {
+ width: 18px;
+ height: 18px;
+ min-height: 18px;
+ accent-color: var(--color-primary);
+}
+
+.filter-chip img {
+ width: 22px;
+ height: 22px;
+ object-fit: contain;
+}
+
+.filter-chip span {
+ overflow: hidden;
+ color: inherit;
+ font-size: var(--font-size-sm);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mhwilds-grid {
+ display: grid;
+ gap: var(--space-4);
+}
+
+.monster-grid {
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
+}
+
+.endemic-grid {
+ grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
+}
+
+.mhwilds-card {
+ overflow: hidden;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.88);
+ box-shadow: var(--shadow-sm);
+ transition:
+ transform var(--duration-fast) var(--ease-standard),
+ border-color var(--duration-fast) var(--ease-standard),
+ background-color var(--duration-fast) var(--ease-standard);
+}
+
+.mhwilds-card:hover {
+ transform: translateY(-2px);
+ border-color: var(--color-border-hover);
+ background: rgba(21, 26, 48, 0.96);
+}
+
+.monster-card {
+ height: 285px;
+ overflow: visible;
+ cursor: pointer;
+ perspective: 1200px;
+}
+
+.monster-card:hover,
+.monster-card:focus-visible {
+ background: transparent;
+}
+
+.mhwilds-card-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ transform-style: preserve-3d;
+ transition: transform 420ms var(--ease-standard);
+}
+
+.monster-card.is-flipped .mhwilds-card-inner {
+ transform: rotateY(180deg);
+}
+
+.mhwilds-card-face {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ overflow: hidden;
+ flex-direction: column;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ background: rgba(16, 20, 38, 0.92);
+ box-shadow: var(--shadow-sm);
+ backface-visibility: hidden;
+}
+
+.mhwilds-card-front {
+ transform: rotateY(0deg);
+}
+
+.mhwilds-card-back {
+ transform: rotateY(180deg);
+}
+
+.monster-card:hover .mhwilds-card-face {
+ border-color: var(--color-border-hover);
+ background: rgba(21, 26, 48, 0.98);
+}
+
+.mhwilds-card-art {
+ display: grid;
+ min-height: 112px;
+ place-items: center;
+ border-bottom: 1px solid var(--color-border);
+ background:
+ radial-gradient(circle at 50% 40%, rgba(139, 92, 246, 0.16), transparent 46%),
+ rgba(5, 7, 17, 0.36);
+}
+
+.endemic-card .mhwilds-card-art {
+ min-height: 104px;
+}
+
+.mhwilds-card-art img {
+ max-width: min(78%, 230px);
+ max-height: 92px;
+ object-fit: contain;
+ filter: drop-shadow(0 16px 24px rgba(0, 0, 0, 0.44));
+}
+
+.endemic-card .mhwilds-card-art img {
+ max-height: 78px;
+}
+
+.mhwilds-card-body {
+ padding: 12px;
+}
+
+.mhwilds-card-body h2 {
+ margin-bottom: 8px;
+ font-size: 1rem;
+}
+
+.monster-card .eyebrow {
+ margin-bottom: 6px;
+}
+
+.mhwilds-card-back .mhwilds-card-body {
+ padding: 10px 12px 6px;
+}
+
+.mhwilds-card-back .eyebrow {
+ margin-bottom: 4px;
+}
+
+.mhwilds-icon-row {
+ display: grid;
+ grid-template-columns: 92px 1fr;
+ gap: var(--space-2);
+ align-items: start;
+ margin-top: 4px;
+}
+
+.mhwilds-icon-row > span {
+ color: var(--color-text-muted);
+ font-size: 0.82rem;
+ line-height: 1.25;
+}
+
+.mhwilds-icon-row > div {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 5px;
+}
+
+.mhwilds-icon-row img {
+ width: 18px;
+ height: 18px;
+ object-fit: contain;
+}
+
+.mhwilds-icon-row em {
+ display: inline-grid;
+ width: 18px;
+ height: 18px;
+ place-items: center;
+ color: var(--color-text-muted);
+ font-style: normal;
+}
+
+.damage-table-wrap {
+ min-height: 0;
+ max-height: 218px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ margin: 0 10px 10px;
+ padding: 0;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-md);
+}
+
+.damage-table {
+ width: 100%;
+ min-width: 0;
+ border-collapse: separate;
+ border-spacing: 0;
+ table-layout: fixed;
+ font-size: 0.62rem;
+}
+
+.damage-table th,
+.damage-table td {
+ width: 9%;
+ padding: 2px 1px;
+ border-right: 1px solid var(--color-border);
+ border-bottom: 1px solid var(--color-border);
+ text-align: center;
+}
+
+.damage-table th:first-child,
+.damage-table td:first-child {
+ position: sticky;
+ left: 0;
+ width: 26%;
+ max-width: 26%;
+ overflow: hidden;
+ border-left: 1px solid var(--color-border);
+ background: var(--color-bg-surface-alt);
+ color: var(--color-text-secondary);
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.damage-table th {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ background: rgba(21, 26, 48, 0.96);
+}
+
+.damage-table th:first-child {
+ z-index: 3;
+}
+
+.damage-table img {
+ width: 14px;
+ height: 14px;
+ object-fit: contain;
+}
+
+.mobile-nav {
+ display: none;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
+
+@media (max-width: 1024px) {
+ .app-shell {
+ grid-template-columns: 72px minmax(0, 1fr);
+ }
+
+ .sidebar {
+ padding: var(--space-4) 10px;
+ }
+
+ .brand span:last-child,
+ .nav-item strong,
+ .sidebar-note {
+ display: none;
+ }
+
+ .brand,
+ .nav-item {
+ justify-content: center;
+ }
+}
+
+@media (max-width: 760px) {
+ .app-shell {
+ display: block;
+ padding-bottom: 76px;
+ }
+
+ .sidebar {
+ display: none;
+ }
+
+ .topbar,
+ .page-heading,
+ .toolbox-head,
+ .module header {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ .topbar {
+ padding: var(--space-4);
+ }
+
+ .topbar-actions {
+ display: flex;
+ }
+
+ .topbar-actions > * {
+ width: 100%;
+ }
+
+ .hero,
+ .game-hero,
+ .origin-section,
+ .section-grid,
+ .info-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .hero,
+ .game-hero {
+ min-height: auto;
+ padding: var(--space-6);
+ }
+
+ .home-visual {
+ justify-self: center;
+ width: min(320px, 100%);
+ min-height: 240px;
+ }
+
+ .home-visual img {
+ object-fit: contain;
+ }
+
+ .origin-section {
+ padding: var(--space-5);
+ }
+
+ .home-dialogue {
+ padding-left: 0;
+ }
+
+ .origin-copy {
+ padding-right: 0;
+ padding-bottom: var(--space-5);
+ border-right: 0;
+ border-bottom: 2px solid rgba(34, 211, 238, 0.66);
+ }
+
+ .dialogue-line {
+ max-width: 92%;
+ }
+
+ .home-stats {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ main {
+ width: min(100% - 24px, 1180px);
+ padding-top: var(--space-5);
+ }
+
+ .modules,
+ .modules[data-layout-cols="1"],
+ .modules[data-layout-cols="2"] {
+ grid-template-columns: 1fr;
+ }
+
+ .module-column {
+ display: contents;
+ }
+
+ .mhwilds-home-grid,
+ .mhwilds-layout {
+ grid-template-columns: 1fr;
+ }
+
+ .mhwilds-filters {
+ position: static;
+ }
+
+ .filter-options {
+ max-height: none;
+ }
+
+ .inline-form {
+ grid-template-columns: 1fr;
+ }
+
+ .mobile-nav {
+ position: fixed;
+ right: 12px;
+ bottom: 12px;
+ left: 12px;
+ z-index: 60;
+ display: grid;
+ grid-template-columns: 1fr 1fr 52px 1fr;
+ gap: 8px;
+ align-items: center;
+ padding: 8px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-xl);
+ background: rgba(11, 14, 27, 0.9);
+ backdrop-filter: blur(18px);
+ box-shadow: var(--shadow-lg);
+ }
+
+ .mobile-nav a,
+ .mobile-nav button {
+ min-height: 44px;
+ padding: 0 8px;
+ border-radius: var(--radius-md);
+ font-size: var(--font-size-sm);
+ }
+
+ .mobile-nav a {
+ display: grid;
+ place-items: center;
+ color: var(--color-text-secondary);
+ }
+
+ .mobile-nav a.active {
+ background: var(--color-primary-soft);
+ color: var(--color-text-primary);
+ }
+
+ .drawer-panel {
+ min-width: 0;
+ width: min(720px, 94vw);
+ }
+
+ .drawer-resize-handle {
+ display: none;
+ }
+}
+
+@media (max-width: 480px) {
+ .home-stats {
+ grid-template-columns: 1fr;
+ }
+}