Deploy Aether Garden application
Browse files- app.py +64 -26
- ui/relationship_graph.py +14 -10
- ui/styles.css +268 -0
app.py
CHANGED
|
@@ -356,7 +356,7 @@ def filter_entities(location_filter, type_filter, status_filter, search):
|
|
| 356 |
status=status_filter,
|
| 357 |
search=search or None,
|
| 358 |
)
|
| 359 |
-
return render_entity_grid(entities)
|
| 360 |
|
| 361 |
|
| 362 |
def filter_book(day, entry_type, search):
|
|
@@ -637,6 +637,13 @@ def build_app() -> gr.Blocks:
|
|
| 637 |
with gr.Blocks(**blocks_kwargs) as demo:
|
| 638 |
session_id = gr.State(value=str(uuid.uuid4()))
|
| 639 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 640 |
opening_gate = gr.HTML(value=opening_gate_html(), elem_id="realm-opening-host")
|
| 641 |
presence_bar = gr.HTML(value="", elem_id="presence-bar")
|
| 642 |
header = gr.HTML(value=get_header_html(), elem_classes=["realm-header-wrap"])
|
|
@@ -706,7 +713,6 @@ def build_app() -> gr.Blocks:
|
|
| 706 |
with gr.Column(elem_classes=["tome-offpage-store"]):
|
| 707 |
world_vignette = gr.HTML(value=render_world_vignette())
|
| 708 |
realm_diorama = gr.HTML(value="")
|
| 709 |
-
map_pick = gr.Textbox(visible=False, elem_id="map_location_pick")
|
| 710 |
with gr.Accordion("How this world works", open=False):
|
| 711 |
gr.HTML(
|
| 712 |
'<div class="how-it-works">'
|
|
@@ -747,7 +753,6 @@ def build_app() -> gr.Blocks:
|
|
| 747 |
container=False,
|
| 748 |
padding=False,
|
| 749 |
)
|
| 750 |
-
explore_place_pick = gr.Textbox(visible=False, elem_id="explore_place_pick")
|
| 751 |
wander_btn = gr.Button("β¦ Wander at random", variant="secondary", size="sm")
|
| 752 |
|
| 753 |
with gr.Column(scale=1, elem_classes=["tome-page-right", "tome-printed-page", "tome-explore-stage"]):
|
|
@@ -761,7 +766,6 @@ def build_app() -> gr.Blocks:
|
|
| 761 |
padding=False,
|
| 762 |
elem_id="explore-diorama-host",
|
| 763 |
)
|
| 764 |
-
portal_pick = gr.Textbox(visible=False, elem_id="portal_location_pick")
|
| 765 |
|
| 766 |
with gr.Column(elem_classes=["tome-offpage-store"]):
|
| 767 |
places_gallery = gr.Gallery(
|
|
@@ -794,7 +798,6 @@ def build_app() -> gr.Blocks:
|
|
| 794 |
with gr.Row(elem_classes=["tome-spread-row"]):
|
| 795 |
with gr.Column(scale=1, elem_classes=["tome-page-left", "tome-printed-page", "tome-book-index"]):
|
| 796 |
day_tabs = gr.HTML(value=render_day_tabs(_init_book_day))
|
| 797 |
-
book_day_pick = gr.Textbox(visible=False, elem_id="book_day_pick")
|
| 798 |
_day_choices = list(range(max(1, _init_book_day - 14), _init_book_day + 1))
|
| 799 |
book_day_select = gr.Dropdown(
|
| 800 |
choices=[(f"Day {d}", d) for d in reversed(_day_choices)],
|
|
@@ -849,8 +852,6 @@ def build_app() -> gr.Blocks:
|
|
| 849 |
rel_graph = gr.HTML(value=render_relationship_graph())
|
| 850 |
|
| 851 |
with gr.Tab("Souls of the Garden", id="entities"):
|
| 852 |
-
entity_pick = gr.Textbox(visible=False, elem_id="entity_pick")
|
| 853 |
-
|
| 854 |
with gr.Column(elem_classes=["tome-spread-shell"]):
|
| 855 |
with gr.Row(elem_classes=["tome-spread-row"]):
|
| 856 |
with gr.Column(scale=1, elem_classes=["tome-page-left", "tome-printed-page", "tome-souls-index"]):
|
|
@@ -972,6 +973,16 @@ def build_app() -> gr.Blocks:
|
|
| 972 |
_realm_map_pick,
|
| 973 |
inputs=[map_pick],
|
| 974 |
outputs=[world_map, location_panel],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 975 |
)
|
| 976 |
|
| 977 |
explore_place_pick.change(
|
|
@@ -982,6 +993,16 @@ def build_app() -> gr.Blocks:
|
|
| 982 |
lambda pick: int(pick) if pick and str(pick).isdigit() else None,
|
| 983 |
inputs=[explore_place_pick],
|
| 984 |
outputs=[explore_loc],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 985 |
)
|
| 986 |
|
| 987 |
portal_pick.change(
|
|
@@ -1107,7 +1128,7 @@ def build_app() -> gr.Blocks:
|
|
| 1107 |
f.change(
|
| 1108 |
filter_entities,
|
| 1109 |
[loc_filter, type_filter, status_filter, entity_search],
|
| 1110 |
-
[entity_grid],
|
| 1111 |
)
|
| 1112 |
|
| 1113 |
entity_pick.change(select_entity_by_id, [entity_pick], [entity_detail])
|
|
@@ -1635,29 +1656,38 @@ def build_app() -> gr.Blocks:
|
|
| 1635 |
wireTomeNav();
|
| 1636 |
wirePageExpand();
|
| 1637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1638 |
const bind = () => {
|
| 1639 |
document.querySelectorAll('#world-map [data-location-id]').forEach((node) => {
|
| 1640 |
if (node.dataset.mapBound) return;
|
| 1641 |
node.dataset.mapBound = '1';
|
| 1642 |
node.style.cursor = 'pointer';
|
| 1643 |
-
node.addEventListener('click', () => {
|
|
|
|
|
|
|
| 1644 |
const id = node.getAttribute('data-location-id');
|
| 1645 |
-
|
| 1646 |
-
const input = root && (root.querySelector('textarea') || root.querySelector('input'));
|
| 1647 |
-
if (input && id) {
|
| 1648 |
-
input.value = id;
|
| 1649 |
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
| 1650 |
-
}
|
| 1651 |
});
|
| 1652 |
});
|
| 1653 |
};
|
| 1654 |
const fireHiddenInput = (id, value) => {
|
| 1655 |
-
const
|
| 1656 |
-
|
| 1657 |
-
if (input) {
|
| 1658 |
-
input.value = value;
|
| 1659 |
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
| 1660 |
-
}
|
| 1661 |
};
|
| 1662 |
|
| 1663 |
const wireClickable = (el, handler) => {
|
|
@@ -1680,7 +1710,11 @@ def build_app() -> gr.Blocks:
|
|
| 1680 |
document.querySelectorAll('.place-ribbon-item').forEach((btn) => {
|
| 1681 |
wireClickable(btn, () => {
|
| 1682 |
const id = btn.getAttribute('data-location-id');
|
| 1683 |
-
if (id)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1684 |
});
|
| 1685 |
});
|
| 1686 |
document.querySelectorAll('.day-tab').forEach((btn) => {
|
|
@@ -1690,12 +1724,16 @@ def build_app() -> gr.Blocks:
|
|
| 1690 |
});
|
| 1691 |
});
|
| 1692 |
document.querySelectorAll('.entity-grid-card').forEach((card) => {
|
| 1693 |
-
|
| 1694 |
-
|
| 1695 |
card.style.cursor = 'pointer';
|
|
|
|
|
|
|
| 1696 |
wireClickable(card, () => {
|
| 1697 |
-
|
| 1698 |
-
|
|
|
|
|
|
|
| 1699 |
});
|
| 1700 |
});
|
| 1701 |
document.querySelectorAll('.location-modal-close').forEach((btn) => {
|
|
|
|
| 356 |
status=status_filter,
|
| 357 |
search=search or None,
|
| 358 |
)
|
| 359 |
+
return render_entity_grid(entities), render_entity_hologram(entities[0] if entities else None)
|
| 360 |
|
| 361 |
|
| 362 |
def filter_book(day, entry_type, search):
|
|
|
|
| 637 |
with gr.Blocks(**blocks_kwargs) as demo:
|
| 638 |
session_id = gr.State(value=str(uuid.uuid4()))
|
| 639 |
|
| 640 |
+
# Hidden pickers at root β Gradio won't wire events inside display:none offpage stores
|
| 641 |
+
map_pick = gr.Textbox(visible=False, elem_id="map_location_pick")
|
| 642 |
+
explore_place_pick = gr.Textbox(visible=False, elem_id="explore_place_pick")
|
| 643 |
+
book_day_pick = gr.Textbox(visible=False, elem_id="book_day_pick")
|
| 644 |
+
entity_pick = gr.Textbox(visible=False, elem_id="entity_pick")
|
| 645 |
+
portal_pick = gr.Textbox(visible=False, elem_id="portal_location_pick")
|
| 646 |
+
|
| 647 |
opening_gate = gr.HTML(value=opening_gate_html(), elem_id="realm-opening-host")
|
| 648 |
presence_bar = gr.HTML(value="", elem_id="presence-bar")
|
| 649 |
header = gr.HTML(value=get_header_html(), elem_classes=["realm-header-wrap"])
|
|
|
|
| 713 |
with gr.Column(elem_classes=["tome-offpage-store"]):
|
| 714 |
world_vignette = gr.HTML(value=render_world_vignette())
|
| 715 |
realm_diorama = gr.HTML(value="")
|
|
|
|
| 716 |
with gr.Accordion("How this world works", open=False):
|
| 717 |
gr.HTML(
|
| 718 |
'<div class="how-it-works">'
|
|
|
|
| 753 |
container=False,
|
| 754 |
padding=False,
|
| 755 |
)
|
|
|
|
| 756 |
wander_btn = gr.Button("β¦ Wander at random", variant="secondary", size="sm")
|
| 757 |
|
| 758 |
with gr.Column(scale=1, elem_classes=["tome-page-right", "tome-printed-page", "tome-explore-stage"]):
|
|
|
|
| 766 |
padding=False,
|
| 767 |
elem_id="explore-diorama-host",
|
| 768 |
)
|
|
|
|
| 769 |
|
| 770 |
with gr.Column(elem_classes=["tome-offpage-store"]):
|
| 771 |
places_gallery = gr.Gallery(
|
|
|
|
| 798 |
with gr.Row(elem_classes=["tome-spread-row"]):
|
| 799 |
with gr.Column(scale=1, elem_classes=["tome-page-left", "tome-printed-page", "tome-book-index"]):
|
| 800 |
day_tabs = gr.HTML(value=render_day_tabs(_init_book_day))
|
|
|
|
| 801 |
_day_choices = list(range(max(1, _init_book_day - 14), _init_book_day + 1))
|
| 802 |
book_day_select = gr.Dropdown(
|
| 803 |
choices=[(f"Day {d}", d) for d in reversed(_day_choices)],
|
|
|
|
| 852 |
rel_graph = gr.HTML(value=render_relationship_graph())
|
| 853 |
|
| 854 |
with gr.Tab("Souls of the Garden", id="entities"):
|
|
|
|
|
|
|
| 855 |
with gr.Column(elem_classes=["tome-spread-shell"]):
|
| 856 |
with gr.Row(elem_classes=["tome-spread-row"]):
|
| 857 |
with gr.Column(scale=1, elem_classes=["tome-page-left", "tome-printed-page", "tome-souls-index"]):
|
|
|
|
| 973 |
_realm_map_pick,
|
| 974 |
inputs=[map_pick],
|
| 975 |
outputs=[world_map, location_panel],
|
| 976 |
+
).then(
|
| 977 |
+
None, None, None,
|
| 978 |
+
js="""
|
| 979 |
+
() => {
|
| 980 |
+
setTimeout(() => {
|
| 981 |
+
const modal = document.querySelector('.location-modal-overlay');
|
| 982 |
+
if (modal) modal.classList.add('is-open');
|
| 983 |
+
}, 120);
|
| 984 |
+
}
|
| 985 |
+
""",
|
| 986 |
)
|
| 987 |
|
| 988 |
explore_place_pick.change(
|
|
|
|
| 993 |
lambda pick: int(pick) if pick and str(pick).isdigit() else None,
|
| 994 |
inputs=[explore_place_pick],
|
| 995 |
outputs=[explore_loc],
|
| 996 |
+
).then(
|
| 997 |
+
None, None, None,
|
| 998 |
+
js="""
|
| 999 |
+
() => {
|
| 1000 |
+
setTimeout(() => {
|
| 1001 |
+
const frame = document.querySelector('.tome-explore-stage .diorama-frame');
|
| 1002 |
+
if (frame) frame.focus();
|
| 1003 |
+
}, 200);
|
| 1004 |
+
}
|
| 1005 |
+
""",
|
| 1006 |
)
|
| 1007 |
|
| 1008 |
portal_pick.change(
|
|
|
|
| 1128 |
f.change(
|
| 1129 |
filter_entities,
|
| 1130 |
[loc_filter, type_filter, status_filter, entity_search],
|
| 1131 |
+
[entity_grid, entity_detail],
|
| 1132 |
)
|
| 1133 |
|
| 1134 |
entity_pick.change(select_entity_by_id, [entity_pick], [entity_detail])
|
|
|
|
| 1656 |
wireTomeNav();
|
| 1657 |
wirePageExpand();
|
| 1658 |
|
| 1659 |
+
const triggerGradioInput = (elemId, value) => {
|
| 1660 |
+
const root = document.getElementById(elemId) || document.querySelector('#' + elemId);
|
| 1661 |
+
if (!root) return false;
|
| 1662 |
+
const input = root.querySelector('textarea')
|
| 1663 |
+
|| root.querySelector('input[type="text"]')
|
| 1664 |
+
|| root.querySelector('input:not([type="hidden"])');
|
| 1665 |
+
if (!input) return false;
|
| 1666 |
+
const proto = input.tagName === 'TEXTAREA' ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
|
| 1667 |
+
const setter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
|
| 1668 |
+
if (setter) setter.call(input, String(value));
|
| 1669 |
+
else input.value = String(value);
|
| 1670 |
+
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
| 1671 |
+
input.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
| 1672 |
+
return true;
|
| 1673 |
+
};
|
| 1674 |
+
|
| 1675 |
const bind = () => {
|
| 1676 |
document.querySelectorAll('#world-map [data-location-id]').forEach((node) => {
|
| 1677 |
if (node.dataset.mapBound) return;
|
| 1678 |
node.dataset.mapBound = '1';
|
| 1679 |
node.style.cursor = 'pointer';
|
| 1680 |
+
node.addEventListener('click', (e) => {
|
| 1681 |
+
e.preventDefault();
|
| 1682 |
+
e.stopPropagation();
|
| 1683 |
const id = node.getAttribute('data-location-id');
|
| 1684 |
+
if (id) triggerGradioInput('map_location_pick', id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1685 |
});
|
| 1686 |
});
|
| 1687 |
};
|
| 1688 |
const fireHiddenInput = (id, value) => {
|
| 1689 |
+
const elemId = (id || '').replace(/^#/, '');
|
| 1690 |
+
triggerGradioInput(elemId, value);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1691 |
};
|
| 1692 |
|
| 1693 |
const wireClickable = (el, handler) => {
|
|
|
|
| 1710 |
document.querySelectorAll('.place-ribbon-item').forEach((btn) => {
|
| 1711 |
wireClickable(btn, () => {
|
| 1712 |
const id = btn.getAttribute('data-location-id');
|
| 1713 |
+
if (!id) return;
|
| 1714 |
+
document.querySelectorAll('.place-ribbon-item').forEach((el) => {
|
| 1715 |
+
el.classList.toggle('is-selected', el.getAttribute('data-location-id') === id);
|
| 1716 |
+
});
|
| 1717 |
+
fireHiddenInput('explore_place_pick', id);
|
| 1718 |
});
|
| 1719 |
});
|
| 1720 |
document.querySelectorAll('.day-tab').forEach((btn) => {
|
|
|
|
| 1724 |
});
|
| 1725 |
});
|
| 1726 |
document.querySelectorAll('.entity-grid-card').forEach((card) => {
|
| 1727 |
+
const id = card.getAttribute('data-entity-id');
|
| 1728 |
+
if (!id) return;
|
| 1729 |
card.style.cursor = 'pointer';
|
| 1730 |
+
if (card.dataset.entityBound === id) return;
|
| 1731 |
+
card.dataset.entityBound = id;
|
| 1732 |
wireClickable(card, () => {
|
| 1733 |
+
document.querySelectorAll('.entity-grid-card').forEach((el) => {
|
| 1734 |
+
el.classList.toggle('is-selected', el.getAttribute('data-entity-id') === id);
|
| 1735 |
+
});
|
| 1736 |
+
fireHiddenInput('entity_pick', id);
|
| 1737 |
});
|
| 1738 |
});
|
| 1739 |
document.querySelectorAll('.location-modal-close').forEach((btn) => {
|
ui/relationship_graph.py
CHANGED
|
@@ -264,22 +264,26 @@ def render_bonds_sidebar(rel_type: str = "all") -> str:
|
|
| 264 |
f'<span class="rel-legend-item"><i style="background:{c}"></i>{k}</span>'
|
| 265 |
for k, c in REL_COLORS.items()
|
| 266 |
)
|
| 267 |
-
|
| 268 |
-
for rel in relationships[:
|
| 269 |
t = TYPE_SHORT.get(rel["relationship_type"], rel["relationship_type"])
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
total = len(get_all_relationships())
|
| 277 |
return f"""
|
| 278 |
<div class="bonds-sidebar">
|
| 279 |
<p class="tome-printed-kicker">The Web of Bonds</p>
|
| 280 |
-
<p class="bonds-sidebar-desc">{len(relationships)}
|
| 281 |
-
<div class="rel-legend">{legend}</div>
|
| 282 |
-
<
|
| 283 |
</div>
|
| 284 |
"""
|
| 285 |
|
|
|
|
| 264 |
f'<span class="rel-legend-item"><i style="background:{c}"></i>{k}</span>'
|
| 265 |
for k, c in REL_COLORS.items()
|
| 266 |
)
|
| 267 |
+
cards = []
|
| 268 |
+
for rel in relationships[:8]:
|
| 269 |
t = TYPE_SHORT.get(rel["relationship_type"], rel["relationship_type"])
|
| 270 |
+
color = REL_COLORS.get(rel["relationship_type"], "#605848")
|
| 271 |
+
desc = (rel.get("description") or "A bond still formingβ¦")[:56]
|
| 272 |
+
cards.append(f"""
|
| 273 |
+
<div class="bond-card" style="--bond-color:{color}">
|
| 274 |
+
<span class="bond-card-type">{t}</span>
|
| 275 |
+
<p class="bond-card-names">{rel["entity_a_name"]} β {rel["entity_b_name"]}</p>
|
| 276 |
+
<p class="bond-card-desc">{desc}</p>
|
| 277 |
+
</div>
|
| 278 |
+
""")
|
| 279 |
|
| 280 |
total = len(get_all_relationships())
|
| 281 |
return f"""
|
| 282 |
<div class="bonds-sidebar">
|
| 283 |
<p class="tome-printed-kicker">The Web of Bonds</p>
|
| 284 |
+
<p class="bonds-sidebar-desc">{len(relationships)} of {total} threads</p>
|
| 285 |
+
<div class="rel-legend bonds-legend-compact">{legend}</div>
|
| 286 |
+
<div class="bond-cards">{"".join(cards)}</div>
|
| 287 |
</div>
|
| 288 |
"""
|
| 289 |
|
ui/styles.css
CHANGED
|
@@ -4622,3 +4622,271 @@ body,
|
|
| 4622 |
.realm-opening.is-back-visible .realm-prologue-card {
|
| 4623 |
display: none !important;
|
| 4624 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4622 |
.realm-opening.is-back-visible .realm-prologue-card {
|
| 4623 |
display: none !important;
|
| 4624 |
}
|
| 4625 |
+
|
| 4626 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4627 |
+
FIX PACK β centering, book edges, interactions, readability
|
| 4628 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 4629 |
+
|
| 4630 |
+
#realm-opening-host,
|
| 4631 |
+
#realm-opening-host .realm-opening {
|
| 4632 |
+
position: fixed !important;
|
| 4633 |
+
inset: 0 !important;
|
| 4634 |
+
width: 100vw !important;
|
| 4635 |
+
max-width: 100vw !important;
|
| 4636 |
+
margin: 0 !important;
|
| 4637 |
+
left: 0 !important;
|
| 4638 |
+
right: 0 !important;
|
| 4639 |
+
display: grid !important;
|
| 4640 |
+
place-items: center !important;
|
| 4641 |
+
}
|
| 4642 |
+
|
| 4643 |
+
.realm-opening-inner {
|
| 4644 |
+
width: 100% !important;
|
| 4645 |
+
max-width: 100% !important;
|
| 4646 |
+
display: flex !important;
|
| 4647 |
+
align-items: center !important;
|
| 4648 |
+
justify-content: center !important;
|
| 4649 |
+
margin: 0 auto !important;
|
| 4650 |
+
}
|
| 4651 |
+
|
| 4652 |
+
.realm-book-stage {
|
| 4653 |
+
width: 100%;
|
| 4654 |
+
display: flex !important;
|
| 4655 |
+
align-items: center !important;
|
| 4656 |
+
justify-content: center !important;
|
| 4657 |
+
margin: 0 auto !important;
|
| 4658 |
+
}
|
| 4659 |
+
|
| 4660 |
+
.realm-book-3d {
|
| 4661 |
+
margin: 0 auto !important;
|
| 4662 |
+
left: auto !important;
|
| 4663 |
+
right: auto !important;
|
| 4664 |
+
}
|
| 4665 |
+
|
| 4666 |
+
.realm-book-front .realm-book-spine {
|
| 4667 |
+
left: -10px !important;
|
| 4668 |
+
transform: none !important;
|
| 4669 |
+
top: 6% !important;
|
| 4670 |
+
bottom: 6% !important;
|
| 4671 |
+
width: 14px !important;
|
| 4672 |
+
border-radius: 4px 0 0 4px !important;
|
| 4673 |
+
}
|
| 4674 |
+
|
| 4675 |
+
.realm-cover-front,
|
| 4676 |
+
.realm-cover-back {
|
| 4677 |
+
border: 3px solid rgba(92, 58, 28, 0.75) !important;
|
| 4678 |
+
outline: 1px solid rgba(201, 161, 59, 0.35) !important;
|
| 4679 |
+
outline-offset: 3px;
|
| 4680 |
+
box-shadow:
|
| 4681 |
+
inset 0 2px 0 rgba(255, 240, 198, 0.12),
|
| 4682 |
+
inset 0 -3px 8px rgba(0, 0, 0, 0.35),
|
| 4683 |
+
0 22px 60px rgba(0, 0, 0, 0.55) !important;
|
| 4684 |
+
}
|
| 4685 |
+
|
| 4686 |
+
/* Book spread β leather edge frame (top + sides) */
|
| 4687 |
+
.realm-tabs [role="tabpanel"] {
|
| 4688 |
+
box-shadow:
|
| 4689 |
+
inset 0 14px 20px -6px rgba(48, 28, 14, 0.18),
|
| 4690 |
+
inset 14px 0 18px -8px rgba(72, 44, 18, 0.12),
|
| 4691 |
+
inset -14px 0 18px -8px rgba(72, 44, 18, 0.12),
|
| 4692 |
+
inset 0 -8px 16px rgba(168, 134, 83, 0.1),
|
| 4693 |
+
0 18px 38px rgba(76, 50, 22, 0.26) !important;
|
| 4694 |
+
}
|
| 4695 |
+
|
| 4696 |
+
/* Page I right β distribute content vertically */
|
| 4697 |
+
.tome-page-centered {
|
| 4698 |
+
display: flex !important;
|
| 4699 |
+
flex-direction: column !important;
|
| 4700 |
+
justify-content: space-between !important;
|
| 4701 |
+
gap: 0.4rem !important;
|
| 4702 |
+
min-height: 0 !important;
|
| 4703 |
+
}
|
| 4704 |
+
|
| 4705 |
+
.tome-page-centered .realm-stats-strip,
|
| 4706 |
+
.tome-page-centered .current-event,
|
| 4707 |
+
.tome-page-centered .realm-pulse,
|
| 4708 |
+
.tome-page-centered .activity-feed {
|
| 4709 |
+
flex-shrink: 0;
|
| 4710 |
+
margin-bottom: 0.35rem !important;
|
| 4711 |
+
}
|
| 4712 |
+
|
| 4713 |
+
.tome-page-centered .realm-summon-block,
|
| 4714 |
+
.tome-page-centered .realm-summon-input,
|
| 4715 |
+
.tome-page-centered .seal-summon-btn {
|
| 4716 |
+
flex-shrink: 0;
|
| 4717 |
+
}
|
| 4718 |
+
|
| 4719 |
+
.tome-page-left .realm-map,
|
| 4720 |
+
.tome-page-left #world-map {
|
| 4721 |
+
flex: 1 1 auto;
|
| 4722 |
+
min-height: 200px;
|
| 4723 |
+
max-height: 42%;
|
| 4724 |
+
}
|
| 4725 |
+
|
| 4726 |
+
/* Explore left β padding */
|
| 4727 |
+
.tome-explore-index {
|
| 4728 |
+
padding: 0.65rem 0.85rem 0.75rem 0.55rem !important;
|
| 4729 |
+
gap: 0.5rem !important;
|
| 4730 |
+
}
|
| 4731 |
+
|
| 4732 |
+
.tome-explore-index .place-ribbon-item {
|
| 4733 |
+
padding: 0.5rem 0.55rem !important;
|
| 4734 |
+
margin-bottom: 0.15rem;
|
| 4735 |
+
}
|
| 4736 |
+
|
| 4737 |
+
.tome-explore-index .wander-btn,
|
| 4738 |
+
.tome-explore-index button {
|
| 4739 |
+
margin-top: 0.35rem !important;
|
| 4740 |
+
}
|
| 4741 |
+
|
| 4742 |
+
.tome-explore-stage {
|
| 4743 |
+
padding: 0.55rem 0.55rem 0.65rem 0.75rem !important;
|
| 4744 |
+
}
|
| 4745 |
+
|
| 4746 |
+
.tome-explore-stage .diorama-header {
|
| 4747 |
+
display: block !important;
|
| 4748 |
+
padding: 0.55rem 0.75rem !important;
|
| 4749 |
+
}
|
| 4750 |
+
|
| 4751 |
+
.tome-explore-stage .diorama-wrap {
|
| 4752 |
+
min-height: 300px !important;
|
| 4753 |
+
flex: 1 1 auto !important;
|
| 4754 |
+
}
|
| 4755 |
+
|
| 4756 |
+
.tome-explore-stage .diorama-frame {
|
| 4757 |
+
min-height: 280px !important;
|
| 4758 |
+
height: min(46vh, 400px) !important;
|
| 4759 |
+
}
|
| 4760 |
+
|
| 4761 |
+
/* Souls β parchment hologram (readable) */
|
| 4762 |
+
.tome-souls-stage .hologram-stage {
|
| 4763 |
+
background: linear-gradient(168deg, #faf3df 0%, #ebe0c4 55%, #dccca8 100%) !important;
|
| 4764 |
+
border: 1px solid rgba(138, 106, 58, 0.45) !important;
|
| 4765 |
+
box-shadow:
|
| 4766 |
+
inset 0 0 24px rgba(88, 56, 24, 0.08),
|
| 4767 |
+
0 12px 28px rgba(76, 50, 22, 0.18) !important;
|
| 4768 |
+
transform: none !important;
|
| 4769 |
+
color: #3d2814 !important;
|
| 4770 |
+
}
|
| 4771 |
+
|
| 4772 |
+
.tome-souls-stage .hologram-beam {
|
| 4773 |
+
display: none;
|
| 4774 |
+
}
|
| 4775 |
+
|
| 4776 |
+
.tome-souls-stage .hologram-meta {
|
| 4777 |
+
color: #8a6424 !important;
|
| 4778 |
+
}
|
| 4779 |
+
|
| 4780 |
+
.tome-souls-stage .hologram-name {
|
| 4781 |
+
color: #3d2814 !important;
|
| 4782 |
+
font-family: 'Cinzel Decorative', 'Cinzel', serif !important;
|
| 4783 |
+
}
|
| 4784 |
+
|
| 4785 |
+
.tome-souls-stage .hologram-appearance,
|
| 4786 |
+
.tome-souls-stage .hologram-memory,
|
| 4787 |
+
.tome-souls-stage .hologram-goals {
|
| 4788 |
+
color: #4a3420 !important;
|
| 4789 |
+
font-family: 'IM Fell English', serif !important;
|
| 4790 |
+
line-height: 1.5 !important;
|
| 4791 |
+
}
|
| 4792 |
+
|
| 4793 |
+
.tome-souls-stage .hologram-greeting {
|
| 4794 |
+
color: #5c4228 !important;
|
| 4795 |
+
border-left-color: rgba(138, 106, 58, 0.55) !important;
|
| 4796 |
+
}
|
| 4797 |
+
|
| 4798 |
+
.tome-souls-stage .hologram-banner {
|
| 4799 |
+
height: 72px;
|
| 4800 |
+
}
|
| 4801 |
+
|
| 4802 |
+
.tome-souls-index .entity-grid-card.is-selected {
|
| 4803 |
+
outline: 2px solid rgba(138, 106, 58, 0.75);
|
| 4804 |
+
outline-offset: 2px;
|
| 4805 |
+
box-shadow: 0 6px 16px rgba(76, 50, 22, 0.2) !important;
|
| 4806 |
+
}
|
| 4807 |
+
|
| 4808 |
+
.tome-souls-index {
|
| 4809 |
+
padding: 0.55rem 0.75rem 0.65rem 0.55rem !important;
|
| 4810 |
+
}
|
| 4811 |
+
|
| 4812 |
+
.tome-souls-index .entity-grid {
|
| 4813 |
+
max-height: 360px !important;
|
| 4814 |
+
}
|
| 4815 |
+
|
| 4816 |
+
/* Bonds β compact cards */
|
| 4817 |
+
.bond-cards {
|
| 4818 |
+
display: flex;
|
| 4819 |
+
flex-direction: column;
|
| 4820 |
+
gap: 0.4rem;
|
| 4821 |
+
overflow-y: auto;
|
| 4822 |
+
max-height: 380px;
|
| 4823 |
+
padding-right: 0.2rem;
|
| 4824 |
+
}
|
| 4825 |
+
|
| 4826 |
+
.bond-card {
|
| 4827 |
+
padding: 0.45rem 0.55rem;
|
| 4828 |
+
border-radius: 8px;
|
| 4829 |
+
border-left: 3px solid var(--bond-color, #8a6a3a);
|
| 4830 |
+
background: rgba(255, 249, 232, 0.72);
|
| 4831 |
+
border: 1px solid rgba(138, 106, 58, 0.22);
|
| 4832 |
+
border-left-width: 3px;
|
| 4833 |
+
border-left-color: var(--bond-color, #8a6a3a);
|
| 4834 |
+
}
|
| 4835 |
+
|
| 4836 |
+
.bond-card-type {
|
| 4837 |
+
font-family: 'Cinzel', serif;
|
| 4838 |
+
font-size: 0.62rem;
|
| 4839 |
+
letter-spacing: 0.1em;
|
| 4840 |
+
text-transform: uppercase;
|
| 4841 |
+
color: var(--bond-color, #8a6a3a);
|
| 4842 |
+
}
|
| 4843 |
+
|
| 4844 |
+
.bond-card-names {
|
| 4845 |
+
margin: 0.15rem 0;
|
| 4846 |
+
font-family: 'Cinzel', serif;
|
| 4847 |
+
font-size: 0.78rem;
|
| 4848 |
+
color: #3d2814;
|
| 4849 |
+
line-height: 1.25;
|
| 4850 |
+
}
|
| 4851 |
+
|
| 4852 |
+
.bond-card-desc {
|
| 4853 |
+
margin: 0;
|
| 4854 |
+
font-family: 'IM Fell English', serif;
|
| 4855 |
+
font-style: italic;
|
| 4856 |
+
font-size: 0.76rem;
|
| 4857 |
+
color: #5c4228;
|
| 4858 |
+
line-height: 1.35;
|
| 4859 |
+
}
|
| 4860 |
+
|
| 4861 |
+
.bonds-legend-compact {
|
| 4862 |
+
margin-bottom: 0.35rem;
|
| 4863 |
+
}
|
| 4864 |
+
|
| 4865 |
+
.bonds-legend-compact .rel-legend-item {
|
| 4866 |
+
font-size: 0.68rem;
|
| 4867 |
+
}
|
| 4868 |
+
|
| 4869 |
+
.bonds-sidebar .rel-list {
|
| 4870 |
+
display: none;
|
| 4871 |
+
}
|
| 4872 |
+
|
| 4873 |
+
/* Book day view β fill right page */
|
| 4874 |
+
.tome-book-index + .column .book-day-view,
|
| 4875 |
+
.tome-page-right .book-day-view {
|
| 4876 |
+
min-height: 200px;
|
| 4877 |
+
}
|
| 4878 |
+
|
| 4879 |
+
.tome-page-right .book-entries {
|
| 4880 |
+
overflow-y: auto !important;
|
| 4881 |
+
max-height: 420px !important;
|
| 4882 |
+
}
|
| 4883 |
+
|
| 4884 |
+
.tome-book-index {
|
| 4885 |
+
padding: 0.55rem 0.75rem !important;
|
| 4886 |
+
gap: 0.45rem !important;
|
| 4887 |
+
}
|
| 4888 |
+
|
| 4889 |
+
/* Location modal always on top */
|
| 4890 |
+
.location-modal-overlay.is-open {
|
| 4891 |
+
z-index: 9900 !important;
|
| 4892 |
+
}
|