POLYMER-PROPERTY / src /ui_style.py
sobinalosious92's picture
Update src/ui_style.py
a210eb3 verified
import base64
import html
import os
from pathlib import Path
from urllib import request
import streamlit as st
def _icon_data_uri(filename: str) -> str:
icon_path = Path(__file__).resolve().parent.parent / "icons" / filename
if not icon_path.exists():
return ""
try:
encoded = base64.b64encode(icon_path.read_bytes()).decode("ascii")
except Exception:
return ""
return f"data:image/png;base64,{encoded}"
def _config_value(name: str, default: str = "") -> str:
try:
if name in st.secrets:
return str(st.secrets[name]).strip()
except Exception:
pass
return str(os.getenv(name, default)).strip()
def _build_sidebar_icon_css() -> str:
fallback = {
1: "🏠",
2: "🔎",
3: "📦",
4: "🧬",
5: "⚙️",
6: "🧠",
7: "✨",
8: "💬",
}
icon_name = {
1: "home1.png",
2: "probe1.png",
3: "batch1.png",
4: "molecule1.png",
5: "manual1.png",
6: "ai1.png",
7: "rnn1.png",
8: "feedback.png",
}
rules = [
'[data-testid="stSidebarNav"] ul li a { position: relative; padding-left: 3.25rem !important; }',
'[data-testid="stSidebarNav"] ul li a::before { content: ""; position: absolute; left: 12px; top: 50%; transform: translateY(-50%); width: 32px; height: 32px; background-size: contain; background-repeat: no-repeat; background-position: center; }',
]
for idx in range(1, 9):
uri = _icon_data_uri(icon_name[idx])
if uri:
rules.append(
'[data-testid="stSidebarNav"] ul li:nth-of-type(%d) a::before { content: ""; background-image: url("%s"); }'
% (idx, uri)
)
else:
emoji = fallback[idx]
rules.append(
'[data-testid="stSidebarNav"] ul li:nth-of-type(%d) a::before { content: "%s"; background-image: none; width: auto; height: auto; font-size: 1.4rem; }'
% (idx, emoji)
)
return "\n".join(rules)
def _log_visit_once_per_session() -> None:
if st.session_state.get("_visit_logged"):
return
webhook_url = _config_value("FEEDBACK_WEBHOOK_URL", "")
webhook_token = _config_value("FEEDBACK_WEBHOOK_TOKEN", "")
if not webhook_url:
return
endpoint = webhook_url
sep = "&" if "?" in webhook_url else "?"
endpoint = f"{webhook_url}{sep}event=visit"
if webhook_token:
endpoint = f"{endpoint}&token={webhook_token}"
try:
with request.urlopen(endpoint, timeout=3):
pass
except Exception:
pass
st.session_state["_visit_logged"] = True
def render_page_header(title: str, subtitle: str = "", badge: str = "") -> None:
title_html = html.escape(title)
subtitle_html = html.escape(subtitle) if subtitle else ""
badge_html = html.escape(badge) if badge else ""
st.markdown(
f"""
<section class="pp-page-header">
{"<span class='pp-badge'>" + badge_html + "</span>" if badge_html else ""}
<h1 class="pp-page-title">{title_html}</h1>
{"<p class='pp-page-subtitle'>" + subtitle_html + "</p>" if subtitle_html else ""}
</section>
""",
unsafe_allow_html=True,
)
def apply_global_style() -> None:
_log_visit_once_per_session()
icon_css = _build_sidebar_icon_css()
css = """
<style>
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap');
:root {
--pp-text: #133a2a;
--pp-muted: #4e6f5d;
--pp-primary: #1f8f52;
--pp-primary-2: #2cab67;
--pp-border: rgba(255, 255, 255, 0.96);
--pp-surface: rgba(251, 247, 255, 0.90);
--pp-shadow: 0 10px 22px rgba(70, 66, 110, 0.12);
--pp-panel-shadow:
0 14px 28px rgba(83, 73, 124, 0.16),
0 1px 0 rgba(255, 255, 255, 0.58) inset;
}
html, body, [class*="css"], [data-testid="stMarkdownContainer"] * {
font-family: "Manrope", "Avenir Next", "Segoe UI", sans-serif;
}
[data-testid="stAppViewContainer"] {
min-height: 100vh;
overflow: visible !important;
background:
radial-gradient(1300px 700px at -10% 105%, rgba(188, 113, 202, 0.62), transparent 62%),
radial-gradient(1200px 700px at 108% 104%, rgba(130, 170, 235, 0.50), transparent 62%),
linear-gradient(120deg, #d5c4e3 0%, #cdd4e9 45%, #c4e1ea 100%) !important;
}
.stApp,
[data-testid="stAppViewContainer"] > .main,
section[data-testid="stMain"] {
color: var(--pp-text);
background: transparent !important;
}
[data-testid="stAppViewContainer"] > .main {
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
background: transparent !important;
overflow: visible !important;
}
section[data-testid="stMain"] {
position: relative;
margin: 12px 14px 12px 18px;
min-height: calc(100vh - 24px) !important;
border-radius: 30px;
border: 1px solid rgba(255, 255, 255, 0.98);
border-right: 2px solid rgba(233, 223, 245, 0.98);
background: rgba(244, 239, 250, 0.96) !important;
box-shadow:
var(--pp-panel-shadow),
inset -1px 0 0 rgba(233, 223, 245, 0.95);
overflow: visible;
isolation: isolate;
}
section[data-testid="stMain"] {
overflow-y: visible !important;
overflow-x: hidden !important;
}
section[data-testid="stMain"]::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.58);
z-index: 0;
}
section[data-testid="stMain"]::after {
display: none;
}
section[data-testid="stMain"] > div,
[data-testid="stMainBlockContainer"] {
position: relative;
z-index: 1;
background: transparent !important;
}
[data-testid="stHeader"] {
background: transparent !important;
}
.block-container {
max-width: 1220px;
padding-top: 1.3rem;
padding-bottom: 2.4rem;
}
h1, h2, h3, h4, h5 {
letter-spacing: -0.02em;
}
p, li, label, [data-testid="stCaptionContainer"] {
color: var(--pp-muted);
}
a, a:visited {
color: #1f8f52 !important;
}
section[data-testid="stSidebar"],
[data-testid="stSidebar"] {
background: transparent !important;
border-right: none !important;
--pp-sidebar-width: 300px;
height: calc(100vh - 24px) !important;
min-width: var(--pp-sidebar-width) !important;
width: var(--pp-sidebar-width) !important;
max-width: var(--pp-sidebar-width) !important;
flex: 0 0 var(--pp-sidebar-width) !important;
flex-basis: var(--pp-sidebar-width) !important;
}
section[data-testid="stSidebar"][aria-expanded="true"] {
min-width: var(--pp-sidebar-width) !important;
width: var(--pp-sidebar-width) !important;
max-width: var(--pp-sidebar-width) !important;
flex: 0 0 var(--pp-sidebar-width) !important;
flex-basis: var(--pp-sidebar-width) !important;
}
[data-testid="stSidebar"] > div:first-child {
margin: 12px 0 12px 12px;
height: calc(100vh - 24px);
border-radius: 30px;
border: 1px solid rgba(255, 255, 255, 0.98);
background: rgba(241, 226, 248, 0.96) !important;
box-shadow: var(--pp-panel-shadow);
backdrop-filter: blur(6px);
overflow-y: auto;
overflow-x: hidden;
}
[data-testid="stSidebarUserContent"] {
padding-top: 0.25rem;
}
[data-testid="stSidebarNav"] ul li,
[data-testid="stSidebarNav"] ul li a,
[data-testid="stSidebarNav"] ul li button {
margin: 0 !important;
padding: 0 !important;
}
[data-testid="stSidebarNav"] ul li + li {
margin-top: 0.44rem !important;
}
[data-testid="stSidebarNav"] ul li a,
[data-testid="stSidebarNav"] ul li button {
font-size: 1.02rem !important;
font-family: "Inter", "Manrope", "Avenir Next", "Segoe UI", sans-serif !important;
font-weight: 600 !important;
color: #1f6b4a !important;
border-radius: 12px !important;
display: flex !important;
align-items: center !important;
justify-content: flex-start !important;
height: 44px !important;
min-height: 44px !important;
max-height: 44px !important;
line-height: 1 !important;
padding: 0 0.78rem 0 3.1rem !important;
border: 1px solid rgba(255, 255, 255, 0.98);
background: rgba(255, 255, 255, 0.78) !important;
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.42) inset,
0 2px 7px rgba(80, 86, 131, 0.07);
transition: all 140ms ease;
box-sizing: border-box !important;
overflow: hidden !important;
}
[data-testid="stSidebarNav"] ul li a > div,
[data-testid="stSidebarNav"] ul li button > div {
margin: 0 !important;
padding: 0 !important;
display: flex !important;
align-items: center !important;
min-height: 0 !important;
line-height: 1 !important;
}
[data-testid="stSidebarNav"] ul li a span,
[data-testid="stSidebarNav"] ul li button span {
font-size: 0.95rem !important;
font-family: "Inter", "Manrope", "Avenir Next", "Segoe UI", sans-serif !important;
font-weight: 600 !important;
color: #1f6b4a !important;
line-height: 1.05 !important;
white-space: nowrap !important;
margin: 0 !important;
padding: 0 !important;
}
[data-testid="stSidebarNav"] ul li a:hover,
[data-testid="stSidebarNav"] ul li button:hover {
transform: translateY(-1px);
background: rgba(255, 255, 255, 0.90) !important;
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.44) inset,
0 4px 10px rgba(85, 94, 142, 0.10);
}
[data-testid="stSidebarNav"] ul li a[aria-current="page"],
[data-testid="stSidebarNav"] ul li button[aria-current="page"] {
border: 1px solid rgba(34, 163, 93, 0.34) !important;
background: linear-gradient(100deg, #21a35e, #34c67a) !important;
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.22) inset,
0 8px 16px rgba(34, 163, 93, 0.28);
}
[data-testid="stSidebarNav"] ul li a[aria-current="page"],
[data-testid="stSidebarNav"] ul li a[aria-current="page"] *,
[data-testid="stSidebarNav"] ul li button[aria-current="page"],
[data-testid="stSidebarNav"] ul li button[aria-current="page"] * {
color: #ffffff !important;
fill: #ffffff !important;
}
[data-testid="stSidebarNav"] ul li a[aria-current="page"]::before {
filter: brightness(0) invert(1);
opacity: 0.96;
}
__ICON_CSS__
.stTextInput > div > div > input,
.stTextArea textarea,
.stSelectbox [data-baseweb="select"] > div,
.stMultiSelect [data-baseweb="select"] > div,
.stNumberInput input {
border-radius: 12px !important;
border: 1px solid #d7deeb !important;
background: rgba(255, 255, 255, 0.87) !important;
box-shadow: none !important;
color: #173b2b !important;
}
.stTextInput > div > div > input:focus,
.stTextArea textarea:focus,
.stSelectbox [data-baseweb="select"] > div:focus-within,
.stMultiSelect [data-baseweb="select"] > div:focus-within,
.stNumberInput input:focus {
border-color: #21a35e !important;
box-shadow: 0 0 0 3px rgba(34, 163, 93, 0.18) !important;
}
/* Force dropdown/expanded menus to green-white accents */
[data-baseweb="popover"] [role="listbox"],
[data-baseweb="popover"] [data-baseweb="menu"],
div[role="listbox"] {
background: rgba(248, 252, 249, 0.98) !important;
border: 1px solid rgba(185, 214, 198, 0.95) !important;
border-radius: 12px !important;
box-shadow: 0 10px 24px rgba(44, 95, 67, 0.14) !important;
}
[data-baseweb="popover"] [role="option"],
[data-baseweb="popover"] li,
[data-baseweb="popover"] [data-baseweb="menu"] > div,
div[role="listbox"] [role="option"] {
background: transparent !important;
color: #173b2b !important;
}
[data-baseweb="popover"] [role="option"]:hover,
[data-baseweb="popover"] li:hover,
[data-baseweb="popover"] [data-highlighted="true"],
div[role="listbox"] [role="option"]:hover {
background: rgba(34, 163, 93, 0.10) !important;
}
[data-baseweb="popover"] [role="option"][aria-selected="true"],
[data-baseweb="popover"] li[aria-selected="true"],
[data-baseweb="popover"] [aria-selected="true"],
div[role="listbox"] [role="option"][aria-selected="true"] {
background: rgba(34, 163, 93, 0.18) !important;
color: #173b2b !important;
}
[data-baseweb="tag"] {
background: #2f9d62 !important;
border: 1px solid #288653 !important;
color: #ffffff !important;
}
[data-baseweb="tag"] *,
[data-baseweb="tag"] svg {
color: #ffffff !important;
fill: #ffffff !important;
}
/* Keep sliders/toggles green while page background stays blue */
.stSlider [data-baseweb="slider"] > div > div > div:first-child,
[data-baseweb="slider"] > div > div > div:first-child {
background-color: #1f8f52 !important;
}
.stSlider [data-baseweb="slider"] > div > div > div:last-child,
[data-baseweb="slider"] > div > div > div:last-child {
background-color: rgba(34, 163, 93, 0.30) !important;
}
[data-baseweb="slider"] [style*="rgb(79, 70, 229)"],
[data-baseweb="slider"] [style*="rgb(91, 80, 255)"],
[data-baseweb="slider"] [style*="rgb(67, 56, 202)"],
[data-baseweb="slider"] [style*="rgb("] {
background-color: #1f8f52 !important;
border-color: #1f8f52 !important;
}
[data-baseweb="slider"] [role="slider"] {
background-color: #1f8f52 !important;
border: 2px solid #ffffff !important;
box-shadow: 0 0 0 1px rgba(34, 163, 93, 0.35), 0 2px 6px rgba(34, 163, 93, 0.28) !important;
}
[data-baseweb="checkbox"] [aria-checked="true"] {
color: #1f8f52 !important;
}
[data-baseweb="checkbox"] [aria-checked="true"] > div {
background-color: #1f8f52 !important;
border-color: #1f8f52 !important;
}
input[type="checkbox"],
input[type="radio"] {
accent-color: #1f8f52 !important;
}
[data-baseweb="radio"] [aria-checked="true"] {
color: #1f8f52 !important;
}
.stButton > button,
.stDownloadButton > button,
[data-testid="baseButton-secondary"] {
border-radius: 999px !important;
border: 1px solid #d7dff2 !important;
font-weight: 500 !important;
min-height: 2.65rem;
padding: 0.3rem 1.08rem !important;
background: rgba(255, 255, 255, 0.94) !important;
transition: all 140ms ease;
}
.stButton > button[kind="primary"],
[data-testid="baseButton-primary"] {
background: linear-gradient(100deg, var(--pp-primary), var(--pp-primary-2)) !important;
color: #fff !important;
border: none !important;
box-shadow: 0 10px 22px rgba(31, 157, 85, 0.34);
}
.stButton > button[kind="primary"] *,
[data-testid="baseButton-primary"] * {
color: #fff !important;
fill: #fff !important;
}
[data-testid="stFormSubmitButton"] button,
[data-testid="stFormSubmitButton"] button * {
color: #fff !important;
fill: #fff !important;
}
.stButton > button:hover,
.stDownloadButton > button:hover {
transform: translateY(-1px);
box-shadow: 0 10px 20px rgba(44, 95, 67, 0.2);
}
div[data-testid="stVerticalBlockBorderWrapper"] {
border-radius: 18px !important;
border: 1px solid var(--pp-border) !important;
background: var(--pp-surface) !important;
box-shadow: var(--pp-shadow);
}
div[data-testid="stMetric"] {
background: rgba(255, 255, 255, 0.72);
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.84);
padding: 0.45rem 0.7rem;
}
div[data-testid="stMetric"] label {
color: #4d705d !important;
font-weight: 600 !important;
letter-spacing: 0.01em;
}
div[data-testid="stMetricValue"] {
color: #1f8f52 !important;
font-weight: 800 !important;
}
[data-testid="stDataFrame"],
[data-testid="stTable"] {
background: rgba(255, 255, 255, 0.78);
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.88);
overflow: hidden;
}
[data-testid="stDataFrame"] [role="grid"],
[data-testid="stDataFrame"] [role="rowgroup"],
[data-testid="stDataFrame"] [role="row"],
[data-testid="stDataFrame"] [role="gridcell"],
[data-testid="stDataFrame"] [role="columnheader"] {
background-color: rgba(247, 252, 248, 0.90) !important;
border-color: rgba(188, 213, 196, 0.55) !important;
}
[data-testid="stTable"] table,
[data-testid="stTable"] th,
[data-testid="stTable"] td {
background-color: rgba(248, 252, 249, 0.94) !important;
border-color: rgba(188, 213, 196, 0.62) !important;
}
.pp-page-header {
margin: 0.1rem 0 1.0rem 0;
}
.pp-page-title {
margin: 0.2rem 0 0.45rem 0;
font-size: clamp(1.95rem, 2.65vw, 3.0rem);
line-height: 1.1;
font-weight: 800;
color: #123726;
}
.pp-page-subtitle {
margin: 0;
max-width: 880px;
color: #4a6e5b;
font-size: 1.02rem;
line-height: 1.62;
}
.pp-badge {
display: inline-flex;
align-items: center;
gap: 0.38rem;
padding: 0.3rem 0.72rem;
border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.92);
background: rgba(255, 255, 255, 0.72);
color: #3f6856;
font-size: 0.76rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.pp-hero {
border-radius: 22px;
border: 1px solid rgba(255, 255, 255, 0.84);
background:
linear-gradient(95deg, rgba(255, 255, 255, 0.74), rgba(255, 255, 255, 0.60)),
radial-gradient(800px 300px at 100% 0%, rgba(34, 163, 93, 0.16), transparent 72%);
box-shadow: 0 16px 32px rgba(56, 70, 121, 0.11);
padding: 1.45rem 1.5rem;
margin: 0.3rem 0 1.2rem;
}
.pp-hero-grid {
display: grid;
grid-template-columns: minmax(0, 4fr) minmax(130px, 1fr);
gap: 1.4rem;
align-items: center;
}
.pp-hero-title {
margin: 0.58rem 0 0.5rem;
color: #123726;
font-size: clamp(1.55rem, 2.12vw, 2.35rem);
font-weight: 800;
letter-spacing: -0.014em;
line-height: 1.2;
}
.pp-hero-copy {
margin: 0;
color: #4c6f5d;
max-width: 780px;
line-height: 1.66;
}
.pp-hero-logo {
display: flex;
justify-content: center;
}
.pp-hero-logo img {
width: 112px;
height: 112px;
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.88);
box-shadow: 0 12px 26px rgba(30, 49, 103, 0.2);
object-fit: contain;
background: rgba(255, 255, 255, 0.96);
padding: 8px;
}
.pp-stat-card {
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.78);
padding: 0.85rem 0.92rem;
box-shadow: 0 8px 22px rgba(56, 78, 145, 0.12);
}
.pp-stat-value {
margin: 0;
color: #2f9d62;
font-size: clamp(1.2rem, 1.8vw, 1.95rem);
font-weight: 800;
letter-spacing: -0.018em;
}
.pp-stat-label {
margin: 0.2rem 0 0;
color: #678a76;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.045em;
font-weight: 700;
}
.pp-kpi-strip {
border-radius: 28px;
border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(247, 251, 248, 0.86);
box-shadow: 0 12px 26px rgba(56, 78, 145, 0.08);
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0;
padding: 1.45rem 1.15rem 1.25rem;
margin: 0.62rem 0 0.9rem 0;
}
.pp-kpi-item {
padding: 0.1rem 0.45rem 0.2rem;
text-align: center;
}
.pp-kpi-strip .pp-kpi-value {
margin: 0;
color: #2f9d62 !important;
font-size: 3.5rem !important;
font-weight: 800 !important;
line-height: 0.98 !important;
letter-spacing: -0.03em !important;
}
.pp-kpi-strip .pp-kpi-label {
margin: 0.75rem 0 0;
color: #6f8d7c !important;
font-size: 0.99rem !important;
font-weight: 700 !important;
letter-spacing: 0.12em !important;
text-transform: uppercase !important;
}
.pp-step-card {
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.77);
padding: 0.8rem 0.92rem;
min-height: 120px;
}
.pp-step-title {
margin: 0 0 0.26rem;
color: #1a4b36;
font-weight: 700;
font-size: 0.98rem;
}
.pp-step-copy {
margin: 0;
color: #557562;
font-size: 0.89rem;
line-height: 1.45;
}
.pp-module-card {
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.77);
box-shadow: 0 8px 22px rgba(56, 78, 145, 0.10);
padding: 1.02rem 1.05rem;
margin-bottom: 0.74rem;
min-height: 136px;
}
.pp-module-title {
margin: 0 0 0.32rem;
color: #1a4b36;
font-size: 1.02rem;
font-weight: 800;
line-height: 1.32;
}
.pp-module-copy {
margin: 0;
color: #557461;
font-size: 0.9rem;
line-height: 1.5;
}
.pp-main-card {
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.77);
box-shadow: 0 8px 22px rgba(56, 78, 145, 0.10);
padding: 1.1rem 1.08rem;
margin: 3.25rem 0 0.9rem 0;
}
.pp-main-grid {
display: grid;
grid-template-columns: minmax(0, 4fr) minmax(120px, 1fr);
gap: 1.1rem;
align-items: center;
}
.pp-main-card .pp-main-title {
margin: 0;
color: #000000 !important;
font-size: clamp(2.8rem, 4.2vw, 3.5rem) !important;
font-weight: 800 !important;
line-height: 0.98 !important;
letter-spacing: -0.03em !important;
}
.pp-main-copy {
margin: 0.5rem 0 0;
color: #557461;
font-size: 1.0rem;
line-height: 1.56;
max-width: 900px;
}
.pp-main-logo {
display: flex;
justify-content: center;
}
.pp-main-logo img {
width: 118px;
height: 118px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.62);
box-shadow: 0 10px 22px rgba(32, 92, 63, 0.20);
object-fit: contain;
background: linear-gradient(145deg, #2f8059, #1f9d55);
padding: 8px;
filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.25));
}
.pp-lab-card {
margin: 0.35rem 0 0.5rem 0;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.92);
background:
linear-gradient(125deg, rgba(255, 255, 255, 0.82), rgba(242, 250, 245, 0.75));
box-shadow: 0 12px 26px rgba(44, 95, 67, 0.12);
padding: 1.3rem 1.35rem 1.25rem;
}
.pp-lab-kicker {
display: inline-flex;
align-items: center;
padding: 0.28rem 0.72rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.82);
border: 1px solid rgba(188, 213, 196, 0.95);
color: #4a6e5b;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.74rem;
font-weight: 700;
}
.pp-lab-title {
margin: 0.72rem 0 0.26rem;
font-size: clamp(1.52rem, 2.1vw, 2.05rem);
font-weight: 800;
letter-spacing: -0.02em;
color: #123726;
}
.pp-lab-subtitle {
margin: 0;
color: #678a76;
font-size: 1.0rem;
font-weight: 600;
line-height: 1.45;
}
.pp-lab-copy {
margin: 1rem 0 1.15rem;
color: #4c6f5d;
font-size: 1.02rem;
line-height: 1.68;
max-width: 1080px;
}
.pp-lab-link {
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
border-radius: 999px;
border: 1px solid rgba(34, 163, 93, 0.36);
background: linear-gradient(100deg, #21a35e, #34c67a);
color: #ffffff !important;
font-size: 0.95rem;
font-weight: 700;
letter-spacing: 0.01em;
padding: 0.56rem 1rem;
box-shadow: 0 8px 16px rgba(34, 163, 93, 0.25);
transition: transform 140ms ease, box-shadow 140ms ease, filter 140ms ease;
}
.pp-lab-link:hover {
color: #ffffff !important;
transform: translateY(-1px);
box-shadow: 0 12px 20px rgba(34, 163, 93, 0.3);
filter: saturate(1.02);
}
@media (max-width: 980px) {
[data-testid="stAppViewContainer"] {
height: auto;
overflow: visible !important;
}
section[data-testid="stMain"] {
margin: 8px;
height: auto !important;
border-radius: 16px;
}
[data-testid="stSidebar"] > div:first-child {
margin: 8px;
height: auto;
border-radius: 16px;
}
.pp-main-grid {
grid-template-columns: 1fr;
gap: 0.75rem;
}
.pp-kpi-strip {
grid-template-columns: 1fr;
gap: 0.42rem;
padding: 0.95rem 1rem 0.85rem;
}
.pp-kpi-item {
padding: 0.18rem 0.45rem;
}
.pp-kpi-strip .pp-kpi-value {
font-size: 3.05rem !important;
}
.pp-kpi-strip .pp-kpi-label {
font-size: 0.7rem !important;
}
.pp-main-logo {
justify-content: flex-start;
}
.pp-main-card {
margin-top: 0.7rem;
}
.pp-hero-grid {
grid-template-columns: 1fr;
gap: 0.85rem;
}
.pp-hero-logo {
justify-content: flex-start;
}
.pp-lab-card {
padding: 1.0rem;
}
.pp-lab-title {
margin-top: 0.58rem;
}
.pp-lab-copy {
margin-top: 0.78rem;
font-size: 0.96rem;
}
}
</style>
"""
st.markdown(css.replace("__ICON_CSS__", icon_css), unsafe_allow_html=True)