""" FormScout custom Gradio theme — Silas Therapy palette. Warm cream + sage green ground, petrol-teal primary, golden-orange accent, dark slate-green text. Matches https://silastherapy.sk branding. """ from __future__ import annotations import gradio as gr # ── Silas palette ────────────────────────────────────────────────────────────── CREAM = "#f7eedd" CREAM_DEEP = "#f1e4cc" SAGE = "#bcd3c8" SAGE_DEEP = "#9cbcad" TEAL = "#2b8a8a" TEAL_HOVER = "#1f6e6e" TEAL_DEEP = "#175757" TEAL_LIGHT = "#d6ecec" TEAL_LIGHT_HOVER = "#bfe3e3" GOLD = "#e0a43b" GOLD_DEEP = "#cf922a" INK = "#243a34" INK_MUTED = "#4a5f57" INK_FAINT = "#6b7d75" def formscout_theme() -> gr.Theme: """Create the FormScout theme in the Silas Therapy palette.""" return gr.themes.Soft( primary_hue=gr.themes.colors.teal, secondary_hue=gr.themes.colors.amber, neutral_hue=gr.themes.colors.stone, font=[ gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif", ], font_mono=[ gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace", ], ).set( # Background — warm cream into soft sage body_background_fill=f"linear-gradient(135deg, {CREAM} 0%, {CREAM_DEEP} 45%, {SAGE} 100%)", body_background_fill_dark=f"linear-gradient(135deg, {CREAM} 0%, {CREAM_DEEP} 45%, {SAGE} 100%)", # Blocks — soft white cards over the sage ground block_background_fill="rgba(255, 255, 255, 0.72)", block_background_fill_dark="rgba(255, 255, 255, 0.72)", block_border_width="1px", block_border_color="rgba(43, 138, 138, 0.22)", block_shadow="0 6px 22px rgba(36, 58, 52, 0.10)", block_radius="14px", # Buttons — petrol teal primary, sage secondary button_primary_background_fill=f"linear-gradient(135deg, {TEAL} 0%, {TEAL_HOVER} 100%)", button_primary_background_fill_hover=f"linear-gradient(135deg, {TEAL_HOVER} 0%, {TEAL_DEEP} 100%)", button_primary_text_color="white", button_primary_border_color="rgba(43, 138, 138, 0.45)", button_secondary_background_fill="rgba(156, 188, 173, 0.55)", button_secondary_text_color=INK, # Inputs input_background_fill="rgba(255, 255, 255, 0.92)", input_background_fill_dark="rgba(255, 255, 255, 0.92)", input_background_fill_focus="rgba(255, 255, 255, 1.0)", input_border_color="rgba(43, 138, 138, 0.30)", input_border_color_focus="rgba(43, 138, 138, 0.75)", # Labels — pin light in both modes so no dark dropdown header appears block_label_background_fill="rgba(188, 211, 200, 0.55)", block_label_background_fill_dark="rgba(188, 211, 200, 0.55)", block_label_text_color=INK, block_label_text_color_dark=INK, # Text body_text_color=INK, body_text_color_dark=INK, block_title_text_color=TEAL_DEEP, # Spacing block_padding="16px", layout_gap="16px", ) FORMSCOUT_CSS = f""" /* FormScout — Silas Therapy theme */ .gradio-container {{ max-width: 1400px !important; margin: 0 auto; }} /* Header styling */ .formscout-header {{ text-align: center; padding: 20px 0; border-bottom: 2px solid rgba(43, 138, 138, 0.30); margin-bottom: 20px; }} .formscout-header h1 {{ font-size: 2.2em; background: linear-gradient(135deg, {TEAL} 0%, {GOLD} 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 8px; }} /* Safety banner — golden */ .safety-banner {{ background: linear-gradient(90deg, rgba(224, 164, 59, 0.20), rgba(224, 164, 59, 0.08)); border: 1px solid rgba(224, 164, 59, 0.55); border-radius: 8px; padding: 12px 16px; margin: 12px 0; font-size: 0.9em; text-align: center; color: {GOLD_DEEP}; }} /* Dropdown option lists — pin light-teal cells in both modes (Gradio's default --background-fill-primary resolves dark here, same issue as the labels). */ .gradio-container ul.options {{ background: {TEAL_LIGHT} !important; border: 1px solid rgba(43, 138, 138, 0.30) !important; }} .gradio-container ul.options li.item {{ background: {TEAL_LIGHT} !important; color: {INK} !important; }} .gradio-container ul.options li.item:hover, .gradio-container ul.options li.item.active {{ background: {TEAL_LIGHT_HOVER} !important; color: {INK} !important; }} /* Movement-guide illustration — rounded card matching the test selection */ #movement-guide img {{ border-radius: 12px; object-fit: contain; }} #movement-guide {{ border: 1px solid rgba(43, 138, 138, 0.22); border-radius: 14px; }} /* Score display */ .score-card {{ background: rgba(43, 138, 138, 0.08); border: 2px solid rgba(43, 138, 138, 0.35); border-radius: 16px; padding: 24px; text-align: center; }} .score-value {{ font-size: 4em; font-weight: 800; background: linear-gradient(135deg, {TEAL} 0%, {GOLD} 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }} /* Confidence meter */ .confidence-bar {{ height: 8px; border-radius: 4px; background: rgba(43, 138, 138, 0.18); overflow: hidden; margin-top: 8px; }} .confidence-fill {{ height: 100%; border-radius: 4px; background: linear-gradient(90deg, #d9534f, {GOLD}, {TEAL}); transition: width 0.5s ease; }} /* Pipeline steps indicator */ .pipeline-steps {{ display: flex; gap: 4px; align-items: center; padding: 8px 0; }} .pipeline-step {{ flex: 1; height: 4px; border-radius: 2px; background: rgba(43, 138, 138, 0.18); transition: background 0.3s ease; }} .pipeline-step.active {{ background: {TEAL}; }} .pipeline-step.complete {{ background: {GOLD}; }} /* Asymmetry indicator */ .asymmetry-bar {{ display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: rgba(156, 188, 173, 0.30); border-radius: 8px; margin: 4px 0; }} .asymmetry-label {{ min-width: 60px; font-size: 0.85em; color: {INK_MUTED}; }} .asymmetry-track {{ flex: 1; height: 6px; background: rgba(43, 138, 138, 0.12); border-radius: 3px; position: relative; }} .asymmetry-marker {{ position: absolute; top: -3px; width: 12px; height: 12px; border-radius: 50%; background: {TEAL}; border: 2px solid {GOLD}; }} /* Topographic pattern accent */ .topo-accent {{ color: {INK_FAINT}; background-image: repeating-linear-gradient( 0deg, transparent, transparent 40px, rgba(43, 138, 138, 0.04) 40px, rgba(43, 138, 138, 0.04) 41px ), repeating-linear-gradient( 90deg, transparent, transparent 40px, rgba(43, 138, 138, 0.03) 40px, rgba(43, 138, 138, 0.03) 41px ); }} /* Warning/error states */ .needs-review {{ border-color: rgba(224, 164, 59, 0.65) !important; background: rgba(224, 164, 59, 0.10) !important; }} .low-confidence {{ opacity: 0.7; border-style: dashed !important; }} /* Rubric drawer */ .rubric-item {{ display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; margin: 2px 0; }} .rubric-met {{ background: rgba(43, 138, 138, 0.10); border-left: 3px solid {TEAL}; }} .rubric-unmet {{ background: rgba(217, 83, 79, 0.10); border-left: 3px solid #d9534f; }} /* Responsive */ @media (max-width: 768px) {{ .gradio-container {{ padding: 8px !important; }} .score-value {{ font-size: 3em; }} }} """