diff --git a/src/epicc/model/models/tb_isolation.yaml b/src/epicc/model/models/tb_isolation.yaml
index 732028b..4340a03 100644
--- a/src/epicc/model/models/tb_isolation.yaml
+++ b/src/epicc/model/models/tb_isolation.yaml
@@ -351,7 +351,7 @@ report:
infections.
$$
- \LaTeX \text{ test.}
+ \text{LaTeX test.}
$$
## Scenarios
diff --git a/src/epicc/ui/export.py b/src/epicc/ui/export.py
index f5ec3f9..b59d69e 100644
--- a/src/epicc/ui/export.py
+++ b/src/epicc/ui/export.py
@@ -98,12 +98,11 @@ def render_parameter_export_modal(
def render_pdf_export_button(container: Any = None) -> None:
# Render a direct Save report as PDF button.
-
rc = container if container is not None else st
clicked = rc.button(
"Save report as PDF",
disabled=not has_results(),
- width='stretch',
+ use_container_width=True,
type='primary',
)
@@ -124,25 +123,8 @@ def trigger_print_if_requested() -> None:
trigger_token = st.session_state.get(_PRINT_TOKEN_KEY, 0)
- # What the hell is this, Streamlit? Why can't I just run JS without this nonsense? Yes, I know
- # you don't want me to mess with your UI, but I just want to trigger the browser print dialog,
- # is that really so bad? I even told you it was okay to run unsafe JS, but no, you had to run
- # it through some weird sanitizer anyways.
- #
- # What's worse is that you silently drop that JS which fails your mysterious security checks
- # instead of throwing an error, leaving me to waste hours debugging why my print button doesn't
- # work at all. So here we are, base64 encoding the JS and evaling it in the browser, just to get
- # around your broken injection system. I hope you're proud of yourselves.
- #
- # Seriously!?!? This works?
- #
- # This is an alternative implementation to something like:
- #
- # https://github.com/thunderbug1/streamlit-javascript
- #
- # Which would have a mess build-wise. As far as I know, I'm the first person to come up with this
- # workaround, so I'm claiming it as my own invention! Don't tell Streamlit.
-
+ # Reverted to Olivia's original, hacky, but highly effective base64 injection bypass.
+ # By using st.html, the script runs in the main window context rather than an isolated iframe.
with importlib.resources.files("epicc").joinpath("js/print_results.js").open("rb") as f:
js = f.read().decode()
js64 = base64.b64encode(js.encode()).decode()
@@ -155,4 +137,4 @@ def trigger_print_if_requested() -> None:
unsafe_allow_javascript=True,
)
- st.session_state[_PRINT_REQUESTED_KEY] = False
+ st.session_state[_PRINT_REQUESTED_KEY] = False
\ No newline at end of file
diff --git a/src/epicc/ui/report.py b/src/epicc/ui/report.py
index 3892e25..0dfe742 100644
--- a/src/epicc/ui/report.py
+++ b/src/epicc/ui/report.py
@@ -172,20 +172,24 @@ def render(self, run_results: dict[str, Any] | None) -> None:
if self._block.title:
st.markdown(
f"
"
- f""
+ f""
f"{self._block.title}
",
unsafe_allow_html=True,
)
if self._block.caption:
st.markdown(
- f""
- f"
"
+ f""
+ f""
f"{self._block.caption}
",
unsafe_allow_html=True
)
- st.plotly_chart(fig, width='stretch', key=f'plotly-{self._uuid}')
+ st.plotly_chart(
+ fig,
+ use_container_width=True,
+ key=f"plotly-{self._uuid}",
+ )
def _resolve_columns(
self, run_results: dict[str, Any]
diff --git a/src/epicc/web/sidebar.css b/src/epicc/web/sidebar.css
index 3630cc8..03d29b4 100644
--- a/src/epicc/web/sidebar.css
+++ b/src/epicc/web/sidebar.css
@@ -25,7 +25,7 @@ div[data-testid="InputInstructions"] > span:nth-child(1) {
/* Fix model selector alignment. TODO: be more specific, `:first-child`? */
.stVerticalBlock {
- justify-content: center;
+ justify-content: center;
}
/* Sidebar section headers */
@@ -95,16 +95,22 @@ div[data-testid="InputInstructions"] > span:nth-child(1) {
margin: 0.5in;
}
- /* [data-testid="stAppViewContainer"] {
- margin: 0 !important;
- padding: 0 !important;
+ html, body, #root, .stlite-container, [data-testid="stAppViewContainer"] {
+ height: auto !important;
+ overflow: visible !important;
+ opacity: 1 !important;
+ filter: none !important;
+ -webkit-filter: none !important;
}
- [data-testid="stMainBlockContainer"] {
- max-width: 100% !important;
- padding-top: 0 !important;
- padding-bottom: 0 !important;
- } */
+ [data-testid="stSelectbox"],
+ [data-testid="stColumn"] button,
+ [data-testid="stHeader"],
+ [data-testid="stSidebar"],
+ .stAppDeployButton,
+ footer {
+ display: none !important;
+ }
.section-divider {
page-break-after: auto;
@@ -131,12 +137,10 @@ div[data-testid="InputInstructions"] > span:nth-child(1) {
.stDataFrame,
.stAgGrid,
.stTable {
- padding-top: 1.5rem !important;
+ padding-top: 0.5rem !important;
padding-bottom: 1.5rem !important;
}
- /* Show only results. */
-
body * {
display: none;
}
@@ -158,5 +162,177 @@ div[data-testid="InputInstructions"] > span:nth-child(1) {
.st-key-results-report,
.st-key-results-report * {
display: revert !important;
+ opacity: 1 !important;
+ filter: none !important;
+ }
+}
+
+/* Action row wrapper */
+.st-key-param-actions-row [data-testid="stHorizontalBlock"] {
+ align-items: flex-start !important;
+}
+
+/* Normalize column internal spacing */
+.st-key-param-actions-row [data-testid="column"] > div {
+ padding-top: 0 !important;
+}
+.st-key-param-actions-row [data-testid="stElementContainer"] {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+/* Make trigger controls fill width and remove extra top offset */
+.st-key-param-actions-row [data-testid="stButton"],
+.st-key-param-actions-row [data-testid="stPopover"] {
+ width: 100%;
+ margin-top: 0 !important;
+ padding-top: 0 !important;
+}
+.st-key-param-actions-row [data-testid="stButton"] > button,
+.st-key-param-actions-row [data-testid="stPopover"] > button {
+ width: 100%;
+}
+
+/* Report spacing: keep headings away from charts */
+.st-key-results-report [data-testid="stPlotlyChart"],
+.st-key-results-report [data-testid="stVegaLiteChart"],
+.st-key-results-report [data-testid="stPyplot"] {
+ margin-bottom: 2rem !important;
+}
+
+.st-key-results-report [data-testid="stMarkdownContainer"] h1,
+.st-key-results-report [data-testid="stMarkdownContainer"] h2,
+.st-key-results-report [data-testid="stMarkdownContainer"] h3 {
+ margin-top: 1.25rem !important;
+}
+
+/* Plotly text contrast follows the active Streamlit theme */
+.st-key-results-report [data-testid="stPlotlyChart"] {
+ color: inherit !important;
+}
+
+.st-key-results-report [data-testid="stPlotlyChart"] .js-plotly-plot,
+.st-key-results-report [data-testid="stPlotlyChart"] .plot-container,
+.st-key-results-report [data-testid="stPlotlyChart"] .main-svg {
+ color: inherit !important;
+}
+
+.st-key-results-report .js-plotly-plot text,
+.st-key-results-report .js-plotly-plot .legendtext,
+.st-key-results-report .js-plotly-plot .gtitle,
+.st-key-results-report .js-plotly-plot .xtick text,
+.st-key-results-report .js-plotly-plot .ytick text,
+.st-key-results-report .js-plotly-plot .annotation text,
+.st-key-results-report .js-plotly-plot .infolayer text {
+ fill: currentColor !important;
+ color: inherit !important;
+}
+
+/* -------- Print/PDF display fixes only (SINGLE CONSOLIDATED BLOCK) -------- */
+@media print {
+ .st-key-results-report {
+ overflow: visible !important;
+ }
+
+ .st-key-results-report [data-testid="stPlotlyChart"],
+ .st-key-results-report [data-testid="stVegaLiteChart"],
+ .st-key-results-report [data-testid="stPyplot"] {
+ display: block !important;
+ position: static !important;
+ clear: both !important;
+ overflow: visible !important;
+ break-inside: avoid !important;
+ page-break-inside: avoid !important;
+ margin: 0 0 2.8rem 0 !important;
+ padding-bottom: 1.2rem !important;
+ }
+
+ .st-key-results-report [data-testid="stPlotlyChart"] .js-plotly-plot {
+ min-height: 520px !important;
+ }
+
+ .st-key-results-report h1,
+ .st-key-results-report h2,
+ .st-key-results-report h3,
+ .st-key-results-report h4 {
+ clear: both !important;
+ position: static !important;
+ z-index: auto !important;
+ margin-top: 2rem !important;
+ }
+
+ .st-key-results-report p,
+ .st-key-results-report [data-testid="stMarkdownContainer"] {
+ clear: both !important;
+ position: static !important;
+ z-index: auto !important;
+ margin-top: 0.5rem !important;
+ }
+
+ .st-key-results-report [data-testid="stMarkdownContainer"] h1,
+ .st-key-results-report [data-testid="stMarkdownContainer"] h2,
+ .st-key-results-report [data-testid="stMarkdownContainer"] h3 {
+ margin-top: 2rem !important;
+ clear: both !important;
+ }
+
+ .st-key-results-report .katex,
+ .st-key-results-report .katex-display,
+ .st-key-results-report mjx-container,
+ .st-key-results-report .MathJax {
+ visibility: visible !important;
+ opacity: 1 !important;
+ }
+
+ .st-key-results-report .katex .katex-mathml,
+ .st-key-results-report mjx-assistive-mml {
+ display: none !important;
+ }
+
+ /* Force strict contrast engine reset across stlite modules */
+ .st-key-results-report,
+ .st-key-results-report * {
+ color: #111827 !important;
+ text-shadow: none !important;
+ -webkit-print-color-adjust: exact !important;
+ print-color-adjust: exact !important;
+ }
+
+ .st-key-results-report [data-testid="stPlotlyChart"],
+ .st-key-results-report [data-testid="stPlotlyChart"] * {
+ opacity: 1 !important;
+ }
+
+ .st-key-results-report .js-plotly-plot text,
+ .st-key-results-report .js-plotly-plot .legendtext,
+ .st-key-results-report .js-plotly-plot .gtitle,
+ .st-key-results-report .js-plotly-plot .xtick text,
+ .st-key-results-report .js-plotly-plot .ytick text,
+ .st-key-results-report .js-plotly-plot .annotation text,
+ .st-key-results-report .js-plotly-plot .infolayer text {
+ fill: #111827 !important;
+ color: #111827 !important;
+ }
+
+ .st-key-results-report .js-plotly-plot .xaxislayer-above path,
+ .st-key-results-report .js-plotly-plot .yaxislayer-above path,
+ .st-key-results-report .js-plotly-plot .xaxislayer-above line,
+ .st-key-results-report .js-plotly-plot .yaxislayer-above line {
+ stroke: #111827 !important;
+ stroke-opacity: 1 !important;
+ stroke-width: 1.2 !important;
+ }
+
+ .st-key-results-report .js-plotly-plot .gridlayer path,
+ .st-key-results-report .js-plotly-plot .gridlayer line,
+ .st-key-results-report .js-plotly-plot .zerolinelayer path,
+ .st-key-results-report .js-plotly-plot .zerolinelayer line {
+ stroke: #9ca3af !important;
+ stroke-opacity: 0.9 !important;
+ }
+
+ .st-key-results-report .js-plotly-plot .scatterlayer .trace path,
+ .st-key-results-report .js-plotly-plot .barlayer .trace path {
+ stroke-opacity: 1 !important;
}
}
\ No newline at end of file