figpack 0.4.2__tar.gz → 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {figpack-0.4.2/figpack.egg-info → figpack-0.4.4}/PKG-INFO +3 -1
- {figpack-0.4.2 → figpack-0.4.4}/figpack/__init__.py +1 -1
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_bundle_utils.py +3 -1
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_figure_spec.py +90 -2
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/figpack_view.py +41 -1
- figpack-0.4.4/figpack/figpack-figure-dist/assets/index-BdXsZMUB.css +1 -0
- figpack-0.4.4/figpack/figpack-figure-dist/assets/index-I4MhhmZQ.js +398 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/figpack-figure-dist/index.html +2 -2
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Box.py +7 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/CaptionedView.py +1 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Markdown.py +8 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/MultiChannelTimeseries.py +25 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Spectrogram.py +32 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Splitter.py +1 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/TabLayout.py +8 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/TimeseriesGraph.py +15 -1
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/VerticalLayout.py +7 -0
- {figpack-0.4.2 → figpack-0.4.4/figpack.egg-info}/PKG-INFO +3 -1
- {figpack-0.4.2 → figpack-0.4.4}/figpack.egg-info/SOURCES.txt +2 -2
- {figpack-0.4.2 → figpack-0.4.4}/figpack.egg-info/requires.txt +2 -0
- {figpack-0.4.2 → figpack-0.4.4}/pyproject.toml +3 -1
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_figure_spec.py +64 -4
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_multichannel_timeseries.py +1 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_timeseries_graph.py +2 -0
- figpack-0.4.2/figpack/figpack-figure-dist/assets/index-DCvZuZLF.js +0 -398
- figpack-0.4.2/figpack/figpack-figure-dist/assets/index-oS-16pKZ.css +0 -1
- {figpack-0.4.2 → figpack-0.4.4}/LICENSE +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/MANIFEST.in +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/README.md +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/cli.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/__init__.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_figure_utils.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_file_handler.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_patch_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_remix_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_remix_patch.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_revert_patch_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_save_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_server_manager.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_show_view.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_upload_bundle.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_view_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/_zarr_consolidate.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/config.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/extension_view.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/figpack_extension.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/core/zarr.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/extensions.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/figpack-figure-dist/assets/neurosift-logo-CLsuwLMO.png +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/utils/__init__.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/DataFrame.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Gallery.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/GalleryItem.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Iframe.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/Image.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/LayoutItem.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/MatplotlibFigure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/MountainLayout.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/MountainLayoutItem.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/PlotlyExtension/PlotlyExtension.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/PlotlyExtension/__init__.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/PlotlyExtension/_plotly_extension.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/PlotlyExtension/plotly_view.js +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/TabLayoutItem.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/VerticalLayoutItem.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack/views/__init__.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack.egg-info/dependency_links.txt +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack.egg-info/entry_points.txt +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/figpack.egg-info/top_level.txt +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/setup.cfg +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_box.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_cli.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_core.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_dataframe.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_extension_system.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_figpack_view.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_file_handler.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_gallery.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_image.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_markdown.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_matplotlib_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_patch_pages.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_plotly_figure.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_remix_patch.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_server_manager.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_spectrogram.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_splitter.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_tablayout.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_upload_bundle.py +0 -0
- {figpack-0.4.2 → figpack-0.4.4}/tests/test_view_figure.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: figpack
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: A Python package for creating shareable, interactive visualizations in the browser
|
|
5
5
|
Author-email: Jeremy Magland <jmagland@flatironinstitute.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -72,6 +72,8 @@ Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
|
|
|
72
72
|
Requires-Dist: lindi; extra == "docs"
|
|
73
73
|
Requires-Dist: nibabel; extra == "docs"
|
|
74
74
|
Requires-Dist: Pillow; extra == "docs"
|
|
75
|
+
Requires-Dist: scikit-learn; extra == "docs"
|
|
76
|
+
Requires-Dist: scipy; extra == "docs"
|
|
75
77
|
Dynamic: license-file
|
|
76
78
|
|
|
77
79
|
# figpack
|
|
@@ -80,7 +80,9 @@ def prepare_figure_bundle(
|
|
|
80
80
|
view.write_to_zarr_group(zarr_group)
|
|
81
81
|
|
|
82
82
|
# Add title and description and script as attributes on the top-level zarr group
|
|
83
|
-
|
|
83
|
+
# The figure title is stored separately from the root view's own "title"
|
|
84
|
+
# attribute (e.g. the title of a Box), so that it does not replace it
|
|
85
|
+
zarr_group.attrs["figure_title"] = title
|
|
84
86
|
if description:
|
|
85
87
|
zarr_group.attrs["description"] = description
|
|
86
88
|
if script:
|
|
@@ -28,7 +28,7 @@ SPEC_SIZE_WARNING_CHARS = 20000
|
|
|
28
28
|
_SPEC_LINE_WIDTH = 120
|
|
29
29
|
|
|
30
30
|
# Props of the root node that belong to the figure rather than its root view
|
|
31
|
-
_FIGURE_PROPS = {"
|
|
31
|
+
_FIGURE_PROPS = {"figure_title"}
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
@dataclass
|
|
@@ -40,6 +40,70 @@ class SpecProp:
|
|
|
40
40
|
description: str
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
# Style keys shared by all views. A view's `style` attr holds any of them, and
|
|
44
|
+
# it cascades: each view's effective style is its parent view's with its own
|
|
45
|
+
# keys merged over it (figpack-figure/src/inheritedStyle.ts). A view ignores
|
|
46
|
+
# the keys it does not use and lists the ones it uses in SpecSchema.style_keys.
|
|
47
|
+
STYLE_KEYS: Dict[str, SpecProp] = {
|
|
48
|
+
p.name: p
|
|
49
|
+
for p in [
|
|
50
|
+
SpecProp("label_font_size", "number", "Axis label font size in pixels."),
|
|
51
|
+
SpecProp("tick_font_size", "number", "Tick label font size in pixels."),
|
|
52
|
+
SpecProp("legend_font_size", "number", "Legend text font size in pixels."),
|
|
53
|
+
SpecProp(
|
|
54
|
+
"font_family",
|
|
55
|
+
"string",
|
|
56
|
+
'CSS font family of all text, e.g. "serif" or "Georgia, serif".',
|
|
57
|
+
),
|
|
58
|
+
SpecProp(
|
|
59
|
+
"text_color",
|
|
60
|
+
"string (CSS color)",
|
|
61
|
+
"Main text color: axis labels, major tick labels, legend text, captions and markdown text.",
|
|
62
|
+
),
|
|
63
|
+
SpecProp(
|
|
64
|
+
"background_color",
|
|
65
|
+
"string (CSS color)",
|
|
66
|
+
"Background color of plot areas (and legends), captions, markdown and the active tab.",
|
|
67
|
+
),
|
|
68
|
+
SpecProp(
|
|
69
|
+
"gridline_color",
|
|
70
|
+
"string (CSS color)",
|
|
71
|
+
"Color of the major gridlines and ticks.",
|
|
72
|
+
),
|
|
73
|
+
SpecProp(
|
|
74
|
+
"minor_gridline_color",
|
|
75
|
+
"string (CSS color)",
|
|
76
|
+
"Color of the minor gridlines and ticks and of the time axis line.",
|
|
77
|
+
),
|
|
78
|
+
SpecProp(
|
|
79
|
+
"title_font_size",
|
|
80
|
+
"number",
|
|
81
|
+
"Font size in pixels of layout item titles and tabs (defaults 12 and 14); a layout's own title is 2 px larger. Title bars and tab bars grow to fit.",
|
|
82
|
+
),
|
|
83
|
+
SpecProp(
|
|
84
|
+
"title_color",
|
|
85
|
+
"string (CSS color)",
|
|
86
|
+
"Text color of layout title bars and tabs.",
|
|
87
|
+
),
|
|
88
|
+
SpecProp(
|
|
89
|
+
"title_background_color",
|
|
90
|
+
"string (CSS color)",
|
|
91
|
+
"Background color of layout title bars and tab bars.",
|
|
92
|
+
),
|
|
93
|
+
SpecProp(
|
|
94
|
+
"colormap",
|
|
95
|
+
'"viridis" | "plasma" | "inferno" | "magma" | "gray"',
|
|
96
|
+
'Colormap of heatmaps; add "_r" to reverse it (e.g. "gray_r").',
|
|
97
|
+
),
|
|
98
|
+
SpecProp(
|
|
99
|
+
"border_color",
|
|
100
|
+
"string (CSS color)",
|
|
101
|
+
"Color of layout borders, splitter bars and caption borders.",
|
|
102
|
+
),
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
43
107
|
@dataclass
|
|
44
108
|
class SpecSchema:
|
|
45
109
|
"""
|
|
@@ -50,6 +114,7 @@ class SpecSchema:
|
|
|
50
114
|
"views": child groups are views (e.g. layouts); each uses its own schema
|
|
51
115
|
"groups": child groups are configurable parts of this view (e.g. the
|
|
52
116
|
series of a TimeseriesGraph), with props given by child_props
|
|
117
|
+
style_keys: the keys of STYLE_KEYS that the view uses
|
|
53
118
|
"""
|
|
54
119
|
|
|
55
120
|
view_type: str
|
|
@@ -58,6 +123,7 @@ class SpecSchema:
|
|
|
58
123
|
children: Literal["none", "views", "groups"] = "none"
|
|
59
124
|
children_description: str = ""
|
|
60
125
|
child_props: List[SpecProp] = field(default_factory=list)
|
|
126
|
+
style_keys: List[str] = field(default_factory=list)
|
|
61
127
|
|
|
62
128
|
|
|
63
129
|
def get_spec_schemas() -> Dict[str, SpecSchema]:
|
|
@@ -113,6 +179,9 @@ def _build_view_node(group, schemas: Dict[str, SpecSchema]) -> Dict[str, Any]:
|
|
|
113
179
|
return {}
|
|
114
180
|
node: Dict[str, Any] = {}
|
|
115
181
|
props = _select_props(group.attrs, schema.props)
|
|
182
|
+
# Any view may set a style, since it cascades to the views inside it
|
|
183
|
+
if group.attrs.get("style"):
|
|
184
|
+
props["style"] = group.attrs["style"]
|
|
116
185
|
if props:
|
|
117
186
|
node["props"] = props
|
|
118
187
|
children = {}
|
|
@@ -171,10 +240,27 @@ def build_figure_spec_docs(
|
|
|
171
240
|
'- data: path of a group in data.zarr for this node (e.g. "/item_0"), or null for a node defined only by the spec (then view_type is required). If omitted, the node uses its counterpart in the original figure: the root group, or the parent\'s subgroup with the same name.',
|
|
172
241
|
"- view_type: the view type of the node.",
|
|
173
242
|
"Only the props documented here are listed in the spec. Other attributes in data.zarr describe the stored data and should not be changed.",
|
|
174
|
-
"Root node: props.
|
|
243
|
+
"Root node: props.figure_title (string) is the figure title.",
|
|
175
244
|
]
|
|
176
245
|
view_types = _collect_view_types(zarr_group)
|
|
177
246
|
documented = [vt for vt in view_types if vt in schemas]
|
|
247
|
+
style_users = {
|
|
248
|
+
key: [vt for vt in documented if key in schemas[vt].style_keys]
|
|
249
|
+
for key in STYLE_KEYS
|
|
250
|
+
}
|
|
251
|
+
if any(style_users.values()):
|
|
252
|
+
lines += [
|
|
253
|
+
"",
|
|
254
|
+
"## Style",
|
|
255
|
+
"",
|
|
256
|
+
"Any view node may set props.style to an object of the style keys below. It applies to that view and to every view inside it: styles merge key by key from the root down, and inner values win. Set it on the root node to style the whole figure. Views ignore keys they do not use.",
|
|
257
|
+
"Style keys:",
|
|
258
|
+
]
|
|
259
|
+
lines += [
|
|
260
|
+
f"- {p.name} ({p.type}): {p.description} Used by: {', '.join(style_users[key])}."
|
|
261
|
+
for key, p in STYLE_KEYS.items()
|
|
262
|
+
if style_users[key]
|
|
263
|
+
]
|
|
178
264
|
for vt in documented:
|
|
179
265
|
schema = schemas[vt]
|
|
180
266
|
lines += ["", f"## {vt}", "", schema.description]
|
|
@@ -183,6 +269,8 @@ def build_figure_spec_docs(
|
|
|
183
269
|
lines += [f"- {p.name} ({p.type}): {p.description}" for p in schema.props]
|
|
184
270
|
else:
|
|
185
271
|
lines.append("No configurable props.")
|
|
272
|
+
if schema.style_keys:
|
|
273
|
+
lines.append(f"Style keys: {', '.join(schema.style_keys)}.")
|
|
186
274
|
if schema.children_description:
|
|
187
275
|
lines.append(f"Children: {schema.children_description}")
|
|
188
276
|
if schema.child_props:
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
Base view class for figpack visualization components
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import functools
|
|
5
6
|
import os
|
|
6
7
|
import random
|
|
7
8
|
import string
|
|
8
|
-
from typing import TYPE_CHECKING, Optional
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional
|
|
9
10
|
|
|
11
|
+
from ._figure_spec import STYLE_KEYS
|
|
10
12
|
from .zarr import Group
|
|
11
13
|
|
|
12
14
|
if TYPE_CHECKING:
|
|
@@ -18,6 +20,44 @@ class FigpackView:
|
|
|
18
20
|
Base class for all figpack visualization components
|
|
19
21
|
"""
|
|
20
22
|
|
|
23
|
+
# Set with set_style(); replaced, never mutated, so the class default is safe
|
|
24
|
+
_style: Dict[str, Any] = {}
|
|
25
|
+
|
|
26
|
+
def __init_subclass__(cls, **kwargs):
|
|
27
|
+
super().__init_subclass__(**kwargs)
|
|
28
|
+
# Every view writes its style attr after its own attrs, without each
|
|
29
|
+
# write_to_zarr_group having to do it
|
|
30
|
+
write = cls.__dict__.get("write_to_zarr_group")
|
|
31
|
+
if write is None:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
@functools.wraps(write)
|
|
35
|
+
def write_with_style(self, group: Group) -> None:
|
|
36
|
+
write(self, group)
|
|
37
|
+
if self._style:
|
|
38
|
+
group.attrs["style"] = dict(self._style)
|
|
39
|
+
|
|
40
|
+
cls.write_to_zarr_group = write_with_style
|
|
41
|
+
|
|
42
|
+
def set_style(self, **style: Any) -> "FigpackView":
|
|
43
|
+
"""
|
|
44
|
+
Set style keys (e.g. label_font_size=16) for this view and every view
|
|
45
|
+
inside it. Views inside it inherit the keys unless they set their own.
|
|
46
|
+
Call it on the root view to style the whole figure. Keys given here are
|
|
47
|
+
merged over those set before.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
The view itself, so that calls can be chained
|
|
51
|
+
"""
|
|
52
|
+
unknown = [k for k in style if k not in STYLE_KEYS]
|
|
53
|
+
if unknown:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"Unknown style keys: {', '.join(unknown)}. "
|
|
56
|
+
f"Known keys: {', '.join(STYLE_KEYS)}"
|
|
57
|
+
)
|
|
58
|
+
self._style = {**self._style, **style}
|
|
59
|
+
return self
|
|
60
|
+
|
|
21
61
|
def show(
|
|
22
62
|
self,
|
|
23
63
|
*,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.unitEntryBase{padding-right:13px;padding-top:10px}.unselectedUnitEntry{border:1px transparent solid;font-weight:400;color:#000;background-color:#fff}.selectedUnitEntry{border:1px solid blue;font-weight:700;color:#000;background-color:#b5d1ff}.unitIdsColumnLabelStyle{min-width:200px;font-weight:700;padding:7px 5px}.unitLabelsStyle{padding-right:3px;color:#333}.plotUnitLabel{text-align:left;margin-left:20px;margin-top:5px;font-weight:700}.plotWrapperButtonParent{display:inline-block}.plotWrapperStyleButton{padding-top:50px}.plotUnselectedStyle{border:3px solid rgb(202,224,231)}.plotSelectedStyle{border:3px solid #9999ff;background-color:#fff}.plotUnselectableStyle{border:3px solid transparent}.plotCurrentStyle{border:3px solid blue;background-color:#fff}.plotLabelStyle{font-weight:700;text-align:center;overflow:hidden;white-space:nowrap}.figpack-markdown table{border-collapse:collapse;margin:.8em 0}.figpack-markdown th,.figpack-markdown td{border:1px solid #d0d7de;padding:4px 12px}.figpack-markdown th{background-color:#7f7f7f14}.figpack-markdown blockquote{margin:.8em 0;padding:0 1em;border-left:4px solid #d0d7de;opacity:.85}.figpack-markdown math[display=block]{margin:.8em 0;font-size:1.15em}:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color:#213547;background-color:#fff;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#747bff}body{margin:0;overflow:hidden}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#f9f9f9;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.status-bar{position:fixed;left:0;right:0;height:30px;background-color:#f5f5f5;color:#333;display:flex;align-items:center;padding:0 12px;font-size:12px;border-top:1px solid #ddd;z-index:1000}.status-bar.warning{background-color:#fff3cd;color:#856404;border-top:1px solid #ffeaa7}.status-bar.error,.status-bar.expired{background-color:#f8d7da;color:#721c24;border-top:1px solid #f5c6cb}.manage-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.manage-button:hover{background-color:#d0d0d0}.about-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s}.about-button:hover{background-color:#d0d0d0}.share-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;margin-left:12px;transition:background-color .2s;display:flex;align-items:center;gap:4px}.share-button:hover{background-color:#d0d0d0}.about-dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:2000}.about-dialog{background-color:#fff;color:#333;border-radius:8px;max-width:600px;max-height:80vh;width:90%;box-shadow:0 4px 20px #00000026;overflow:hidden}.about-dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #ddd}.about-dialog-header h2{margin:0;font-size:18px;font-weight:600}.about-dialog-close{background:none;border:none;color:#333;font-size:24px;cursor:pointer;padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s}.about-dialog-close:hover{background-color:#f0f0f0}.about-dialog-content{padding:20px;overflow-y:auto;max-height:calc(80vh - 80px)}.about-dialog-description{line-height:1.6}.about-dialog-provenance{margin-top:0;margin-bottom:12px;font-size:.9em;color:#555;overflow-wrap:anywhere}.about-dialog-description h1,.about-dialog-description h2,.about-dialog-description h3{margin-top:0;margin-bottom:12px}.about-dialog-description p{margin-bottom:12px}.about-dialog-description code{background-color:#f5f5f5;color:#333;padding:2px 4px;border-radius:3px;font-family:Courier New,monospace;font-size:.9em}.about-dialog-description pre{background-color:#f5f5f5;color:#333;padding:12px;border-radius:4px;overflow-x:auto;margin-bottom:12px}.about-dialog-description ul,.about-dialog-description ol{margin-bottom:12px;padding-left:20px}.about-dialog-description blockquote{border-left:4px solid #ccc;padding-left:16px;margin:12px 0;font-style:italic}.manage-edits-view{display:flex;align-items:center;margin-left:12px}.edits-notification{color:#e65100;font-weight:500;margin-right:8px}.save-changes-button{background-color:#ff9800;color:#fff;border:1px solid #f57c00;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:11px;height:22px;transition:background-color .2s}.save-changes-button:hover{background-color:#f57c00}.dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:2000}.dialog-content{background-color:#fff;color:#333;border-radius:8px;max-width:500px;width:90%;box-shadow:0 4px 20px #00000026;overflow:hidden}.dialog-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #ddd}.dialog-header h3{margin:0;font-size:18px;font-weight:600}.dialog-close{background:none;border:none;color:#333;font-size:24px;cursor:pointer;padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s}.dialog-close:hover{background-color:#f0f0f0}.dialog-body{padding:20px}.dialog-body p{margin:0 0 12px;line-height:1.5}.dialog-footer{padding:16px 20px;border-top:1px solid #ddd;display:flex;justify-content:flex-end}.dialog-button{background-color:#e0e0e0;color:#333;border:1px solid #ccc;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:14px;transition:background-color .2s}.dialog-button:hover{background-color:#d0d0d0}.dialog-fullscreen{position:fixed;inset:0;background-color:#fff;color:#333;z-index:2000;display:flex;flex-direction:column}.dialog-content-fullscreen{display:flex;flex-direction:column;height:100%;overflow:hidden}.dialog-content-fullscreen .dialog-header{flex-shrink:0}.dialog-content-fullscreen .dialog-body{flex:1;overflow-y:auto;padding:20px}.dialog-content-fullscreen .dialog-footer{flex-shrink:0}
|