gstaff commited on
Commit
9f77976
1 Parent(s): 209a8f1

Commit initial app files.

Browse files
Files changed (10) hide show
  1. README.md +6 -4
  2. SampleCard.png +0 -0
  3. app.py +479 -0
  4. favicon-96x96.png +0 -0
  5. hotkeys.js +22 -0
  6. monsterMakerTemplate.html +158 -0
  7. monstermaker.css +1493 -0
  8. packages.txt +3 -0
  9. placeholder.png +0 -0
  10. requirements.txt +7 -0
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  title: MonsterGenV2
3
- emoji: 🦀
4
- colorFrom: purple
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 4.7.1
8
  app_file: app.py
@@ -10,4 +10,6 @@ pinned: false
10
  license: apache-2.0
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
  title: MonsterGenV2
3
+ emoji: 👹
4
+ colorFrom: black
5
+ colorTo: red
6
  sdk: gradio
7
  sdk_version: 4.7.1
8
  app_file: app.py
 
10
  license: apache-2.0
11
  ---
12
 
13
+ # 👹 MonsterGenV2
14
+
15
+ ## Generate and Edit D&D Monsters with a Chat Assistant
SampleCard.png ADDED
app.py ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # pip install imgkit
2
+ # pip install html2image
3
+ import base64
4
+ import random
5
+ import uuid
6
+ from io import BytesIO
7
+
8
+ import imgkit
9
+ import os
10
+ import pathlib
11
+ import re
12
+ import gradio as gr
13
+ import requests
14
+ from PIL import Image, ImageChops, ImageDraw
15
+ from gradio_client import Client
16
+ import torch
17
+ from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline, Pipeline
18
+
19
+
20
+
21
+ HF_TOKEN = os.getenv("HF_TOKEN")
22
+
23
+ if not HF_TOKEN:
24
+ raise Exception("HF_TOKEN environment variable is required to call remote API.")
25
+
26
+ API_URL = "https://api-inference.huggingface.co/models/HuggingFaceH4/zephyr-7b-beta"
27
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
28
+
29
+ client = Client("https://latent-consistency-super-fast-lcm-lora-sd1-5.hf.space/")
30
+
31
+
32
+ def init_speech_to_text_model() -> Pipeline:
33
+ device = "cuda:0" if torch.cuda.is_available() else "cpu"
34
+ torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
35
+
36
+ model_id = "distil-whisper/distil-medium.en"
37
+ model = AutoModelForSpeechSeq2Seq.from_pretrained(
38
+ model_id, torch_dtype=torch_dtype, low_cpu_mem_usage=True, use_safetensors=True
39
+ )
40
+ model.to(device)
41
+ processor = AutoProcessor.from_pretrained(model_id)
42
+ return pipeline(
43
+ "automatic-speech-recognition",
44
+ model=model,
45
+ tokenizer=processor.tokenizer,
46
+ feature_extractor=processor.feature_extractor,
47
+ max_new_tokens=128,
48
+ torch_dtype=torch_dtype,
49
+ device=device,
50
+ )
51
+
52
+
53
+ whisper_pipe = init_speech_to_text_model()
54
+
55
+
56
+ def query(payload: dict):
57
+ response = requests.post(API_URL, headers=headers, json=payload)
58
+ return response.json()
59
+
60
+
61
+ def generate_text(card_text: str, user_request: str) -> (str, str, str):
62
+ # Prompt must apply the correct chat template for the model see:
63
+ # https://huggingface.co/docs/transformers/main/en/chat_templating
64
+ prompt = f"""<|system|>
65
+ You create Dungeons & Dragons monsters based on the user's request.
66
+ # RULES
67
+ - In your response always generate a new monster.
68
+ - Only generate one monster, no other dialogue.
69
+ - Surround monster info in triple backticks (```).
70
+ - Format the monster text using headers like in the example below:
71
+ ```
72
+ Name: Jabberwock
73
+ Type: Medium humanoid (human), neutral evil
74
+ Description: A Jabberwock is a creature of the Deep Sea.
75
+
76
+ Stats:
77
+ Armor Class: 15 (breastplate)
78
+ Hit Points: 22 (5d8 + 5)
79
+ Speed: 30 ft
80
+ STR: 8 (-1)
81
+ DEX: 14 (+2)
82
+ CON: 12 (+1)
83
+ INT: 2 (-4)
84
+ WIS: 10 (+0)
85
+ CHA: 4 (-3)
86
+ Skills: Perception +3
87
+ Senses: darkvision 60 ft., passive Perception 14
88
+ Languages: —
89
+ Challenge: 1/4 (50 XP)
90
+
91
+ Passives:
92
+ Legendary Resistance (3/Day): If the Jabberwock fails a saving throw, it can choose to succeed instead
93
+
94
+ Actions:
95
+ Bite: Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d8 + 3) piercing damage.
96
+ Claws (Recharge 5-6): Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d10 + 3) slashing damage.
97
+ ```</s>
98
+ <|user|>
99
+ {user_request}</s>
100
+ <|assistant|>
101
+ """
102
+ if card_text and card_text != starting_text:
103
+ prompt = f"""<|system|>
104
+ You edit Dungeons & Dragons monsters based on the user's request.
105
+ # RULES
106
+ - In your response always generate a new monster.
107
+ - Only generate one monster, no other dialogue.
108
+ - Surround monster info in triple backticks (```).
109
+ - Format the monster text using headers like in the example below:
110
+ ```
111
+ Name: Jabberwock
112
+ Type: Medium humanoid (human), neutral evil
113
+ Description: A Jabberwock is a creature of the Deep Sea.
114
+
115
+ Stats:
116
+ Armor Class: 15 (breastplate)
117
+ Hit Points: 22 (5d8 + 5)
118
+ Speed: 30 ft
119
+ STR: 8 (-1)
120
+ DEX: 14 (+2)
121
+ CON: 12 (+1)
122
+ INT: 2 (-4)
123
+ WIS: 10 (+0)
124
+ CHA: 4 (-3)
125
+ Skills: Perception +3
126
+ Senses: darkvision 60 ft., passive Perception 14
127
+ Languages: —
128
+ Challenge: 1/4 (50 XP)
129
+
130
+ Passives:
131
+ Legendary Resistance (3/Day): If the Jabberwock fails a saving throw, it can choose to succeed instead
132
+
133
+ Actions:
134
+ Bite: Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d8 + 3) piercing damage.
135
+ Claws (Recharge 5-6): Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d10 + 3) slashing damage.
136
+ ```</s>
137
+ <|user|>
138
+ # CARD TO EDIT
139
+ ```
140
+ {card_text}
141
+ ```
142
+ # EDIT REQUEST
143
+ {user_request}</s>
144
+ <|assistant|>
145
+ """
146
+ print(f"Calling API with prompt:\n{prompt}")
147
+ params = {"max_new_tokens": 512}
148
+ output = query({"inputs": prompt, "parameters": params})
149
+ if 'error' in output:
150
+ print(f'Language model call failed: {output["error"]}')
151
+ raise gr.Warning(f'Language model call failed: {output["error"]}')
152
+ print(f'API RESPONSE SIZE: {len(output[0]["generated_text"])}')
153
+ assistant_reply = output[0]["generated_text"].split('<|assistant|>')[1]
154
+ print(f'ASSISTANT REPLY:\n{assistant_reply}')
155
+ new_card_text = assistant_reply.split('```')
156
+ if len(new_card_text) > 1:
157
+ new_card_text = new_card_text[1].strip() + '\n'
158
+ else:
159
+ return assistant_reply, assistant_reply, None
160
+ return assistant_reply, new_card_text, None
161
+
162
+
163
+ def extract_text_for_header(text, header):
164
+ match = re.search(fr"{header}: (.*)", text)
165
+ if match is None:
166
+ return ''
167
+ return match.group(1)
168
+
169
+
170
+ def remove_section(html, html_class):
171
+ match = re.search(f'<li class="{html_class}"([\w\W])*?li>', html)
172
+ if match is not None:
173
+ html = html.replace(match.group(0), '')
174
+ return html
175
+
176
+
177
+ def format_html(monster_text, image_data):
178
+ print('FORMATTING MONSTER TEXT')
179
+ # see giffyglyph's monster maker https://giffyglyph.com/monstermaker/app/
180
+ # Different Formatting style examples and some json export formats
181
+ card = pathlib.Path('monsterMakerTemplate.html').read_text()
182
+ if not isinstance(image_data, (bytes, bytearray)):
183
+ card = card.replace('{image_data}', f'{image_data}')
184
+ else:
185
+ card = card.replace('{image_data}', f'data:image/png;base64,{image_data.decode("utf-8")}')
186
+ name = extract_text_for_header(monster_text, 'Name')
187
+ card = card.replace('{name}', name)
188
+ monster_type = extract_text_for_header(monster_text, 'Type')
189
+ card = card.replace('{monster_type}', monster_type)
190
+ armor_class = extract_text_for_header(monster_text, 'Armor Class')
191
+ card = card.replace('{armor_class}', armor_class)
192
+ hit_points = extract_text_for_header(monster_text, 'Hit Points')
193
+ card = card.replace('{hit_points}', hit_points)
194
+ speed = extract_text_for_header(monster_text, 'Speed')
195
+ card = card.replace('{speed}', speed)
196
+ str_stat = extract_text_for_header(monster_text, 'STR')
197
+ card = card.replace('{str_stat}', str_stat)
198
+ dex_stat = extract_text_for_header(monster_text, 'DEX')
199
+ card = card.replace('{dex_stat}', dex_stat)
200
+ con_stat = extract_text_for_header(monster_text, 'CON')
201
+ card = card.replace('{con_stat}', con_stat)
202
+ int_stat = extract_text_for_header(monster_text, 'INT')
203
+ card = card.replace('{int_stat}', int_stat)
204
+ wis_stat = extract_text_for_header(monster_text, 'WIS')
205
+ card = card.replace('{wis_stat}', wis_stat)
206
+ cha_stat = extract_text_for_header(monster_text, 'CHA')
207
+ card = card.replace('{cha_stat}', cha_stat)
208
+ saving_throws = extract_text_for_header(monster_text, 'Saving Throws')
209
+ card = card.replace('{saving_throws}', saving_throws)
210
+ if not saving_throws:
211
+ card = remove_section(card, 'monster-saves')
212
+ skills = extract_text_for_header(monster_text, 'Skills')
213
+ card = card.replace('{skills}', skills)
214
+ if not skills:
215
+ card = remove_section(card, 'monster-skills')
216
+ damage_vulnerabilities = extract_text_for_header(monster_text, 'Damage Vulnerabilities')
217
+ card = card.replace('{damage_vulnerabilities}', damage_vulnerabilities)
218
+ if not damage_vulnerabilities:
219
+ card = remove_section(card, 'monster-vulnerabilities')
220
+ damage_resistances = extract_text_for_header(monster_text, 'Damage Resistances')
221
+ card = card.replace('{damage_resistances}', damage_resistances)
222
+ if not damage_resistances:
223
+ card = remove_section(card, 'monster-resistances')
224
+ damage_immunities = extract_text_for_header(monster_text, 'Damage Immunities')
225
+ card = card.replace('{damage_immunities}', damage_immunities)
226
+ if not damage_immunities:
227
+ card = remove_section(card, 'monster-immunities')
228
+ condition_immunities = extract_text_for_header(monster_text, 'Condition Immunities')
229
+ card = card.replace('{condition_immunities}', condition_immunities)
230
+ if not condition_immunities:
231
+ card = remove_section(card, 'monster-conditions')
232
+ senses = extract_text_for_header(monster_text, 'Senses')
233
+ card = card.replace('{senses}', senses)
234
+ if not senses:
235
+ card = remove_section(card, 'monster-senses')
236
+ languages = extract_text_for_header(monster_text, 'Languages')
237
+ card = card.replace('{languages}', languages)
238
+ if not languages:
239
+ card = remove_section(card, 'monster-languages')
240
+ challenge = extract_text_for_header(monster_text, 'Challenge')
241
+ card = card.replace('{challenge}', challenge)
242
+ if not challenge:
243
+ card = remove_section(card, 'monster-challenge')
244
+
245
+ description = extract_text_for_header(monster_text, 'Description')
246
+ card = card.replace('{description}', description)
247
+
248
+ match = re.search(r"Passives:\n([\w\W]*)", monster_text)
249
+ if match is None:
250
+ passives = ''
251
+ else:
252
+ passives = match.group(1)
253
+ p = passives.split(':')
254
+ if len(p) > 1:
255
+ p = ":".join(p)
256
+ p = p.split('\n')
257
+ passives_data = ''
258
+ for x in p:
259
+ x = x.split(':')
260
+ if len(x) > 1:
261
+ trait = x[0]
262
+ if trait == "Passives":
263
+ continue
264
+ if 'Action' in trait:
265
+ break
266
+ detail = ":".join(x[1:])
267
+ passives_data += f'<div class="monster-trait"><p><span class="name">{trait}</span> <span class="detail">{detail}</span></p></div>'
268
+ card = card.replace('{passives}', passives_data)
269
+ else:
270
+ card = card.replace('{passives}', f'<div class="monster-trait"><p>{passives}</p></div>')
271
+
272
+ match = re.search(r"Actions:\n([\w\W]*)", monster_text)
273
+ if match is None:
274
+ actions = ''
275
+ else:
276
+ actions = match.group(1)
277
+ a = actions.split(':')
278
+ if len(a) > 1:
279
+ a = ":".join(a)
280
+ a = a.split('\n')
281
+ actions_data = ''
282
+ for x in a:
283
+ x = x.split(':')
284
+ if len(x) > 1:
285
+ action = x[0]
286
+ if action == "Actions":
287
+ continue
288
+ if 'Passive' in action:
289
+ break
290
+ detail = ":".join(x[1:])
291
+ actions_data += f'<div class="monster-action"><p><span class="name">{action}</span> <span class="detail">{detail}</span></p></div>'
292
+ card = card.replace('{actions}', actions_data)
293
+ else:
294
+ card = card.replace('{actions}', f'<div class="monster-action"><p>{actions}</p></div>')
295
+
296
+ # TODO: Legendary actions, reactions, make column count for format an option (1 or 2 column layout)
297
+
298
+ card = card.replace('Melee or Ranged Weapon Attack:', '<i>Melee or Ranged Weapon Attack:</i>')
299
+ card = card.replace('Melee Weapon Attack:', '<i>Melee Weapon Attack:</i>')
300
+ card = card.replace('Ranged Weapon Attack:', '<i>Ranged Weapon Attack:</i>')
301
+ card = card.replace('Hit:', '<i>Hit:</i>')
302
+
303
+ print('FORMATTING MONSTER TEXT COMPLETE')
304
+ return card
305
+
306
+
307
+ def get_savename(directory, name, extension):
308
+ save_name = f"{name}.{extension}"
309
+ i = 1
310
+ while os.path.exists(os.path.join(directory, save_name)):
311
+ save_name = save_name.replace(f'.{extension}', '').split('-')[0] + f"-{i}.{extension}"
312
+ i += 1
313
+ return save_name
314
+
315
+
316
+ def trim(im, border):
317
+ bg = Image.new(im.mode, im.size, border)
318
+ diff = ImageChops.difference(im, bg)
319
+ bbox = diff.getbbox()
320
+ if bbox:
321
+ return im.crop(bbox)
322
+
323
+
324
+ def crop_background(image):
325
+ white = (255, 255, 255)
326
+ ImageDraw.floodfill(image, (image.size[0] - 1, 0), white, thresh=50)
327
+ image = trim(image, white)
328
+ return image
329
+
330
+
331
+ def html_to_png(card_name, html):
332
+ save_name = get_savename('rendered_cards', card_name, 'png')
333
+ print('CONVERTING HTML CARD TO PNG IMAGE')
334
+
335
+ path = os.path.join('rendered_cards', save_name)
336
+ try:
337
+ css = ['./css/mana.css', './css/keyrune.css',
338
+ './css/mtg_custom.css']
339
+ imgkit.from_string(html, path, {"xvfb": "", "enable-local-file-access": ""}, css=css)
340
+ except Exception as e:
341
+ try:
342
+ # For Windows local, requires 'html2image' package from pip.
343
+ from html2image import Html2Image
344
+ rendered_card_dir = 'rendered_cards'
345
+ hti = Html2Image(output_path=rendered_card_dir)
346
+ paths = hti.screenshot(html_str=html,
347
+ css_file='monstermaker.css',
348
+ save_as=save_name, size=(800, 1440))
349
+ print(paths)
350
+ path = paths[0]
351
+ except:
352
+ pass
353
+ print('OPENING IMAGE FROM FILE')
354
+ img = Image.open(path).convert("RGB")
355
+ print('CROPPING BACKGROUND')
356
+ img = crop_background(img)
357
+ print('CONVERTING HTML CARD TO PNG IMAGE COMPLETE')
358
+ return img
359
+
360
+
361
+ def get_initial_card():
362
+ return Image.open('SampleCard.png')
363
+
364
+
365
+ def pil_to_base64(image):
366
+ print('CONVERTING PIL IMAGE TO BASE64 STRING')
367
+ buffered = BytesIO()
368
+ image.save(buffered, format="PNG")
369
+ img_str = base64.b64encode(buffered.getvalue())
370
+ print('CONVERTING PIL IMAGE TO BASE64 STRING COMPLETE')
371
+ return img_str
372
+
373
+
374
+ def generate_card(image: str, card_text: str):
375
+ image_data = pil_to_base64(Image.open(image))
376
+ html = format_html(card_text, image_data)
377
+ pattern = re.compile('Name: (.*)')
378
+ name = pattern.findall(card_text)[0]
379
+ card = html_to_png(name, html)
380
+ return card
381
+
382
+
383
+ def transcribe(audio: str) -> (str, str):
384
+ result = whisper_pipe(audio)
385
+ return result["text"], None
386
+
387
+
388
+ starting_text = """Name: Jabberwock
389
+ Type: Medium humanoid (human), neutral evil
390
+ Description: A Jabberwock is a creature of the Deep Sea.
391
+
392
+ Stats:
393
+ Armor Class: 15 (breastplate)
394
+ Hit Points: 22 (5d8 + 5)
395
+ Speed: 30 ft
396
+ STR: 8 (-1)
397
+ DEX: 14 (+2)
398
+ CON: 12 (+1)
399
+ INT: 2 (-4)
400
+ WIS: 10 (+0)
401
+ CHA: 4 (-3)
402
+ Skills: Perception +3
403
+ Senses: darkvision 60 ft., passive Perception 14
404
+ Languages: —
405
+ Challenge: 1/4 (50 XP)
406
+
407
+ Passives:
408
+ Legendary Resistance (3/Day): If the Jabberwock fails a saving throw, it can choose to succeed instead
409
+
410
+ Actions:
411
+ Bite: Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d8 + 3) piercing damage.
412
+ Claws (Recharge 5-6): Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 6 (1d10 + 3) slashing damage."""
413
+
414
+
415
+ def generate_image(card_text: str):
416
+ pattern = re.compile('Name: (.*)')
417
+ name = pattern.findall(card_text)[0]
418
+ pattern = re.compile('Type: (.*)')
419
+ card_type = pattern.findall(card_text)[0]
420
+ prompt = f"fantasy illustration of a {card_type} {name}, by Greg Rutkowski"
421
+ print(f'Calling image generation with prompt: {prompt}')
422
+ try:
423
+ result = client.predict(
424
+ prompt, # str in 'parameter_5' Textbox component
425
+ 0.3, # float (numeric value between 0.0 and 5) in 'Guidance' Slider component
426
+ 4, # float (numeric value between 2 and 10) in 'Steps' Slider component
427
+ random.randint(0, 12013012031030),
428
+ # float (numeric value between 0 and 12013012031030) in 'Seed' Slider component
429
+ api_name="/predict"
430
+ )
431
+ print(result)
432
+ return result
433
+ except Exception as e:
434
+ print(f'Failed to generate image from client: {e}')
435
+ return 'placeholder.png'
436
+
437
+
438
+ def add_hotkeys() -> str:
439
+ return pathlib.Path("hotkeys.js").read_text()
440
+
441
+
442
+ with gr.Blocks(title='MonsterGen') as demo:
443
+ gr.Markdown("# 👹 MonsterGenV2")
444
+ gr.Markdown("## Generate and Edit D&D Monsters with a Chat Assistant")
445
+ with gr.Row():
446
+ with gr.Column():
447
+ with gr.Group():
448
+ audio_in = gr.Microphone(label="Record a voice request (click or press ctrl + ` to start/stop)",
449
+ type='filepath', elem_classes=["record-btn"])
450
+ prompt_in = gr.Textbox(label="Or type a text request and press Enter", interactive=True,
451
+ placeholder="Need an idea? Try one of these:\n- Create a creature card named 'WiFi Elemental'\n- Make it an instant\n- Change the color")
452
+ with gr.Accordion(label='🤖 Chat Assistant Response', open=False):
453
+ bot_text = gr.TextArea(label='Response', interactive=False)
454
+ with gr.Row():
455
+ with gr.Column():
456
+ in_text = gr.TextArea(label="Card Text (Shift+Enter to submit)", value=starting_text)
457
+ gen_image_button = gr.Button('🖼️ Generate Card Image')
458
+ in_image = gr.Image(label="Card Image (256px x 256px)", type='filepath', value='placeholder.png')
459
+ render_button = gr.Button('🎴 Render Card', variant="primary")
460
+ gr.ClearButton([audio_in, prompt_in, in_text, in_image])
461
+ with gr.Column():
462
+ out_image = gr.Image(label="Rendered Card", value=get_initial_card())
463
+
464
+ transcribe_params = {'fn': transcribe, 'inputs': [audio_in], 'outputs': [prompt_in, audio_in]}
465
+ generate_text_params = {'fn': generate_text, 'inputs': [in_text, prompt_in],
466
+ 'outputs': [bot_text, in_text, audio_in]}
467
+ generate_image_params = {'fn': generate_image, 'inputs': [in_text], 'outputs': [in_image]}
468
+ generate_card_params = {'fn': generate_card, 'inputs': [in_image, in_text], 'outputs': [out_image]}
469
+ # Shift + Enter to submit text in TextAreas
470
+ audio_in.stop_recording(**transcribe_params).then(**generate_text_params).then(**generate_image_params).then(
471
+ **generate_card_params)
472
+ prompt_in.submit(**generate_text_params).then(**generate_image_params).then(**generate_card_params)
473
+ in_text.submit(**generate_card_params)
474
+ render_button.click(**generate_card_params)
475
+ gen_image_button.click(**generate_image_params).then(**generate_card_params)
476
+ demo.load(None, None, None, js=add_hotkeys())
477
+
478
+ if __name__ == "__main__":
479
+ demo.queue().launch(favicon_path="favicon-96x96.png")
favicon-96x96.png ADDED
hotkeys.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ () => {
2
+ function gradioApp() {
3
+ const elems = document.getElementsByTagName('gradio-app');
4
+ const elem = elems.length == 0 ? document : elems[0];
5
+
6
+ if (elem !== document) {
7
+ elem.getElementById = function(id) {
8
+ return document.getElementById(id);
9
+ };
10
+ }
11
+ return elem.shadowRoot ? elem.shadowRoot : elem;
12
+ }
13
+ window.addEventListener('keydown', (e) => {
14
+ if ((e.ctrlKey || e.metaKey) && e.key == "`") { // CTRL + ` key
15
+ const recordButtons = [...gradioApp().querySelectorAll('button.record.record-button')].filter(x => x.checkVisibility());
16
+ const stopButtons = [...gradioApp().querySelectorAll('button.stop-button')].filter(x => x.checkVisibility());
17
+ for (let button of recordButtons.concat(stopButtons)) {
18
+ button.click();
19
+ }
20
+ }
21
+ });
22
+ }
monsterMakerTemplate.html ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <title>Document</title>
9
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
10
+ integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css"
12
+ crossorigin="anonymous">
13
+ <link rel="stylesheet" type="text/css"
14
+ href="https://cdn.datatables.net/v/bs4/dt-1.10.18/r-2.2.2/b-1.5.6/b-colvis-1.5.6/datatables.min.css">
15
+ <link rel="stylesheet" type="text/css"
16
+ href="https://fonts.googleapis.com/css?family=Roboto:400,400i,700,700i|Alegreya+Sans+SC:700">
17
+ <link rel="stylesheet" type="text/css" href="monstermaker.css">
18
+ </head>
19
+
20
+ <body>
21
+ <div class="monster theme-5e columns-2">
22
+ <div class="monster-contents">
23
+ <div class="monster-contents-header"></div>
24
+ <div class="monster-contents-body">
25
+ <div class="monster-image inline">
26
+ <img src="{image_data}" alt="Picture of {name}" />
27
+ </div>
28
+ <div class="monster-header">
29
+ <div>
30
+ <h4>{name}</h4>
31
+ <p class="monster-description">{monster_type}</p>
32
+ </div>
33
+ </div>
34
+ <hr>
35
+ <ul>
36
+ <li class="monster-ac">
37
+ <p>
38
+ <span class="label">Armor Class</span>
39
+ <span>{armor_class}</span>
40
+ </p>
41
+ </li>
42
+ <li class="monster-hp">
43
+ <p>
44
+ <span class="label">Hit Points</span>
45
+ <span>{hit_points}</span>
46
+ </p>
47
+ </li>
48
+ <li class="monster-speed">
49
+ <p>
50
+ <span class="label">Speed</span>
51
+ <span>{speed}</span>
52
+ </p>
53
+ </li>
54
+ </ul>
55
+ <hr>
56
+ <div class="monster-abilities">
57
+ <div class="monster-ability">
58
+ <span class="label">Str</span>
59
+ <span>{str_stat}</span>
60
+ </div>
61
+ <div class="monster-ability">
62
+ <span class="label">Dex</span>
63
+ <span>{dex_stat}</span>
64
+ </div>
65
+ <div class="monster-ability">
66
+ <span class="label">Con</span>
67
+ <span>{con_stat}</span>
68
+ </div>
69
+ <div class="monster-ability">
70
+ <span class="label">Int</span>
71
+ <span>{int_stat}</span>
72
+ </div>
73
+ <div class="monster-ability">
74
+ <span class="label">Wis</span>
75
+ <span>{wis_stat}</span>
76
+ </div>
77
+ <div class="monster-ability">
78
+ <span class="label">Cha</span>
79
+ <span>{cha_stat}</span>
80
+ </div>
81
+ </div>
82
+ <hr>
83
+ <ul class="monster-stats">
84
+ <li class="monster-saves">
85
+ <p>
86
+ <span class="label">Saving Throws</span>
87
+ <span>{saving_throws}</span>
88
+ </p>
89
+ </li>
90
+ <li class="monster-skills">
91
+ <p>
92
+ <span class="label">Skills</span>
93
+ <span>{skills}</span>
94
+ </p>
95
+ </li>
96
+ <li class="monster-vulnerabilities">
97
+ <p>
98
+ <span class="label">Damage Vulnerabilities</span>
99
+ <span>{damage_vulnerabilities}</span>
100
+ </p>
101
+ </li>
102
+ <li class="monster-resistances">
103
+ <p>
104
+ <span class="label">Damage Resistances</span>
105
+ <span>{damage_resistances}</span>
106
+ </p>
107
+ </li>
108
+ <li class="monster-immunities">
109
+ <p>
110
+ <span class="label">Damage Immunities</span>
111
+ <span>{damage_immunities}</span>
112
+ </p>
113
+ </li>
114
+ <li class="monster-conditions">
115
+ <p>
116
+ <span class="label">Condition Immunities</span>
117
+ <span>{condition_immunities}</span>
118
+ </p>
119
+ </li>
120
+ <li class="monster-senses">
121
+ <p>
122
+ <span class="label">Senses</span>
123
+ <span>{senses}</span>
124
+ </p>
125
+ </li>
126
+ <li class="monster-languages">
127
+ <p>
128
+ <span class="label">Languages</span>
129
+ <span>{languages}</span>
130
+ </p>
131
+ </li>
132
+ <li class="monster-challenge">
133
+ <p>
134
+ <span class="label">Challenge</span>
135
+ <span>{challenge}</span>
136
+ </p>
137
+ </li>
138
+ </ul>
139
+ <hr>
140
+ <h5 class="h5-traits">Traits</h5>
141
+ <div class="h5-border"></div>
142
+ {passives}
143
+ <h5>Actions</h5>
144
+ <div class="h5-border"></div>
145
+ {actions}
146
+ <h5 class="h5-notes">Notes</h5>
147
+ <div class="h5-border"></div>
148
+ <div class="monster-notes">
149
+ <p class="note">{description}</p>
150
+ </div>
151
+ <p class="monster-footer">Made by MonsterGen</p>
152
+ </div>
153
+ <div class="monster-contents-footer"></div>
154
+ </div>
155
+ </div>
156
+ </body>
157
+
158
+ </html>
monstermaker.css ADDED
@@ -0,0 +1,1493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .alert > :last-child {
2
+ margin-bottom: 0; }
3
+
4
+ .alert-default {
5
+ border: 4px solid #dee2e6;
6
+ border-radius: 1em; }
7
+
8
+ .app {
9
+ display: grid;
10
+ min-height: 100vh;
11
+ min-width: 300px;
12
+ grid-template-rows: 1fr auto;
13
+ grid-template-columns: 100%; }
14
+ .app .app-container {
15
+ max-width: 1200px;
16
+ margin: 0 auto; }
17
+
18
+ .app .app-body {
19
+ background: #666f7f;
20
+ margin-top: 6.25rem;
21
+ display: flex;
22
+ flex-direction: column; }
23
+ .app .app-body .app-container {
24
+ padding: 0.5rem 10px;
25
+ width: 100%;
26
+ flex-grow: 1; }
27
+
28
+ .app .app-header {
29
+ position: fixed;
30
+ top: 0;
31
+ width: 100%;
32
+ z-index: 2;
33
+ box-shadow: 0 0.25rem 0.75rem 0 #505762; }
34
+ @media screen and (min-width: 801px) {
35
+ .app .app-header .app-header-navbar {
36
+ display: none; } }
37
+ .app .app-header .app-header-heading {
38
+ background: #22252a; }
39
+ .app .app-header .app-header-heading .app-container {
40
+ padding: 0.625rem 10px;
41
+ display: grid;
42
+ grid-template-columns: auto repeat(8, 2rem);
43
+ grid-column-gap: 0.25rem;
44
+ align-items: end; }
45
+ @media screen and (max-width: 800px) {
46
+ .app .app-header .app-header-heading .app-container {
47
+ grid-template-columns: auto repeat(2, 2rem); }
48
+ .app .app-header .app-header-heading .app-container .btn:not(.btn-patreon):not(.btn-menu) {
49
+ display: none; } }
50
+ @media screen and (min-width: 801px) {
51
+ .app .app-header .app-header-heading .app-container .btn-menu {
52
+ display: none; } }
53
+ .app .app-header .app-header-heading h1 {
54
+ text-transform: uppercase;
55
+ font-weight: bold;
56
+ display: flex;
57
+ flex-direction: row;
58
+ line-height: 1;
59
+ margin: 0; }
60
+ .app .app-header .app-header-heading h1 img {
61
+ height: 2.5rem;
62
+ width: 2.5rem;
63
+ border: 2px solid #666f7f;
64
+ padding: 2px;
65
+ box-sizing: border-box;
66
+ border-radius: 100%;
67
+ margin-right: 0.325rem; }
68
+ .app .app-header .app-header-heading h1 a {
69
+ display: flex;
70
+ flex-direction: column; }
71
+ .app .app-header .app-header-heading h1 a span:first-of-type {
72
+ font-size: 0.95rem;
73
+ color: #da3737;
74
+ letter-spacing: 1px; }
75
+ .app .app-header .app-header-heading h1 a span:last-of-type {
76
+ color: #FFFFFF;
77
+ font-size: 1.9rem;
78
+ margin-bottom: -0.35rem; }
79
+ .app .app-header .app-header-heading h1 a:hover {
80
+ text-decoration: none; }
81
+ .app .app-header .app-header-heading h1 a:hover span:last-of-type {
82
+ text-decoration: underline;
83
+ text-decoration-color: #da3737; }
84
+ .app .app-header .app-header-heading .btn {
85
+ height: 2rem;
86
+ border-radius: 100%;
87
+ box-sizing: border-box;
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ font-size: 1rem;
92
+ background-color: #666f7f;
93
+ border-color: #666f7f;
94
+ line-height: 1;
95
+ padding: 0; }
96
+ .app .app-header .app-header-heading .btn .fas,
97
+ .app .app-header .app-header-heading .btn .fab {
98
+ background: none;
99
+ padding: 0;
100
+ margin: 0; }
101
+ .app .app-header .app-header-heading .btn:hover {
102
+ background: #da3737;
103
+ border-color: #da3737; }
104
+ .app .app-header .app-header-heading .btn.btn-patreon {
105
+ background-color: #e85b46;
106
+ border-color: #e85b46; }
107
+ .app .app-header .app-header-heading .btn.btn-patreon:hover {
108
+ color: #e85b46;
109
+ background-color: #FFFFFF;
110
+ border-color: #FFFFFF; }
111
+ .app .app-header .app-header-navbar {
112
+ background: #22252a; }
113
+ .app .app-header .app-header-navbar .navbar {
114
+ padding: 0; }
115
+ .app .app-header .app-header-navbar .navbar .nav-item {
116
+ padding-left: 0.625rem;
117
+ padding-right: 0.625rem; }
118
+ .app .app-header .app-header-navbar .navbar .nav-item + .nav-item {
119
+ border-top: 1px dotted #444a54; }
120
+ .app .app-header .app-header-navbar .navbar .nav-item a {
121
+ color: white;
122
+ font-weight: bold; }
123
+ .app .app-header .app-header-navbar .navbar .nav-item a:hover {
124
+ color: #da3737; }
125
+ .app .app-header .app-header-navbar .navbar .nav-item button {
126
+ padding: 0;
127
+ color: white;
128
+ font-weight: bold;
129
+ display: block;
130
+ padding: 0.5rem 0;
131
+ background: none;
132
+ border: none;
133
+ box-shadow: none;
134
+ width: 100%;
135
+ text-align: left; }
136
+ .app .app-header .app-header-navbar .navbar .nav-item button:hover {
137
+ color: #da3737;
138
+ cursor: pointer; }
139
+ .app .app-header .app-header-navbar .navbar .nav-item .fab,
140
+ .app .app-header .app-header-navbar .navbar .nav-item .fas {
141
+ width: 2.5rem;
142
+ text-align: center;
143
+ margin-right: 0.325rem; }
144
+ .app .app-header .app-header-navbar .navbar .nav-item:first-child {
145
+ border-top: 1px solid #444a54; }
146
+ .app .app-header .app-header-navbar .navbar .nav-item:last-child {
147
+ border-bottom: 1px solid #444a54; }
148
+ .app .app-header .app-header-navbar .navbar .nav-item .nav-link-detail {
149
+ color: #666f7f; }
150
+
151
+ .app .app-header .app-header-navigation {
152
+ background: #2d3138; }
153
+ .app .app-header .app-header-navigation .app-container {
154
+ padding: 0 10px; }
155
+ .app .app-header .app-header-navigation .nav {
156
+ display: grid;
157
+ grid-template-columns: repeat(2, 1fr); }
158
+ .app .app-header .app-header-navigation .nav .nav-item {
159
+ text-align: center;
160
+ font-weight: bold; }
161
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link {
162
+ color: #666f7f;
163
+ padding: 0.5rem 0.5rem 0.25rem;
164
+ border-radius: 0;
165
+ border-bottom: 0.25rem solid #22252a; }
166
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link .badge {
167
+ background: rgba(102, 111, 127, 0.5); }
168
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link:not(.active):hover {
169
+ border-bottom: 0.25rem solid rgba(218, 55, 55, 0.5);
170
+ color: rgba(255, 255, 255, 0.5); }
171
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link:not(.active):hover .fas,
172
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link:not(.active):hover .fab {
173
+ color: rgba(218, 55, 55, 0.5); }
174
+ @media screen and (max-width: 800px) {
175
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link .nav-link-text,
176
+ .app .app-header .app-header-navigation .nav .nav-item .nav-link .badge {
177
+ display: none; } }
178
+ .app .app-header .app-header-navigation .nav .nav-item .active {
179
+ background: none;
180
+ border-radius: 0;
181
+ border-bottom: 0.25rem solid #da3737;
182
+ color: white; }
183
+ .app .app-header .app-header-navigation .nav .nav-item .active .badge {
184
+ background: #666f7f; }
185
+ .app .app-header .app-header-navigation .nav .nav-item .active .fas,
186
+ .app .app-header .app-header-navigation .nav .nav-item .active .fab {
187
+ color: #da3737; }
188
+ .app .app-header .app-header-navigation .nav .nav-item .fas,
189
+ .app .app-header .app-header-navigation .nav .nav-item .fab {
190
+ margin-right: 0.325rem; }
191
+ .app .app-header .app-header-navigation .nav .nav-item .badge {
192
+ border-radius: 1cm;
193
+ font-size: inherit;
194
+ padding: 0.1625rem 0.325rem; }
195
+
196
+ .app .app-footer {
197
+ background: #565e6b;
198
+ text-align: center; }
199
+ .app .app-footer .app-container {
200
+ padding: 1.25rem 10px;
201
+ display: grid;
202
+ grid-template-columns: 1fr 1fr 2fr;
203
+ text-align: left; }
204
+ @media screen and (max-width: 800px) {
205
+ .app .app-footer .app-container {
206
+ grid-template-columns: 1fr;
207
+ grid-row-gap: 0.5rem;
208
+ text-align: center; }
209
+ .app .app-footer .app-container p {
210
+ text-align: center; } }
211
+ .app .app-footer a {
212
+ color: inherit;
213
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
214
+ text-decoration: none;
215
+ display: inline-block; }
216
+ .app .app-footer a:hover {
217
+ color: #da3737; }
218
+ .app .app-footer p {
219
+ text-align: right;
220
+ margin: 0;
221
+ color: #f1f2f3;
222
+ font-size: 0.9rem; }
223
+ .app .app-footer p a:not(:first-of-type) {
224
+ margin-left: 0.75rem; }
225
+ .app .app-footer p .fab {
226
+ font-size: 2rem;
227
+ color: #9ca3af;
228
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; }
229
+ .app .app-footer p .fab:hover {
230
+ color: #da3737; }
231
+ .app .app-footer ul {
232
+ margin: 0;
233
+ padding: 0;
234
+ list-style: none;
235
+ font-size: 0.9rem;
236
+ color: #f1f2f3; }
237
+ .app .app-footer h5 {
238
+ color: #9ca3af;
239
+ font-size: 0.75rem;
240
+ text-transform: uppercase;
241
+ font-weight: bold; }
242
+ .app .app-footer .links > :not(:last-child) {
243
+ margin-bottom: 0.5rem; }
244
+
245
+ html {
246
+ font-size: 16px; }
247
+ @media screen and (max-width: 400px) {
248
+ html {
249
+ font-size: 12px; } }
250
+
251
+ body {
252
+ font-family: 'Roboto', sans-serif;
253
+ background: #666f7f; }
254
+
255
+ a {
256
+ color: #da3737; }
257
+ a:hover {
258
+ color: #da3737; }
259
+
260
+ .breadcrumbs {
261
+ background: #565e6b;
262
+ margin-top: 0.5rem;
263
+ color: #dee2e6;
264
+ font-size: 0.9em; }
265
+ @media screen and (max-width: 800px) {
266
+ .breadcrumbs {
267
+ display: none; } }
268
+ .breadcrumbs .app-container {
269
+ padding: 0.5rem 10px;
270
+ max-width: 1200px;
271
+ margin: 0 auto; }
272
+ .breadcrumbs .divider,
273
+ .breadcrumbs .fas {
274
+ margin: 0 0.25rem;
275
+ color: #dee2e6; }
276
+ .breadcrumbs a {
277
+ color: inherit; }
278
+ .breadcrumbs a:hover {
279
+ color: white; }
280
+
281
+ .btn {
282
+ border-radius: 2rem;
283
+ padding: 0 0.75rem 0 0; }
284
+ .btn .fas,
285
+ .btn .fab {
286
+ background: #da3737;
287
+ padding: 0.325rem;
288
+ line-height: inherit;
289
+ border-radius: 2rem;
290
+ margin: 0 0.325rem 0 0; }
291
+ .btn .fas:before,
292
+ .btn .fab:before {
293
+ min-width: 1.5rem;
294
+ display: block;
295
+ text-align: center; }
296
+ .btn.icon-only .fas,
297
+ .btn.icon-only .fab {
298
+ margin-right: -0.75rem; }
299
+ .btn.btn-sm {
300
+ padding: 0 0.5rem 0 0; }
301
+ .btn.btn-sm .fas,
302
+ .btn.btn-sm .fab {
303
+ padding: 0;
304
+ margin: 0 0.25rem 0 0; }
305
+ .btn.btn-sm .fas::before,
306
+ .btn.btn-sm .fab::before {
307
+ min-width: 1.3rem; }
308
+ .btn.btn-sm.icon-only {
309
+ padding-right: 0; }
310
+ .btn.btn-sm.icon-only .fas,
311
+ .btn.btn-sm.icon-only .fab {
312
+ margin-right: 0; }
313
+
314
+ .btn-primary {
315
+ color: #FFFFFF;
316
+ background-color: #2d3138;
317
+ border-color: #2d3138;
318
+ font-weight: bold; }
319
+ .btn-primary.icon-only:not(.icon-border) {
320
+ border-color: #da3737; }
321
+
322
+ .btn-secondary {
323
+ color: #FFFFFF;
324
+ background-color: #666f7f;
325
+ border-color: #666f7f;
326
+ font-weight: bold; }
327
+ .btn-secondary.icon-only:not(.icon-border) {
328
+ border-color: #da3737; }
329
+
330
+ .btn-primary,
331
+ .btn-secondary {
332
+ display: inline-flex;
333
+ align-items: center;
334
+ border-width: 2px; }
335
+ .btn-primary:hover, .btn-primary:not(:disabled):not(:disabled):active, .btn-primary.dropdown-toggle[aria-expanded="true"],
336
+ .btn-secondary:hover,
337
+ .btn-secondary:not(:disabled):not(:disabled):active,
338
+ .btn-secondary.dropdown-toggle[aria-expanded="true"] {
339
+ background-color: #da3737;
340
+ border-color: #da3737; }
341
+ .btn-primary:not(:disabled):not(:disabled):focus, .btn-primary:not(:disabled):not(:disabled):active:focus, .btn-primary.dropdown-toggle[aria-expanded="true"],
342
+ .btn-secondary:not(:disabled):not(:disabled):focus,
343
+ .btn-secondary:not(:disabled):not(:disabled):active:focus,
344
+ .btn-secondary.dropdown-toggle[aria-expanded="true"] {
345
+ box-shadow: 0 0 0 0.2rem rgba(218, 55, 55, 0.5); }
346
+
347
+ .card {
348
+ border: 0;
349
+ background: none; }
350
+ .card .card-header {
351
+ background: #dee2e6;
352
+ border: 0;
353
+ color: #22252a;
354
+ font-size: larger;
355
+ font-weight: bold;
356
+ border-bottom: 4px solid #ccd1d6;
357
+ border-radius: 0.5rem 0.5rem 0 0;
358
+ font-size: 1.4rem; }
359
+ @media screen and (max-width: 400px) {
360
+ .card .card-header {
361
+ font-size: 1.35rem; } }
362
+ .card .card-header .card-icon {
363
+ background: #da3737;
364
+ padding: 0.325rem 0.75em 0.325rem 0.325em;
365
+ border-radius: 0 1cm 1cm 0;
366
+ line-height: inherit;
367
+ margin: -0.325rem 0 -0.325rem -1.25rem;
368
+ color: white; }
369
+ .card .card-header .card-icon::before {
370
+ min-width: 1.75rem;
371
+ text-align: center;
372
+ display: block; }
373
+ .card .card-header .divider {
374
+ color: #da3737; }
375
+ .card .card-header .subtitle {
376
+ font-weight: normal;
377
+ font-size: 0.8em; }
378
+ .card .card-body {
379
+ background: #FFFFFF; }
380
+ .card .card-footer {
381
+ background: #dee2e6;
382
+ border: 0;
383
+ border-radius: 0 0 0.5rem 0.5rem; }
384
+
385
+ .dropdown {
386
+ display: inline-block; }
387
+ .dropdown .dropdown-item {
388
+ padding-left: 0.75rem;
389
+ padding-right: 0.75rem; }
390
+ .dropdown .dropdown-item .fas {
391
+ margin-right: 0.75rem; }
392
+ .dropdown .icon-only::after {
393
+ display: none; }
394
+
395
+ .dropdown-menu {
396
+ border: 1px solid #2d3138;
397
+ border-radius: .5rem;
398
+ box-shadow: 0px 2px 5px 0px #505762bf; }
399
+ .dropdown-menu button:hover {
400
+ cursor: pointer;
401
+ background: rgba(218, 55, 55, 0.15); }
402
+ .dropdown-menu button:hover .fas,
403
+ .dropdown-menu button:hover .fab {
404
+ color: #da3737; }
405
+ .dropdown-menu .dropdown-item .fas {
406
+ min-width: 1.1rem;
407
+ text-align: center; }
408
+ .dropdown-menu .dropdown-item.active,
409
+ .dropdown-menu .dropdown-item:active {
410
+ background: #da3737;
411
+ color: #FFFFFF; }
412
+ .dropdown-menu .dropdown-item.active .fas,
413
+ .dropdown-menu .dropdown-item.active .fab,
414
+ .dropdown-menu .dropdown-item:active .fas,
415
+ .dropdown-menu .dropdown-item:active .fab {
416
+ color: inherit; }
417
+
418
+ .error {
419
+ display: flex;
420
+ height: 100%;
421
+ justify-content: center;
422
+ align-items: center;
423
+ flex-direction: column; }
424
+ .error .box {
425
+ color: #9ca3af;
426
+ border-radius: 1rem;
427
+ text-align: center;
428
+ padding: 1.25rem;
429
+ background: #565e6b; }
430
+ .error .box > :last-child {
431
+ margin-bottom: 0; }
432
+ .error .fas {
433
+ font-size: 4rem;
434
+ margin-bottom: 1rem; }
435
+
436
+ .laboratory > .card-body {
437
+ padding: 0;
438
+ display: grid;
439
+ grid-template-columns: 380px 1fr; }
440
+ @media screen and (max-width: 840px) {
441
+ .laboratory > .card-body {
442
+ grid-template-columns: 344px 1fr; } }
443
+ @media screen and (max-width: 800px) {
444
+ .laboratory > .card-body {
445
+ grid-template-columns: 1fr;
446
+ grid-template-rows: auto auto; } }
447
+ .laboratory #laboratory-import-file {
448
+ display: none; }
449
+ .laboratory .laboratory-blueprint {
450
+ background: #dee2e6; }
451
+
452
+ .blueprint-form {
453
+ background: #dee2e6; }
454
+ .blueprint-form .btn-help {
455
+ color: #b1b7bd;
456
+ box-shadow: none;
457
+ margin-right: -0.25em; }
458
+ .blueprint-form .btn-help:hover {
459
+ color: #da3737; }
460
+ .blueprint-form .btn-help .fas {
461
+ background: none; }
462
+ .blueprint-form .card {
463
+ overflow: visible; }
464
+ .blueprint-form .card-body {
465
+ padding: 0;
466
+ overflow: visible; }
467
+ .blueprint-form .card-body .card-header {
468
+ border-bottom: 1px solid #ccd1d6; }
469
+ .blueprint-form form {
470
+ background: #FFFFFF; }
471
+ .blueprint-form form[data-method="quickstart"] .manual-only {
472
+ display: none; }
473
+ .blueprint-form form[data-method="manual"] .quickstart-only {
474
+ display: none; }
475
+ .blueprint-form form:not([data-rank="solo"]) .solo-only {
476
+ display: none; }
477
+ .blueprint-form .form-group {
478
+ margin: 0;
479
+ display: flex; }
480
+ .blueprint-form .form-group.hidden {
481
+ display: none; }
482
+ .blueprint-form .form-group:not(:last-child) {
483
+ border-bottom: 1px solid #dee2e6; }
484
+ .blueprint-form .form-group > label {
485
+ width: 7.5rem;
486
+ flex-shrink: 0;
487
+ margin: 0;
488
+ font-weight: bold;
489
+ padding: 0.325rem 0.75rem;
490
+ box-sizing: border-box;
491
+ display: flex;
492
+ text-align: right;
493
+ justify-content: flex-end;
494
+ border-right: 1px solid #dee2e6;
495
+ background: rgba(222, 226, 230, 0.5);
496
+ line-height: calc(2.375rem - 0.75rem); }
497
+ .blueprint-form .form-group input,
498
+ .blueprint-form .form-group select {
499
+ border: 0;
500
+ background: none; }
501
+ .blueprint-form .form-group input::placeholder {
502
+ color: rgba(102, 111, 127, 0.5); }
503
+ .blueprint-form .form-group select {
504
+ padding-left: 0.5rem; }
505
+ .blueprint-form .form-group textarea {
506
+ padding: .375rem .75rem;
507
+ border: 0;
508
+ width: 100%;
509
+ box-sizing: border-box;
510
+ resize: vertical;
511
+ color: #495057;
512
+ min-height: 2.375rem;
513
+ font-size: 0.8em; }
514
+ .blueprint-form .form-group > :last-child {
515
+ margin-bottom: 0; }
516
+ .blueprint-form .form-group.section-end {
517
+ border-bottom: 2px solid #dee2e6; }
518
+ .blueprint-form .form-group .flex-input {
519
+ width: 100%;
520
+ display: flex; }
521
+ .blueprint-form .form-group .flex-input span {
522
+ opacity: 0.5;
523
+ padding: 0 0.5em;
524
+ display: flex;
525
+ align-items: center;
526
+ color: #b2b7c9; }
527
+ .blueprint-form .form-radio-list {
528
+ width: 100%;
529
+ display: flex;
530
+ padding: .375rem .75rem; }
531
+ .blueprint-form .form-radio-list .form-check-input:checked ~ * {
532
+ background: #da3737;
533
+ color: #FFFFFF;
534
+ font-weight: bold; }
535
+ .blueprint-form .form-radio-list .form-check-input {
536
+ display: none; }
537
+ .blueprint-form .form-radio-list .form-check {
538
+ flex-grow: 1;
539
+ margin: 0;
540
+ flex-shrink: 0;
541
+ width: 50%; }
542
+ .blueprint-form .form-radio-list .form-check:first-child .form-check-label {
543
+ border-radius: 4px 0 0 4px; }
544
+ .blueprint-form .form-radio-list .form-check:last-child .form-check-label {
545
+ border-radius: 0 4px 4px 0; }
546
+ .blueprint-form .form-radio-list .form-check-label {
547
+ flex-grow: 1;
548
+ text-align: center;
549
+ background: #dee2e6;
550
+ text-transform: uppercase;
551
+ font-size: 0.75rem;
552
+ color: #666f7f; }
553
+ .blueprint-form .form-radio-list .form-check-label:hover {
554
+ cursor: pointer; }
555
+ .blueprint-form .repeatable-section .card-footer {
556
+ background: #eef0f2;
557
+ padding-left: 0.75rem;
558
+ padding-right: 0.75rem; }
559
+ .blueprint-form .repeatable-item {
560
+ border-bottom: 2px solid #dee2e6;
561
+ position: relative; }
562
+ .blueprint-form .repeatable-item .dropdown-options {
563
+ position: absolute;
564
+ top: 0.325rem;
565
+ right: 0.75rem; }
566
+ .blueprint-form .repeatable-item .dropdown-options .btn {
567
+ border-color: #da3737; }
568
+ .blueprint-form .repeatable-item .dropdown-toggle {
569
+ opacity: .1; }
570
+ .blueprint-form .repeatable-item .dropdown-toggle:disabled {
571
+ display: none; }
572
+ .blueprint-form .repeatable-item .dropdown-toggle:hover, .blueprint-form .repeatable-item .dropdown-toggle[aria-expanded="true"] {
573
+ opacity: 1; }
574
+ .blueprint-form .accordion .card {
575
+ border-radius: 0; }
576
+ .blueprint-form .accordion .card .card-header {
577
+ padding: 0;
578
+ border-radius: 0;
579
+ display: flex;
580
+ border-bottom: 1px solid #ccd1d6;
581
+ margin-bottom: 0; }
582
+ .blueprint-form .accordion .card .card-header button {
583
+ background: #dee2e6;
584
+ display: block;
585
+ text-align: left;
586
+ font-weight: bold;
587
+ width: 100%;
588
+ color: #2d3138;
589
+ text-decoration: none;
590
+ padding: 0;
591
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
592
+ border-radius: 0;
593
+ border: 0;
594
+ display: flex;
595
+ align-items: center;
596
+ padding: 0.1875rem 0; }
597
+ .blueprint-form .accordion .card .card-header button .title {
598
+ flex-grow: 1;
599
+ margin-left: 0.325rem; }
600
+ .blueprint-form .accordion .card .card-header button:hover, .blueprint-form .accordion .card .card-header button[aria-expanded="true"] {
601
+ background: #da3737;
602
+ color: #FFFFFF; }
603
+ .blueprint-form .accordion .card .card-header button:hover .badge, .blueprint-form .accordion .card .card-header button[aria-expanded="true"] .badge {
604
+ background: #FFFFFF;
605
+ color: #da3737; }
606
+ .blueprint-form .accordion .card .card-header button .fa-chevron-right::before {
607
+ position: relative;
608
+ left: 1px; }
609
+ .blueprint-form .accordion .card .card-header button[aria-expanded="true"] .fa-chevron-right::before {
610
+ transform: rotate(90deg); }
611
+ .blueprint-form .accordion .card .card-header .badge {
612
+ background-color: #b1b7bd;
613
+ border-radius: 1cm;
614
+ padding: 0 0.325rem;
615
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
616
+ color: white;
617
+ float: right;
618
+ margin-right: 0.75rem;
619
+ line-height: 1.5; }
620
+ .blueprint-form .accordion .card .card-header .fas {
621
+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
622
+ color: white;
623
+ border-radius: 1cm;
624
+ margin: 0 0 0 0.325rem;
625
+ width: 1.5rem;
626
+ height: 1.5rem;
627
+ padding: 0;
628
+ display: flex;
629
+ justify-content: center;
630
+ align-items: center; }
631
+ .blueprint-form .accordion .card .card-header .fas::before {
632
+ transition: transform .15s ease-in-out; }
633
+ .blueprint-form .accordion .card .card-footer {
634
+ border-radius: 0; }
635
+ .blueprint-form .accordion .card .collapse.show {
636
+ border-bottom: 1px solid #ccd1d6; }
637
+ .blueprint-form > .card-footer {
638
+ padding-left: 0.75rem;
639
+ padding-right: 0.75rem; }
640
+
641
+ #modal-blueprint-traits .modal-body:not([filter='any']) .trait.any, #modal-blueprint-traits .modal-body:not([filter='controller']) .trait.controller, #modal-blueprint-traits .modal-body:not([filter='defender']) .trait.defender, #modal-blueprint-traits .modal-body:not([filter='lurker']) .trait.lurker, #modal-blueprint-traits .modal-body:not([filter='striker']) .trait.striker, #modal-blueprint-traits .modal-body:not([filter='supporter']) .trait.supporter, #modal-blueprint-traits .modal-body:not([filter='sniper']) .trait.sniper, #modal-blueprint-traits .modal-body:not([filter='scout']) .trait.scout {
642
+ display: none; }
643
+ #modal-blueprint-traits .modal-body select {
644
+ margin-bottom: 1.25rem; }
645
+ #modal-blueprint-traits .modal-body ul {
646
+ list-style: none;
647
+ padding-left: 0; }
648
+ #modal-blueprint-traits .modal-body ul .title {
649
+ margin: 0; }
650
+ #modal-blueprint-traits .modal-body ul .description {
651
+ font-size: small;
652
+ margin: 0; }
653
+ #modal-blueprint-traits .modal-body .form-check:hover {
654
+ background: #eef0f2;
655
+ margin-left: -1.25rem;
656
+ margin-right: -1.25rem;
657
+ padding-left: 2.5rem;
658
+ padding-right: 1.25rem; }
659
+ #modal-blueprint-traits .modal-body .form-check-label {
660
+ cursor: pointer;
661
+ padding-top: 0.325rem;
662
+ padding-bottom: 0.325rem;
663
+ width: 100%; }
664
+ #modal-blueprint-traits .modal-body .form-check-input {
665
+ top: 0.325rem; }
666
+ #modal-blueprint-traits .modal-body .form-check-input:checked ~ label {
667
+ color: #da3737; }
668
+
669
+ #modal-markdown .accordion-markdown-help table {
670
+ background: #dee2e659;
671
+ overflow: hidden;
672
+ border-radius: 0.5em;
673
+ border: none; }
674
+ #modal-markdown .accordion-markdown-help table td {
675
+ border: none; }
676
+ #modal-markdown .accordion-markdown-help .card:not(:first-child) {
677
+ margin-top: 1rem; }
678
+ #modal-markdown .accordion-markdown-help .collapse.show {
679
+ border-bottom: none; }
680
+ #modal-markdown .accordion-markdown-help .card-header {
681
+ border: none;
682
+ background: none;
683
+ margin-left: -0.25em;
684
+ margin-right: -1em; }
685
+ #modal-markdown .accordion-markdown-help .card-header button {
686
+ background: #da3737;
687
+ color: #FFFFFF;
688
+ font-weight: bold;
689
+ padding-left: 0.1875rem;
690
+ padding-right: 0.5em;
691
+ border-radius: 1em 0 0 1em; }
692
+ #modal-markdown .accordion-markdown-help .card-header button::before {
693
+ content: "\f054";
694
+ transition: transform .15s ease-in-out;
695
+ font-family: "Font Awesome 5 Free";
696
+ -webkit-font-smoothing: antialiased;
697
+ font-style: normal;
698
+ font-variant: normal;
699
+ text-rendering: auto;
700
+ margin-right: 0.5em;
701
+ transform: rotate(90deg);
702
+ background: #da3737;
703
+ color: white;
704
+ width: 1.5em;
705
+ border-radius: 1em;
706
+ text-align: center; }
707
+ #modal-markdown .accordion-markdown-help .card-header button.collapsed::before {
708
+ transform: rotate(0deg); }
709
+ #modal-markdown .accordion-markdown-help .card-header button.collapsed:not(:hover) {
710
+ background: #dee2e6;
711
+ color: inherit; }
712
+ #modal-markdown .accordion-markdown-help .card-body {
713
+ padding: 1rem 0 0; }
714
+ #modal-markdown .accordion-markdown-help .card-body > :last-child {
715
+ margin-bottom: 0; }
716
+
717
+ .monster-preview {
718
+ background-color: #ccd1d6;
719
+ display: flex;
720
+ flex-direction: column;
721
+ justify-content: flex-start;
722
+ align-items: center;
723
+ padding: 1.25rem 10px;
724
+ background-image: linear-gradient(45deg, #ccd1d6 25%, #c6ccd1 25%, #c6ccd1 50%, #ccd1d6 50%, #ccd1d6 75%, #c6ccd1 75%, #c6ccd1 100%);
725
+ background-size: 10px 10px; }
726
+ .monster-preview .btn-png {
727
+ margin-top: 1.25rem;
728
+ box-shadow: 0px 5px 10px 0px #50576240; }
729
+ .monster-preview .btn-png .fas {
730
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; }
731
+ .monster-preview .btn-png:not(:hover) {
732
+ background: #FFFFFF;
733
+ border-color: #FFFFFF;
734
+ color: #666f7f; }
735
+ .monster-preview .btn-png:not(:hover) .fas {
736
+ color: #FFFFFF; }
737
+ .monster-preview .btn-columns {
738
+ margin-top: 1.25rem;
739
+ box-shadow: 0px 5px 10px 0px #50576240; }
740
+ .monster-preview .btn-columns .fas {
741
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; }
742
+ .monster-preview .btn-columns:not(:hover) {
743
+ background: #FFFFFF;
744
+ border-color: #FFFFFF; }
745
+ .monster-preview .btn-columns:not(:hover) .fas {
746
+ color: #da3737;
747
+ background: none; }
748
+
749
+ .modal-backdrop.show {
750
+ opacity: 0.75; }
751
+
752
+ .modal .modal-header {
753
+ background: #22252a;
754
+ color: white;
755
+ border-bottom: 0;
756
+ border-radius: 0;
757
+ padding: 0.75rem 1.25rem;
758
+ border-bottom: 4px solid #dee2e6; }
759
+ .modal .modal-header .card-icon {
760
+ background: #da3737;
761
+ padding: 0.325rem 0.75rem 0.325rem 0.325rem;
762
+ border-radius: 0 1cm 1cm 0;
763
+ line-height: inherit;
764
+ margin: -0.325rem 0 -0.325rem -1.25rem; }
765
+ .modal .modal-header .card-icon::before {
766
+ min-width: 1.75rem;
767
+ text-align: center;
768
+ display: block; }
769
+ .modal .modal-header .modal-title {
770
+ font-weight: bold; }
771
+ .modal .modal-header .close {
772
+ opacity: 1;
773
+ color: #2d3138;
774
+ text-shadow: none;
775
+ margin: -0.75rem -1.25rem -0.75rem auto;
776
+ padding: 0.9rem 1.25rem; }
777
+ .modal .modal-header .close span {
778
+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; }
779
+ .modal .modal-header .close:hover, .modal .modal-header .close:focus {
780
+ color: white;
781
+ outline: none;
782
+ opacity: 1; }
783
+ .modal .modal-header .close:hover span, .modal .modal-header .close:focus span {
784
+ background: #da3737; }
785
+ .modal .modal-header .close span {
786
+ background: #666f7f;
787
+ display: block;
788
+ border-radius: 1cm 0 0 1cm;
789
+ padding: 0 0.75rem 0 0.75rem;
790
+ margin-right: -1.25rem; }
791
+ .modal .modal-content {
792
+ border: 1px solid transparent;
793
+ background: none;
794
+ overflow: hidden;
795
+ border: 2px solid #da3737;
796
+ border-radius: 0.75rem; }
797
+ .modal .modal-body {
798
+ background: white;
799
+ padding: 1.25rem; }
800
+ .modal .modal-body > :last-child {
801
+ margin-bottom: 0; }
802
+ .modal .modal-footer {
803
+ background: #dee2e6;
804
+ border-top: 0;
805
+ padding: 0.75rem 1.25rem; }
806
+
807
+ #modal-settings .settings {
808
+ border: 4px solid #dee2e6;
809
+ border-radius: 1rem; }
810
+ #modal-settings .setting .btn {
811
+ margin-left: 0.5rem; }
812
+ #modal-settings .setting .content {
813
+ display: flex;
814
+ align-items: center;
815
+ padding: 0.75rem 1.25rem; }
816
+ #modal-settings .setting .confirmation {
817
+ display: none;
818
+ color: #da3737;
819
+ padding: 0.75rem 1.25rem; }
820
+ #modal-settings .setting .confirmed {
821
+ display: none;
822
+ color: green;
823
+ padding: 0.75rem 1.25rem; }
824
+ #modal-settings .setting .confirmed .fa-check-circle {
825
+ font-size: 2.5em; }
826
+ #modal-settings .setting select.form-control {
827
+ width: auto;
828
+ margin-left: 1em;
829
+ cursor: pointer; }
830
+ #modal-settings .setting.confirm .content,
831
+ #modal-settings .setting.confirm .confirmed {
832
+ display: none; }
833
+ #modal-settings .setting.confirm .confirmation {
834
+ display: flex;
835
+ align-items: center; }
836
+ #modal-settings .setting.confirmed .content,
837
+ #modal-settings .setting.confirmed .confirmation {
838
+ display: none; }
839
+ #modal-settings .setting.confirmed .confirmed {
840
+ display: flex;
841
+ align-items: center; }
842
+ #modal-settings .setting + .setting {
843
+ border-top: 2px solid #dee2e6; }
844
+ #modal-settings .setting .description {
845
+ flex-grow: 1; }
846
+ #modal-settings .setting .description .title {
847
+ font-weight: bold;
848
+ margin: 0;
849
+ text-transform: uppercase;
850
+ font-size: 0.9rem; }
851
+ #modal-settings .setting .description > :last-child {
852
+ margin-bottom: 0; }
853
+
854
+ #modal-gmbinder .modal-body {
855
+ white-space: pre-line;
856
+ font-family: monospace;
857
+ font-size: small; }
858
+
859
+ .monster {
860
+ font-size: 0.875rem;
861
+ position: relative;
862
+ width: 28.6em;
863
+ box-shadow: 0px 5px 10px 0px #50576240;
864
+ display: flex;
865
+ flex-direction: column; }
866
+ .monster > :first-child {
867
+ margin-top: 0; }
868
+ .monster > :last-child {
869
+ margin-bottom: 0; }
870
+ .monster .monster-contents {
871
+ width: 100%; }
872
+ .monster .monster-contents .monster-contents-body {
873
+ padding: 1.42em;
874
+ background: white; }
875
+ .monster.quickstart:not(.rank-solo) .solo-only {
876
+ display: none; }
877
+ .monster.quickstart .monster-header .monster-quickstart {
878
+ font-size: 0.8em;
879
+ font-weight: bold;
880
+ text-align: right;
881
+ margin-left: 0.8em;
882
+ flex-shrink: 0; }
883
+ .monster .monster-image.inline + * {
884
+ margin-top: 1.42em; }
885
+ .monster .monster-image img {
886
+ width: 100%;
887
+ border-radius: 0.25em; }
888
+ .monster .monster-image.banner {
889
+ width: 100%; }
890
+ .monster .monster-image.banner img {
891
+ border-radius: 0; }
892
+ .monster .monster-core > :last-child {
893
+ margin-bottom: 0; }
894
+ .monster .monster-core + * {
895
+ margin-top: 0.57em; }
896
+ .monster .monster-header {
897
+ display: inline-flex;
898
+ width: 100%;
899
+ justify-content: space-between;
900
+ align-items: flex-end; }
901
+ .monster .monster-header h4 {
902
+ font-weight: bold;
903
+ color: #9a1515;
904
+ margin: 0;
905
+ line-height: 1;
906
+ font-size: 2em;
907
+ font-family: "Alegreya Sans SC", sans-serif;
908
+ margin-top: -0.1em; }
909
+ .monster .monster-header p {
910
+ margin: 0; }
911
+ .monster .monster-header .monster-description {
912
+ font-style: italic;
913
+ font-size: 0.8em; }
914
+ .monster .monster-header .monster-description span:first-of-type {
915
+ display: inline-block; }
916
+ .monster .monster-header .monster-description span:first-of-type::first-letter {
917
+ text-transform: uppercase; }
918
+ .monster .monster-header .monster-description span + span::before {
919
+ content: " "; }
920
+ .monster .monster-header .monster-description * + .alignment::before {
921
+ content: ", "; }
922
+ .monster .monster-ac,
923
+ .monster .monster-hp,
924
+ .monster .monster-speed,
925
+ .monster .monster-saves,
926
+ .monster .monster-skills,
927
+ .monster .monster-languages,
928
+ .monster .monster-senses,
929
+ .monster .monster-immunities,
930
+ .monster .monster-vulnerabilities,
931
+ .monster .monster-resistances,
932
+ .monster .monster-conditions,
933
+ .monster .monster-challenge {
934
+ display: flex;
935
+ flex-wrap: wrap; }
936
+ .monster h5 {
937
+ font-weight: bold;
938
+ color: #9a1515;
939
+ font-family: "Alegreya Sans SC", sans-serif;
940
+ display: inline-block;
941
+ width: 100%;
942
+ margin-bottom: 0;
943
+ font-size: 1.45em;
944
+ margin-top: 0.36em !important; }
945
+ .monster h5 + * {
946
+ margin-top: 0.52em; }
947
+ .monster hr {
948
+ margin: 0.285em 0 0;
949
+ width: 100%;
950
+ min-height: 1px;
951
+ height: 0.143em;
952
+ border: 0;
953
+ background: linear-gradient(to right, rgba(154, 21, 21, 0.75), rgba(154, 21, 21, 0));
954
+ -webkit-column-break-inside: avoid;
955
+ page-break-inside: avoid;
956
+ break-inside: avoid; }
957
+ .monster hr:first-of-type, .monster hr:last-of-type {
958
+ height: 0.2143em;
959
+ background: linear-gradient(to right, #9a1515, rgba(154, 21, 21, 0)); }
960
+ .monster hr + * {
961
+ margin-top: 0.285em; }
962
+ .monster hr:last-of-type + * {
963
+ margin-top: 0.57em; }
964
+ .monster .label {
965
+ font-weight: bold; }
966
+ .monster .monster-abilities {
967
+ display: inline-grid;
968
+ width: 100%;
969
+ grid-template-columns: repeat(6, 1fr);
970
+ text-align: center;
971
+ line-height: 1.4; }
972
+ .monster .monster-abilities .label {
973
+ color: #9a1515;
974
+ display: block;
975
+ text-transform: uppercase; }
976
+ .monster ul {
977
+ list-style: none;
978
+ padding: 0;
979
+ margin-bottom: 0; }
980
+ .monster ul .label {
981
+ color: #9a1515; }
982
+ .monster ul li > p {
983
+ margin: 0; }
984
+ .monster p {
985
+ margin-bottom: 0; }
986
+ .monster p + * {
987
+ margin-top: 0.57em; }
988
+ .monster .monster-trait + *,
989
+ .monster .monster-action + *,
990
+ .monster .monster-reaction + *,
991
+ .monster .monster-legendary-action + *,
992
+ .monster .monster-lair-action + * {
993
+ margin-top: 0.57em; }
994
+ .monster .monster-trait p + *,
995
+ .monster .monster-action p + *,
996
+ .monster .monster-reaction p + *,
997
+ .monster .monster-legendary-action p + *,
998
+ .monster .monster-lair-action p + * {
999
+ margin-top: 0.57em; }
1000
+ .monster .monster-trait .name,
1001
+ .monster .monster-action .name,
1002
+ .monster .monster-reaction .name,
1003
+ .monster .monster-legendary-action .name,
1004
+ .monster .monster-lair-action .name {
1005
+ font-weight: bold;
1006
+ font-style: italic; }
1007
+ .monster .monster-trait > :last-child,
1008
+ .monster .monster-action > :last-child,
1009
+ .monster .monster-reaction > :last-child,
1010
+ .monster .monster-legendary-action > :last-child,
1011
+ .monster .monster-lair-action > :last-child {
1012
+ margin-bottom: 0; }
1013
+ .monster .lair-initiative,
1014
+ .monster .legendary-per-round,
1015
+ .monster .paragon-actions {
1016
+ font-size: 0.8em;
1017
+ font-style: italic; }
1018
+ .monster .monster-notes + * {
1019
+ margin-top: 0.57em; }
1020
+ .monster hr + .h5-border {
1021
+ display: none; }
1022
+ .monster .monster-footer {
1023
+ font-style: italic;
1024
+ opacity: 0.5;
1025
+ font-size: 0.8em; }
1026
+ .monster .line-break {
1027
+ display: block;
1028
+ height: 0.57em; }
1029
+ .monster .h5-border {
1030
+ min-height: 1px;
1031
+ height: 0.0714em;
1032
+ background: linear-gradient(to right, rgba(154, 21, 21, 0.75), rgba(154, 21, 21, 0));
1033
+ display: block;
1034
+ margin-top: 0;
1035
+ margin-bottom: 0.52em; }
1036
+ .monster .h5-border.notes {
1037
+ margin-top: 0.52em;
1038
+ height: 0.2143em; }
1039
+ @media screen and (max-width: 459px) {
1040
+ .monster.columns-1 {
1041
+ font-size: 0.75rem; } }
1042
+ .monster.columns-2 {
1043
+ width: 55em;
1044
+ font-size: 0.85rem; }
1045
+ @media screen and (max-width: 1200px) {
1046
+ .monster.columns-2 {
1047
+ font-size: 0.75rem; } }
1048
+ @media screen and (max-width: 1095px) {
1049
+ .monster.columns-2 {
1050
+ font-size: 0.6rem; } }
1051
+ @media screen and (max-width: 980px) {
1052
+ .monster.columns-2 {
1053
+ font-size: 0.5rem; } }
1054
+ @media screen and (max-width: 880px) {
1055
+ .monster.columns-2 {
1056
+ font-size: 0.45rem; } }
1057
+ @media screen and (max-width: 800px) {
1058
+ .monster.columns-2 {
1059
+ font-size: 0.7rem; } }
1060
+ @media screen and (max-width: 680px) {
1061
+ .monster.columns-2 {
1062
+ font-size: 0.6rem; } }
1063
+ @media screen and (max-width: 580px) {
1064
+ .monster.columns-2 {
1065
+ font-size: 0.5rem; } }
1066
+ @media screen and (max-width: 490px) {
1067
+ .monster.columns-2 {
1068
+ font-size: 0.4rem; } }
1069
+ @media screen and (max-width: 410px) {
1070
+ .monster.columns-2 {
1071
+ font-size: 0.35rem; } }
1072
+ @media screen and (max-width: 400px) {
1073
+ .monster.columns-2 {
1074
+ font-size: 0.5rem; } }
1075
+ @media screen and (max-width: 380px) {
1076
+ .monster.columns-2 {
1077
+ font-size: 0.45rem; } }
1078
+ @media screen and (max-width: 350px) {
1079
+ .monster.columns-2 {
1080
+ font-size: 0.38rem; } }
1081
+ .monster.columns-2 .monster-contents-body {
1082
+ column-count: 2;
1083
+ column-gap: 1.42em; }
1084
+ .monster .h5-traits {
1085
+ display: none; }
1086
+ .monster .h5-traits + .h5-border {
1087
+ display: none; }
1088
+ .monster .h5-traits + .h5-border + .monster-trait {
1089
+ margin-top: 0.57em; }
1090
+ .monster.theme-5e .monster-contents-body {
1091
+ background: url("https://i.imgur.com/wAhINL9.jpg"); }
1092
+ .monster.theme-5e .monster-contents-header,
1093
+ .monster.theme-5e .monster-contents-footer {
1094
+ height: 0.4em;
1095
+ min-height: 3px;
1096
+ background: #bd9b4c;
1097
+ border: 1px solid black;
1098
+ border-left: 0;
1099
+ border-right: 0;
1100
+ width: 100%;
1101
+ background-image: linear-gradient(45deg, #bd9b4c 25%, #b38720 25%, #b38720 50%, #bd9b4c 50%, #bd9b4c 75%, #b38720 75%, #b38720 100%);
1102
+ background-size: 5px 5px; }
1103
+ .monster.theme-transparent {
1104
+ box-shadow: none; }
1105
+ .monster.theme-transparent .monster-contents-body {
1106
+ background: none; }
1107
+ .monster.theme-giffyglyph {
1108
+ box-shadow: none; }
1109
+ .monster.theme-giffyglyph .h5-traits {
1110
+ display: block; }
1111
+ .monster.theme-giffyglyph ul {
1112
+ padding: 0 !important;
1113
+ margin-left: 1em;
1114
+ margin-right: 1em;
1115
+ border-radius: 0.5em;
1116
+ flex-direction: column;
1117
+ width: calc(100% - 2em);
1118
+ border: 1px dotted rgba(88, 24, 13, 0.1);
1119
+ overflow: hidden; }
1120
+ .monster.theme-giffyglyph ul li {
1121
+ display: flex;
1122
+ width: 100%; }
1123
+ .monster.theme-giffyglyph ul li:not(:last-child) {
1124
+ border-bottom: 1px dotted rgba(88, 24, 13, 0.1); }
1125
+ .monster.theme-giffyglyph ul li p {
1126
+ width: 100%;
1127
+ display: inline-flex; }
1128
+ .monster.theme-giffyglyph ul li p .label {
1129
+ font-family: "Alegreya Sans SC", sans-serif;
1130
+ margin-right: 0.5em;
1131
+ text-align: right;
1132
+ display: inline-block;
1133
+ width: 10.75em;
1134
+ flex-shrink: 0;
1135
+ font-size: 0.8em;
1136
+ line-height: 1.9;
1137
+ background: rgba(88, 24, 13, 0.05);
1138
+ padding-right: 0.5em; }
1139
+ .monster.theme-giffyglyph ul li p .label + span {
1140
+ display: inline-block;
1141
+ width: 100%;
1142
+ padding-right: 0.5em; }
1143
+ .monster.theme-giffyglyph hr {
1144
+ display: none; }
1145
+ .monster.theme-giffyglyph hr + * {
1146
+ margin-top: 0.5em; }
1147
+ .monster.theme-giffyglyph hr:first-of-type + * {
1148
+ margin-top: 1em; }
1149
+ .monster.theme-giffyglyph .quickstart-helpers {
1150
+ margin-top: 0.5em; }
1151
+ .monster.theme-giffyglyph .monster-contents-body {
1152
+ padding: 0;
1153
+ border-radius: 1em;
1154
+ overflow: hidden;
1155
+ box-shadow: 0px 5px 10px 0px #50576240; }
1156
+ .monster.theme-giffyglyph .monster-contents-body .monster-header {
1157
+ background: #58180d;
1158
+ color: #FFFFFF;
1159
+ padding: 0.75em 1em 0.5em; }
1160
+ .monster.theme-giffyglyph .monster-contents-body .monster-header > * {
1161
+ z-index: 1;
1162
+ position: relative; }
1163
+ .monster.theme-giffyglyph .monster-contents-body .monster-header h4 {
1164
+ color: #FFFFFF; }
1165
+ .monster.theme-giffyglyph .monster-contents-body > * {
1166
+ padding-left: 1em;
1167
+ padding-right: 1em; }
1168
+ .monster.theme-giffyglyph .monster-abilities {
1169
+ column-gap: 0.25em;
1170
+ margin-top: 0.5em;
1171
+ margin-bottom: 0; }
1172
+ .monster.theme-giffyglyph .monster-stats + hr + *:not(.quickstart-helpers) {
1173
+ margin-top: 0.5em !important; }
1174
+ .monster.theme-giffyglyph .h5-border {
1175
+ display: none; }
1176
+ .monster.theme-giffyglyph .quickstart-helpers li {
1177
+ display: flex; }
1178
+ .monster.theme-giffyglyph h5 {
1179
+ content: "Traits";
1180
+ background: rgba(88, 24, 13, 0.1);
1181
+ display: block;
1182
+ margin: 0 0.65em 0.3em;
1183
+ font-weight: bold;
1184
+ color: #9a1515;
1185
+ font-family: "Alegreya Sans SC", sans-serif;
1186
+ display: inline-block;
1187
+ width: calc(100% - 1.3em);
1188
+ padding: 0 0.5em !important;
1189
+ border-radius: 0.3em;
1190
+ line-height: 1.5; }
1191
+ .monster.theme-giffyglyph h5 > * {
1192
+ font-size: 1.45em; }
1193
+ .monster.theme-giffyglyph .monster-ability {
1194
+ background: rgba(88, 24, 13, 0.1);
1195
+ padding: 0.4em 0;
1196
+ border-radius: 0.5em; }
1197
+ .monster.theme-giffyglyph .monster-footer {
1198
+ padding-bottom: 1.4em; }
1199
+ .monster.theme-giffyglyph .monster-image.banner {
1200
+ background: #FFFFFF;
1201
+ border-radius: 0.5em 0.5em 0 0;
1202
+ overflow: hidden;
1203
+ border-bottom: 0;
1204
+ z-index: 1; }
1205
+ .monster.theme-giffyglyph .monster-image.banner + .monster-contents .monster-contents-body {
1206
+ border-top: 0;
1207
+ border-top-left-radius: 0;
1208
+ border-top-right-radius: 0; }
1209
+ .monster.theme-giffyglyph.columns-2 .monster-contents-body {
1210
+ padding-top: 1em;
1211
+ padding-bottom: 1em;
1212
+ column-gap: 0; }
1213
+ .monster.theme-giffyglyph.columns-2 .monster-header {
1214
+ border-radius: 0.5em;
1215
+ margin-left: 1em;
1216
+ width: calc(100% - 2em); }
1217
+ .monster.theme-giffyglyph.columns-2 .monster-footer {
1218
+ padding-bottom: 0; }
1219
+ .monster.theme-giffyglyph.columns-2 hr:first-of-type + * {
1220
+ margin-top: 0.5em; }
1221
+
1222
+ .panel {
1223
+ box-shadow: 0px 5px 10px 0px #505762; }
1224
+
1225
+ .vault > .card-header {
1226
+ padding-right: 0.75rem; }
1227
+ .vault > .card-body {
1228
+ padding: 0; }
1229
+ .vault > .card-footer {
1230
+ padding-left: 0.75rem;
1231
+ padding-right: 0.75rem; }
1232
+ .vault #vault-import-file,
1233
+ .vault #vault-import-srd {
1234
+ display: none; }
1235
+ .vault .dataTables_wrapper {
1236
+ display: flex;
1237
+ flex-direction: column; }
1238
+ .vault .dataTables_wrapper .top {
1239
+ display: flex;
1240
+ justify-content: space-between;
1241
+ padding: 0.325rem 0.75rem;
1242
+ background: #eef0f2;
1243
+ border-radius: 0;
1244
+ border-bottom: 0.25rem solid #da3737; }
1245
+ .vault .dataTables_wrapper .top .dataTables_length {
1246
+ min-width: 7rem;
1247
+ margin-right: 0.75rem; }
1248
+ .vault .dataTables_wrapper .top label {
1249
+ margin: 0;
1250
+ position: relative;
1251
+ width: 100%; }
1252
+ .vault .dataTables_wrapper .top label input {
1253
+ padding-right: 1.6rem; }
1254
+ .vault .dataTables_wrapper .top label input,
1255
+ .vault .dataTables_wrapper .top label select {
1256
+ border-radius: 1cm;
1257
+ font-size: inherit;
1258
+ line-height: inherit;
1259
+ padding-top: 0;
1260
+ padding-bottom: 0;
1261
+ height: auto;
1262
+ width: 100%;
1263
+ box-sizing: border-box;
1264
+ margin: 0; }
1265
+ .vault .dataTables_wrapper .top .dataTables_filter {
1266
+ flex-grow: 1;
1267
+ margin-right: 0;
1268
+ text-align: right; }
1269
+ .vault .dataTables_wrapper .top .dataTables_filter label {
1270
+ max-width: 16rem; }
1271
+ .vault .dataTables_wrapper .top .dataTables_filter label::after {
1272
+ font-family: "Font Awesome 5 Free";
1273
+ content: "\f002";
1274
+ -webkit-font-smoothing: antialiased;
1275
+ display: inline-block;
1276
+ font-style: normal;
1277
+ font-variant: normal;
1278
+ text-rendering: auto;
1279
+ position: absolute;
1280
+ right: 0.75rem;
1281
+ font-weight: 900;
1282
+ color: #666f7f;
1283
+ line-height: inherit; }
1284
+ .vault .dataTables_wrapper .content {
1285
+ overflow: hidden; }
1286
+ .vault .dataTables_wrapper table {
1287
+ margin: 0 !important;
1288
+ width: 100% !important;
1289
+ table-layout: fixed; }
1290
+ .vault .dataTables_wrapper table tbody tr:hover {
1291
+ background: #eef0f2;
1292
+ cursor: pointer; }
1293
+ .vault .dataTables_wrapper table td,
1294
+ .vault .dataTables_wrapper table th {
1295
+ box-sizing: border-box; }
1296
+ .vault .dataTables_wrapper table td {
1297
+ padding: 0; }
1298
+ .vault .dataTables_wrapper table th {
1299
+ background: #eef0f2;
1300
+ padding-top: 0.325rem;
1301
+ padding-bottom: 0.325rem; }
1302
+ .vault .dataTables_wrapper table th:not(:first-child) {
1303
+ border-left: 1px solid #dee2e6; }
1304
+ .vault .dataTables_wrapper table th::before, .vault .dataTables_wrapper table th::after {
1305
+ bottom: 0.4em;
1306
+ right: 0.5em;
1307
+ font-family: "Font Awesome 5 Free";
1308
+ color: #da3737; }
1309
+ @media screen and (max-width: 400px) {
1310
+ .vault .dataTables_wrapper table th::before, .vault .dataTables_wrapper table th::after {
1311
+ bottom: 0.25em; } }
1312
+ .vault .dataTables_wrapper table th::before {
1313
+ content: "\f884"; }
1314
+ .vault .dataTables_wrapper table th::after {
1315
+ content: "\f160"; }
1316
+ .vault .dataTables_wrapper table .sorting::after,
1317
+ .vault .dataTables_wrapper table .sorting_asc::after,
1318
+ .vault .dataTables_wrapper table .sorting_desc::before {
1319
+ opacity: 0; }
1320
+ .vault .dataTables_wrapper table .sorting::before {
1321
+ opacity: 0.1;
1322
+ color: inherit; }
1323
+ .vault .dataTables_wrapper table .col-id {
1324
+ width: 4rem;
1325
+ text-align: center; }
1326
+ .vault .dataTables_wrapper table .col-ac {
1327
+ width: 4rem;
1328
+ text-align: center; }
1329
+ .vault .dataTables_wrapper table .col-hp {
1330
+ width: 5rem;
1331
+ text-align: center; }
1332
+ .vault .dataTables_wrapper table .col-level {
1333
+ width: 4rem;
1334
+ text-align: center; }
1335
+ .vault .dataTables_wrapper table .col-role {
1336
+ width: 6rem; }
1337
+ .vault .dataTables_wrapper table .col-rank {
1338
+ width: 5.75rem; }
1339
+ .vault .dataTables_wrapper table .col-cr {
1340
+ width: 4rem;
1341
+ text-align: center; }
1342
+ .vault .dataTables_wrapper table .col-description,
1343
+ .vault .dataTables_wrapper table .col-role-rank,
1344
+ .vault .dataTables_wrapper table .col-ac-hp {
1345
+ overflow: hidden;
1346
+ width: 0; }
1347
+ .vault .dataTables_wrapper table .dataTables_empty {
1348
+ padding: 0.5rem 0.75rem; }
1349
+ @media screen and (max-width: 800px) {
1350
+ .vault .dataTables_wrapper table .col-ac,
1351
+ .vault .dataTables_wrapper table .col-hp,
1352
+ .vault .dataTables_wrapper table .col-role,
1353
+ .vault .dataTables_wrapper table .col-rank {
1354
+ overflow: hidden !important;
1355
+ width: 0;
1356
+ padding: 0 !important;
1357
+ border-right: none !important; } }
1358
+ .vault .dataTables_wrapper table .table-card {
1359
+ display: flex;
1360
+ flex-direction: row; }
1361
+ .vault .dataTables_wrapper table .table-card .col-id {
1362
+ text-align: center;
1363
+ flex-shrink: 0;
1364
+ font-weight: bold; }
1365
+ .vault .dataTables_wrapper table .table-card .col-name {
1366
+ white-space: normal;
1367
+ flex-grow: 1; }
1368
+ .vault .dataTables_wrapper table .table-card .col-name .name {
1369
+ margin: 0;
1370
+ font-weight: bold; }
1371
+ .vault .dataTables_wrapper table .table-card .col-name .role {
1372
+ font-size: 0.7em;
1373
+ font-style: italic;
1374
+ opacity: .75;
1375
+ margin: 0.25em 0 0; }
1376
+ .vault .dataTables_wrapper table .table-card .col-name .role .fas {
1377
+ opacity: .5; }
1378
+ .vault .dataTables_wrapper table .table-card .col-name .role:not(.rank-solo) .players {
1379
+ display: none; }
1380
+ .vault .dataTables_wrapper table .table-card .col-name .details,
1381
+ .vault .dataTables_wrapper table .table-card .col-name .stats {
1382
+ font-size: 0.7em;
1383
+ font-style: italic;
1384
+ opacity: .75;
1385
+ margin: 0; }
1386
+ .vault .dataTables_wrapper table .table-card .col-hp::after {
1387
+ font-family: "Font Awesome 5 Free";
1388
+ content: " \f004";
1389
+ color: #da3737; }
1390
+ .vault .dataTables_wrapper table .table-card .col-id,
1391
+ .vault .dataTables_wrapper table .table-card .col-name,
1392
+ .vault .dataTables_wrapper table .table-card .col-ac,
1393
+ .vault .dataTables_wrapper table .table-card .col-hp,
1394
+ .vault .dataTables_wrapper table .table-card .col-level,
1395
+ .vault .dataTables_wrapper table .table-card .col-role,
1396
+ .vault .dataTables_wrapper table .table-card .col-rank,
1397
+ .vault .dataTables_wrapper table .table-card .col-cr {
1398
+ padding: 0.5rem 0.75rem;
1399
+ overflow: hidden;
1400
+ text-overflow: ellipsis; }
1401
+ .vault .dataTables_wrapper table .table-card .col-id:not(:last-child),
1402
+ .vault .dataTables_wrapper table .table-card .col-name:not(:last-child),
1403
+ .vault .dataTables_wrapper table .table-card .col-ac:not(:last-child),
1404
+ .vault .dataTables_wrapper table .table-card .col-hp:not(:last-child),
1405
+ .vault .dataTables_wrapper table .table-card .col-level:not(:last-child),
1406
+ .vault .dataTables_wrapper table .table-card .col-role:not(:last-child),
1407
+ .vault .dataTables_wrapper table .table-card .col-rank:not(:last-child),
1408
+ .vault .dataTables_wrapper table .table-card .col-cr:not(:last-child) {
1409
+ border-right: 1px dotted #eef0f2; }
1410
+ .vault .dataTables_wrapper table .table-card .col-description,
1411
+ .vault .dataTables_wrapper table .table-card .col-role-rank,
1412
+ .vault .dataTables_wrapper table .table-card .col-ac-hp {
1413
+ overflow: hidden;
1414
+ width: 0; }
1415
+ .vault .dataTables_wrapper table .table-card .col-ac,
1416
+ .vault .dataTables_wrapper table .table-card .col-hp,
1417
+ .vault .dataTables_wrapper table .table-card .col-level,
1418
+ .vault .dataTables_wrapper table .table-card .col-role,
1419
+ .vault .dataTables_wrapper table .table-card .col-rank,
1420
+ .vault .dataTables_wrapper table .table-card .col-cr {
1421
+ flex-shrink: 0; }
1422
+ .vault .dataTables_wrapper table .table-card .col-rank:not(.rank-solo) .players {
1423
+ display: none; }
1424
+ .vault .dataTables_wrapper table .table-card.method-manual .role {
1425
+ display: none; }
1426
+ @media screen and (min-width: 801px) {
1427
+ .vault .dataTables_wrapper table .table-card .role {
1428
+ display: none; } }
1429
+ .vault .dataTables_wrapper .bottom {
1430
+ display: flex;
1431
+ justify-content: space-between;
1432
+ align-items: center;
1433
+ padding: 0.325rem 0.75rem;
1434
+ background: #eef0f2;
1435
+ border-radius: 0;
1436
+ border-top: 0.25rem solid #da3737; }
1437
+ .vault .dataTables_wrapper .bottom .dataTables_info {
1438
+ padding: 0;
1439
+ text-overflow: ellipsis;
1440
+ overflow: hidden;
1441
+ margin-right: 0.75rem;
1442
+ white-space: normal; }
1443
+ .vault .dataTables_wrapper .bottom .pagination {
1444
+ margin: 0; }
1445
+ @media screen and (max-width: 800px) {
1446
+ .vault .dataTables_wrapper .bottom {
1447
+ flex-direction: column; }
1448
+ .vault .dataTables_wrapper .bottom .dataTables_info {
1449
+ margin-bottom: 0.25rem;
1450
+ margin-right: 0; } }
1451
+ .vault .dataTables_wrapper .page-link {
1452
+ color: #da3737;
1453
+ background-color: white;
1454
+ border: 1px solid white;
1455
+ border: none;
1456
+ border-radius: 1cm;
1457
+ min-width: 2.2rem;
1458
+ line-height: 1.2;
1459
+ text-align: center;
1460
+ font-weight: bold; }
1461
+ .vault .dataTables_wrapper .page-item.active .page-link {
1462
+ background-color: #da3737;
1463
+ border-color: #da3737;
1464
+ color: #FFFFFF; }
1465
+ .vault .dataTables_wrapper .page-item.disabled .page-link {
1466
+ color: rgba(0, 0, 0, 0.25);
1467
+ background: #dee2e6;
1468
+ border: 1px solid #dee2e6; }
1469
+ .vault .dataTables_wrapper .page-item:not(:first-child) .page-link {
1470
+ margin-left: 2px; }
1471
+ .vault .dataTables_wrapper .page-item:first-child .page-link, .vault .dataTables_wrapper .page-item:last-child .page-link {
1472
+ border-radius: 100%; }
1473
+
1474
+ .vault.edit > .card-body {
1475
+ padding: 0;
1476
+ display: grid;
1477
+ grid-template-columns: 1fr 380px; }
1478
+ @media screen and (max-width: 840px) {
1479
+ .vault.edit > .card-body {
1480
+ grid-template-columns: 1fr 344px; } }
1481
+ @media screen and (max-width: 800px) {
1482
+ .vault.edit > .card-body {
1483
+ grid-template-columns: 1fr;
1484
+ grid-template-rows: auto auto; } }
1485
+ .vault.edit > .card-footer {
1486
+ display: flex;
1487
+ justify-content: space-between; }
1488
+ .vault.edit #monster-import-file {
1489
+ display: none; }
1490
+ .vault.edit .monster-blueprint {
1491
+ background: #dee2e6; }
1492
+
1493
+ /*# sourceMappingURL=monstermaker.1.0.3.3.css.map */
packages.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ chromium
2
+ wkhtmltopdf
3
+ xvfb
placeholder.png ADDED
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ accelerate
2
+ html2image
3
+ ftfy
4
+ gradio-client
5
+ torch
6
+ transformers
7
+ imgkit