import re import gradio as gr CUSTOM_CSS = """ body { background: linear-gradient(180deg, #f4f6f8 0%, #edf1f5 100%); } .gradio-container { max-width: 1280px !important; padding-top: 20px !important; padding-bottom: 36px !important; font-family: "Aptos", "Segoe UI", "Helvetica Neue", sans-serif !important; color: #1c2733; } .hero-shell { background: linear-gradient(135deg, #11283f 0%, #1a3d5f 100%); border-radius: 10px; overflow: hidden; box-shadow: 0 18px 40px rgba(18, 36, 53, 0.16); margin-bottom: 18px; border: 1px solid rgba(255, 255, 255, 0.08); } .hero-inner { padding: 30px 34px; color: #ffffff; } .eyebrow { display: inline-block; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #ffffff !important; margin-bottom: 12px; } .hero-title { margin: 0 0 12px 0; font-size: 2.5rem; line-height: 1.08; font-weight: 800; letter-spacing: -0.02em; color: #ffffff !important; opacity: 1 !important; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18); } .hero-subtitle { max-width: 860px; margin: 0; font-size: 1.02rem; line-height: 1.75; color: #ffffff !important; } .hero-bar { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; margin-top: 22px; background: rgba(255, 255, 255, 0.12); border-radius: 8px; overflow: hidden; } .hero-stat { background: rgba(255, 255, 255, 0.08); padding: 14px 16px; } .hero-stat strong { display: block; font-size: 0.92rem; margin-bottom: 4px; color: #ffffff !important; } .hero-stat span { font-size: 0.84rem; color: #ffffff !important; line-height: 1.45; } .panel { background: #ffffff; border: 1px solid #d7dde5; border-radius: 10px; box-shadow: 0 8px 20px rgba(31, 47, 61, 0.06); overflow: hidden; padding: 0 !important; } /* When .panel is applied to a gr.Column, neutralize the Gradio block wrapping the panel-head HTML so the gradient bleeds edge-to-edge. The header lives inside the FIRST .block child of .panel. */ .gradio-container .panel > .block:first-child, .gradio-container .panel > div:first-child { background: transparent !important; background-color: transparent !important; border: none !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; } /* Give all body content (everything except the header) consistent internal padding so the textbox, buttons, and examples don't touch the rounded edges of the panel. */ .gradio-container .panel > *:not(:first-child) { padding-left: 22px !important; padding-right: 22px !important; } .gradio-container .panel > *:nth-child(2) { padding-top: 18px !important; } .gradio-container .panel > *:last-child { padding-bottom: 22px !important; } .panel-head { padding: 20px 22px 14px 22px; border-bottom: 1px solid #e3e8ee; background: linear-gradient(180deg, #fbfcfd 0%, #f5f8fb 100%); } .panel-title { margin: 0 0 6px 0; font-size: 1.2rem; font-weight: 800; color: #17324a; } .panel-copy { margin: 0; color: #56697a; font-size: 0.95rem; line-height: 1.6; } .panel-body { padding: 20px 22px 22px 22px; } .metric-strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 18px 22px 4px 22px; } .metric-card { background: #f8fafc; border: 1px solid #dfe5eb; border-left: 4px solid #244e73; border-radius: 8px; padding: 14px 14px 12px 14px; } .metric-card strong { display: block; color: #173954; font-size: 1rem; margin-bottom: 4px; } .metric-card span { color: #607180; font-size: 0.88rem; line-height: 1.45; } /* Base Textbox & Textarea styling */ textarea, [data-testid="textbox"] textarea { background: #ffffff !important; border: 1px solid #ccd5de !important; border-radius: 8px !important; font-size: 0.98rem !important; color: #27272A !important; box-shadow: none !important; } textarea::placeholder, [data-testid="textbox"] textarea::placeholder { color: #7a8896 !important; } textarea:focus, [data-testid="textbox"] textarea:focus { border: 1px solid #244e73 !important; box-shadow: 0 0 0 3px rgba(36, 78, 115, 0.12) !important; } /* Button styling */ button.primary { background: #173a59 !important; color: #ffffff !important; border: 1px solid #173a59 !important; border-radius: 8px !important; min-height: 46px !important; font-weight: 700 !important; transition: all 0.2s ease !important; } button.primary:hover { background: #214d75 !important; border-color: #214d75 !important; color: #ffffff !important; } button.secondary { background: #ffffff !important; color: #173954 !important; border: 1px solid #ccd5de !important; border-radius: 8px !important; min-height: 46px !important; font-weight: 700 !important; transition: all 0.2s ease !important; } button.secondary:hover { background: #eef4f8 !important; color: #16324a !important; border-color: #b8c7d4 !important; } /* Output Prose styling */ .prose, .prose * { color: #1e2f3d !important; line-height: 1.72 !important; } .prose h1, .prose h2, .prose h3 { color: #16324a !important; font-weight: 800 !important; } /* Footer Banner */ .footer-banner { margin-top: 16px; background: #ffffff; border: 1px solid #d8dfe6; border-radius: 10px; padding: 16px 20px; color: #4d6272; font-size: 0.94rem; line-height: 1.65; box-shadow: 0 8px 18px rgba(31, 47, 61, 0.05); } .footer-banner strong { color: #16324a; } /* Keep hero stats white no matter what */ .hero-shell *, .hero-inner *, .hero-subtitle, .eyebrow, .hero-stat strong, .hero-stat span { color: #ffffff !important; } @media (max-width: 900px) { .hero-title { font-size: 2rem; } .hero-bar, .metric-strip { grid-template-columns: 1fr; } } /* ========================================= SLEDGEHAMMER OVERRIDES FOR GRADIO BUGS ========================================= */ /* 1. HERO TITLE FIX (Bypasses Gradio's internal h1 color reset) */ .gradio-container .hero-shell h1.hero-title, .gradio-container .hero-shell h1, .hero-shell .hero-title { color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; /* Forces white even if webkit overrides it */ opacity: 1 !important; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18) !important; margin: 0 0 12px 0 !important; font-size: 2.5rem !important; font-weight: 800 !important; } /* 2. TABS VISIBILITY FIX */ div.tab-nav { gap: 8px !important; padding: 14px 22px 0 22px !important; background: #ffffff !important; } button[role="tab"] { color: #41586b !important; /* Forces unselected text to be dark grey */ border-radius: 999px !important; border: 1px solid #d5dce4 !important; background: #f7f9fb !important; font-weight: 700 !important; transition: all 0.2s ease !important; } button[role="tab"]:hover { background: #edf3f8 !important; color: #173954 !important; border-color: #bfd0dd !important; } button[role="tab"].selected { background: #173a59 !important; /* Force background on active */ color: #ffffff !important; /* Force white text on active */ border-color: #173a59 !important; } /* ========================================================= EXAMPLES (gr.Examples -> gr.Dataset) STYLING gr.Examples renders a gr.Dataset. Its root is .dataset, and the clickable items are .gallery-item / table rows depending on type (here, single-text examples render as a samples table OR as gallery buttons depending on Gradio version). We scope everything under our own .ba-examples class (set via elem_classes) and use high-specificity selectors with the .gradio-container prefix to beat Gradio's default grey :hover. ========================================================= */ /* Section label "Sample Business Scenarios" */ .gradio-container .ba-examples .label-wrap, .gradio-container .ba-examples .label-wrap *, .gradio-container .ba-examples > label, .gradio-container .ba-examples > label * { color: #000000 !important; font-weight: 700 !important; opacity: 1 !important; } /* ---- BASE (un-hovered) state ---- Cover every form the dataset items can take: table cells, gallery items, and generic buttons. */ .gradio-container .ba-examples .dataset td, .gradio-container .ba-examples table td, .gradio-container .ba-examples .gallery-item, .gradio-container .ba-examples button, .gradio-container .ba-examples [role="button"] { background-color: #ffffff !important; border: 1px solid #ccd5de !important; color: #000000 !important; } .gradio-container .ba-examples .dataset td *, .gradio-container .ba-examples table td *, .gradio-container .ba-examples .gallery-item *, .gradio-container .ba-examples button *, .gradio-container .ba-examples [role="button"] * { color: #000000 !important; -webkit-text-fill-color: #000000 !important; opacity: 1 !important; } /* ---- HOVER / SELECTED state ---- This is the part that kept failing. Gradio applies its own grey hover with high specificity, so we match the SAME elements and force BOTH background and text. The .gradio-container prefix + element + pseudo gives us enough specificity to win. */ .gradio-container .ba-examples .dataset tr:hover td, .gradio-container .ba-examples .dataset td:hover, .gradio-container .ba-examples table tr:hover td, .gradio-container .ba-examples table td:hover, .gradio-container .ba-examples .gallery-item:hover, .gradio-container .ba-examples button:hover, .gradio-container .ba-examples [role="button"]:hover, .gradio-container .ba-examples .gallery-item.selected, .gradio-container .ba-examples tr.selected td, .gradio-container .ba-examples [aria-selected="true"] { background-color: #173a59 !important; /* dark blue */ border-color: #173a59 !important; } /* Force the TEXT white on hover/selected — target the element itself AND all descendants, with -webkit-text-fill-color to defeat any webkit text-fill override. */ .gradio-container .ba-examples .dataset tr:hover td, .gradio-container .ba-examples .dataset tr:hover td *, .gradio-container .ba-examples .dataset td:hover, .gradio-container .ba-examples .dataset td:hover *, .gradio-container .ba-examples table tr:hover td, .gradio-container .ba-examples table tr:hover td *, .gradio-container .ba-examples table td:hover, .gradio-container .ba-examples table td:hover *, .gradio-container .ba-examples .gallery-item:hover, .gradio-container .ba-examples .gallery-item:hover *, .gradio-container .ba-examples button:hover, .gradio-container .ba-examples button:hover *, .gradio-container .ba-examples [role="button"]:hover, .gradio-container .ba-examples [role="button"]:hover *, .gradio-container .ba-examples .gallery-item.selected, .gradio-container .ba-examples .gallery-item.selected *, .gradio-container .ba-examples tr.selected td, .gradio-container .ba-examples tr.selected td *, .gradio-container .ba-examples [aria-selected="true"], .gradio-container .ba-examples [aria-selected="true"] * { color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; opacity: 1 !important; } /* ========================================================= GRADIO FOOTER FIX The default footer ("Use via API · Built with Gradio · Settings") has a broken hover state — text fades to nearly invisible on hover. We give it a readable base color and a clearly visible hover color that matches the app's dark-blue accent. Targets