"""Shared Streamlit UI components — disclaimer banner, KPI cards, tier pill, and a one-shot mobile-responsive CSS injection that every page picks up via ``disclaimer_banner()``. """ from __future__ import annotations import streamlit as st from .theme import TIER_COLORS _DISCLAIMER_TEXT = ( "**Not investment advice.** This is a technical study and analysis " "intended for discussion. See the [Disclaimer](Disclaimer) page." ) # Tightens layout, shrinks heavy chart heights, compacts KPI metrics, and # makes wide DataFrames horizontally scrollable on narrow viewports. Streamlit # columns already stack on narrow viewports — this CSS just polishes the # resulting vertical layout so it doesn't feel like a desktop site mashed # onto a phone. _MOBILE_CSS = """ """ def _inject_mobile_css() -> None: """Inject the responsive CSS once per session run. Streamlit deduplicates identical st.markdown calls implicitly across the same page render, so this is safe to call from every page.""" st.markdown(_MOBILE_CSS, unsafe_allow_html=True) def disclaimer_banner() -> None: _inject_mobile_css() st.info(_DISCLAIMER_TEXT, icon=":material/info:") def page_header(title: str, subtitle: str | None = None, *, eyebrow: str | None = None) -> None: """Heavyweight typographic header — sets a forensic, editorial tone.""" _inject_mobile_css() if eyebrow: st.markdown( f"