# postponed evaluation of annotations for cleaner forward-reference typing from __future__ import annotations # standard-library utilities for escaping, serialization, environment access, synchronization, temporary files, and identifiers import html import json import os import threading import tempfile import uuid # path and typing helpers used throughout dataset and UI handling from pathlib import Path from typing import Any import spaces # libraries for the Gradio interface, model serialization, dataframe handling, and Hugging Face downloads import gradio as gr import joblib import pandas as pd from huggingface_hub import hf_hub_download # local ML agent that coordinates tool-based analysis and code generation from agent import MachineLearningAgent # app configuration values that control runtime behavior, dataset limits, and model settings from config import ( APP_TITLE, DEFAULT_MAX_TOKENS, EXAMPLE_DATASET_FILE, EXAMPLE_DATASET_REPO, EXAMPLE_DATASET_TARGET, HF_MODEL_ID, HF_PROVIDER, HF_TOKEN, MAX_PROFILE_ROWS, MAX_TRAIN_ROWS, MAX_UPLOAD_MB, SUPPORTED_DATA_EXTENSIONS, ) # supported algorithms and the reusable machine-learning context implementation from ml_engine import ( ALL_ALGORITHMS, CLASSIFICATION_ALGORITHMS, REGRESSION_ALGORITHMS, MLContext, ) # ZeroGPU startup registration probe. # This function is never called, but guarantees Hugging Face detects @spaces.GPU at startup. @spaces.GPU(duration=1) def _zerogpu_startup_probe(): return None # ml contexts by browser session identifier SESSIONS: dict[str, MLContext] = {} # shared session storage from concurrent access across Gradio requests LOCK = threading.Lock() # canonical HF source label for the bundled example dataset EXAMPLE_DATASET_SOURCE = f"hf://datasets/{EXAMPLE_DATASET_REPO}/{EXAMPLE_DATASET_FILE}" # Returns the existing session identifier or creates a new unique identifier when needed def _sid(sid: str | None) -> str: return sid or uuid.uuid4().hex # Retrieves the machine-learning context associated with a session in a thread-safe manner def _get(sid: str | None) -> MLContext | None: if not sid: return None with LOCK: return SESSIONS.get(sid) # Stores a machine-learning context for the specified session under the shared lock def _set(sid: str, ctx: MLContext) -> None: with LOCK: SESSIONS[sid] = ctx # Builds the workspace-status markup from the currently loaded dataset context def _status(ctx: MLContext | None, message: str = "Ready") -> str: # Handles the empty-workspace state before attempting to inspect dataset metadata if ctx is None: details = "No dataset loaded" state_class = "ready" else: # Reads the active dataset profile to summarize its dimensions and source profile = ctx.profile() details = f"{profile['rows']:,} rows · {profile['columns']:,} columns · {html.escape(ctx.source_name)}" state_class = "active" return f'''
WORKSPACE STATUS
{html.escape(message)} {details}
''' # Converts the dataset schema profile into a dataframe suitable for display in Gradio def _schema_table(ctx: MLContext) -> pd.DataFrame: return pd.DataFrame( [ { "column": item["name"], "logical_type": item["logical_type"], "pandas_dtype": item["pandas_dtype"], "null_pct": item["null_pct"], "unique_count": item["unique_count"], "examples": json.dumps(item["examples"], default=str), } for item in ctx.profile()["column_schema"] ] ) # Returns the algorithm choices appropriate for the currently resolved problem type def _algorithm_choices(problem_type: str) -> list[str]: if problem_type == "classification": return ["Auto"] + CLASSIFICATION_ALGORITHMS if problem_type == "regression": return ["Auto"] + REGRESSION_ALGORITHMS return ALL_ALGORITHMS # Chooses a preferred prediction target from an explicit selection or inferred candidates def _preferred_target(ctx: MLContext, preferred: str | None = None) -> str | None: # Normalizes dataframe column names to strings for consistent UI selection behavior columns = [str(c) for c in ctx.dataframe.columns] if preferred and preferred in columns: return preferred candidates = ctx.target_candidates() if candidates: return candidates[0] return columns[-1] if columns else None # Packages dataset-derived values into the coordinated outputs expected by the interface def _dataset_outputs( ctx: MLContext, sid: str, message: str, preferred_target: str | None = None, extra_diagnostics: dict[str, Any] | None = None, ): # Profiles the loaded dataset and resolves the target and inferred supervised-learning task profile = ctx.profile() target = _preferred_target(ctx, preferred_target) inferred = "Auto" resolved = None if target: try: resolved = ctx.infer_problem_type(target, "Auto") except Exception: resolved = None # Collects dataset metadata and current modeling limits for the diagnostics panel diagnostics = { "source": ctx.source_name, "rows_loaded": profile["rows"], "columns": profile["columns"], "memory_mb": profile["memory_mb"], "duplicate_rows": profile["duplicate_rows"], "profiling_row_limit": MAX_PROFILE_ROWS, "training_row_limit": MAX_TRAIN_ROWS, "suggested_target": target, "inferred_problem_type": resolved, } # Merges any caller-specific diagnostics into the standard dataset diagnostics payload if extra_diagnostics: diagnostics.update(extra_diagnostics) # Returns synchronized UI values for status, previews, selectors, and diagnostics return ( sid, _status(ctx, message), ctx.dataframe.head(24), _schema_table(ctx), gr.Dropdown(choices=[str(c) for c in ctx.dataframe.columns], value=target), gr.Dropdown(value=inferred, choices=["Auto", "classification", "regression"]), gr.Dropdown(choices=_algorithm_choices(resolved or ""), value="Auto"), diagnostics, ) # Loads, validates, profiles, and registers a user-uploaded dataset for the active session def load_dataset(uploaded: Any, sid: str | None): # Ensures the upload workflow has a valid session identifier before processing the file sid = _sid(sid) # Returns empty interface state when the user has not selected a file if uploaded is None: return ( sid, _status(_get(sid), "No file selected"), pd.DataFrame(), pd.DataFrame(), gr.Dropdown(choices=[], value=None), gr.Dropdown(value="Auto", choices=["Auto", "classification", "regression"]), gr.Dropdown(choices=ALL_ALGORITHMS, value="Auto"), {}, ) # Resolves the uploaded file path before validating its format and size path = Path(uploaded.name if hasattr(uploaded, "name") else str(uploaded)) # Rejects files whose extension is not included in the supported dataset formats if path.suffix.lower() not in SUPPORTED_DATA_EXTENSIONS: raise gr.Error("Unsupported file type.") # Calculates the upload size in megabytes and enforces the configured size limit size_mb = path.stat().st_size / 1024 / 1024 if size_mb > MAX_UPLOAD_MB: raise gr.Error(f"{path.name} is {size_mb:.1f} MB. Limit is {MAX_UPLOAD_MB} MB.") # Creates the machine-learning context from the uploaded file and stores it in the session try: ctx = MLContext.from_path(path, max_rows=MAX_PROFILE_ROWS) _set(sid, ctx) except Exception as exc: raise gr.Error(f"Could not load {path.name}: {exc}") from exc # Returns the standard dataset outputs along with upload-specific diagnostics return _dataset_outputs( ctx, sid, "Dataset loaded", extra_diagnostics={"dataset_origin": "User upload", "upload_mb": round(size_mb, 3)}, ) # Downloads and loads the configured public example dataset into the current session def load_example_dataset(sid: str | None): # Ensures the example-dataset workflow operates under a valid session identifier sid = _sid(sid) # Attempts to retrieve the example dataset from the configured Hugging Face repository try: cached_path = hf_hub_download( repo_id=EXAMPLE_DATASET_REPO, filename=EXAMPLE_DATASET_FILE, repo_type="dataset", ) # Profiles the downloaded example dataset, labels its source, and stores its context ctx = MLContext.from_path(cached_path, max_rows=MAX_PROFILE_ROWS) ctx.source_name = EXAMPLE_DATASET_SOURCE _set(sid, ctx) return _dataset_outputs( ctx, sid, "HF example dataset loaded", preferred_target=EXAMPLE_DATASET_TARGET, extra_diagnostics={ "dataset_repo": EXAMPLE_DATASET_REPO, "dataset_file": EXAMPLE_DATASET_FILE, "dataset_origin": "Hugging Face Datasets", "preloaded_example": True, }, ) # Falls back to empty interface outputs while preserving details about download failures except Exception as exc: return ( sid, _status(_get(sid), "HF example dataset unavailable"), pd.DataFrame(), pd.DataFrame(), gr.Dropdown(choices=[], value=None), gr.Dropdown(value="Auto", choices=["Auto", "classification", "regression"]), gr.Dropdown(choices=ALL_ALGORITHMS, value="Auto"), { "dataset_repo": EXAMPLE_DATASET_REPO, "preloaded_example": False, "error": str(exc), }, ) # Keeps the algorithm selector, generated pipeline, and recommendation data synchronized def sync_model_controls(target: str, problem_type: str, algorithm: str, sid: str): # Retrieves the active dataset context required to infer compatible modeling settings ctx = _get(sid) # Returns neutral controls when no dataset context or target is currently available if ctx is None or not target: return gr.Dropdown(choices=ALL_ALGORITHMS, value="Auto"), "", {} # Resolves the modeling task and regenerates dependent UI values from the selected target try: resolved = ctx.infer_problem_type(target, problem_type) choices = _algorithm_choices(resolved) selected = algorithm if algorithm in choices else "Auto" code = ctx.generate_pipeline_code(target, selected, problem_type, 0.2) info = ctx.modeling_recommendation(target, problem_type) return gr.Dropdown(choices=choices, value=selected), code, info except Exception as exc: return gr.Dropdown(choices=ALL_ALGORITHMS, value="Auto"), f"# Could not generate pipeline yet: {exc}", {"error": str(exc)} # Generates reproducible pipeline code for the selected target and modeling configuration def generate_pipeline_code(target: str, algorithm: str, problem_type: str, test_size: float, sid: str): # Retrieves the active session context before attempting pipeline generation ctx = _get(sid) # Returns instructional placeholder text when required modeling inputs are missing if ctx is None: return "# Load a dataset first." if not target: return "# Select a target column first." # Delegates pipeline construction to the machine-learning context with the chosen settings try: return ctx.generate_pipeline_code(target, algorithm, problem_type, float(test_size)) except Exception as exc: return f"# Pipeline Generation Failed: {exc}" # Formats a training result dictionary into a concise Markdown model-evaluation summary def _metrics_markdown(result: dict[str, Any]) -> str: # Extracts reported metrics and renders each metric as a Markdown bullet metrics = result.get("metrics", {}) metric_lines = "\n".join(f"- **{name}**: `{value}`" for name, value in metrics.items()) or "- No metrics returned." return f'''### Model Evaluation **{result.get('algorithm', 'Model')}** · `{result.get('problem_type', 'unknown')}` {metric_lines} **Training Footprint:** {result.get('train_rows', 0):,} train rows · {result.get('test_rows', 0):,} test rows · {result.get('feature_columns', 0)} raw features · {result.get('fit_seconds', 0)}s fit time ''' # Trains the selected model, prepares evaluation outputs, and serializes the fitted pipeline def train_model(target: str, algorithm: str, problem_type: str, test_size: float, sid: str): # Validates that a dataset context and target are available before starting training ctx = _get(sid) if ctx is None: raise gr.Error("Load a dataset first.") if not target: raise gr.Error("Select a target column.") # Runs model training and captures the resulting metrics, metadata, and fitted pipeline try: result = ctx.train_candidate(target, algorithm, problem_type, float(test_size)) # Converts feature-importance results into a dataframe for interactive display importance = pd.DataFrame(result.get("feature_importance", [])) # Regenerates pipeline code using the algorithm and problem type actually used for training code = ctx.generate_pipeline_code(target, result["algorithm"], result["problem_type"], float(test_size)) # Builds a compact diagnostics record describing the completed training run diagnostics = { "model_training": "complete", "algorithm": result["algorithm"], "problem_type": result["problem_type"], "rows_used": result["rows_used"], "fit_seconds": result["fit_seconds"], "metrics": result["metrics"], } # Writes the fitted pipeline to a temporary Joblib artifact that the user can download artifact_path = Path(tempfile.gettempdir()) / f"trained_pipeline_{uuid.uuid4().hex[:10]}.joblib" joblib.dump(ctx.last_pipeline, artifact_path) # Returns the formatted evaluation, raw metrics, importance data, code, artifact, and diagnostics return _metrics_markdown(result), result["metrics"], importance, code, str(artifact_path), diagnostics except Exception as exc: raise gr.Error(f"Model training failed: {exc}") from exc # Compares supported baseline algorithms for the selected supervised-learning task def compare_models(target: str, problem_type: str, test_size: float, sid: str): # Validates that the active session contains a dataset and selected prediction target ctx = _get(sid) if ctx is None: raise gr.Error("Load a dataset first.") if not target: raise gr.Error("Select a target column.") # Runs the deterministic baseline comparison and converts the results into display outputs try: comparison = ctx.compare_algorithms(target, problem_type, float(test_size)) frame = pd.DataFrame(comparison.get("results", [])) # Extracts the best reported baseline name to build the comparison summary text best = comparison.get("best_algorithm") note = ( f"### Baseline Comparison:\nBest Holdout Baseline: **{best}**\n\nUse this as a starting point, then add cross-validation and hyperparameter tuning." if best else "### Baseline Comparison:\nNo baseline completed successfully." ) return note, frame, comparison except Exception as exc: raise gr.Error(f"Baseline Comparison Failed: {exc}") from exc # Runs the tool-calling machine-learning agent with the current dataset and modeling controls @spaces.GPU(duration=120) def run_agent( task: str, target: str, algorithm: str, problem_type: str, test_size: float, temperature: float, max_tokens: int, sid: str, ): # Retrieves and validates the active context and user inputs required by the agent ctx = _get(sid) if ctx is None: raise gr.Error("Load a dataset first.") if not target: raise gr.Error("Select a target column in Model Lab first.") if not (task or "").strip(): raise gr.Error("Enter a machine learning task.") # Constructs the agent with the selected target, algorithm, task type, split, and generation settings agent = MachineLearningAgent( context=ctx, target=target, algorithm=algorithm, problem_type=problem_type, test_size=float(test_size), temperature=float(temperature), max_tokens=int(max_tokens), ) # Executes the agent task and captures its response, generated code, and tool trace answer, code, trace = agent.run(task.strip()) # Records model, provider, tool-use, and modeling selections for runtime diagnostics diagnostics = { "model": HF_MODEL_ID, "provider": HF_PROVIDER, "hf_token_configured": bool(HF_TOKEN), "tool_calls": len(trace), "tools_used": [item.get("tool") for item in trace], "target": target, "algorithm": algorithm, "problem_type_setting": problem_type, } # Returns the agent response, generated pipeline code, execution trace, and diagnostics return answer, code, trace, diagnostics # Clears the active session context and resets all dataset, model, and agent interface outputs def clear_session(sid: str): # Removes the session context under the shared lock when a session identifier is present if sid: with LOCK: SESSIONS.pop(sid, None) # Returns the full set of cleared component values expected by the reset callback return ( "", _status(None, "Session cleared"), pd.DataFrame(), pd.DataFrame(), gr.Dropdown(choices=[], value=None), gr.Dropdown(value="Auto", choices=["Auto", "classification", "regression"]), gr.Dropdown(choices=ALL_ALGORITHMS, value="Auto"), "", {}, pd.DataFrame(), "", pd.DataFrame(), "", None, "", [], {}, ) # stylesheet CSS = r''' :root { --bg-0: #04050a; --bg-1: #070a12; --panel: rgba(11, 15, 27, .84); --panel-soft: rgba(255,255,255,.035); --stroke: rgba(255,255,255,.09); --stroke-strong: rgba(255,255,255,.15); --text: #f7f9ff; --muted: #98a5bc; --cyan: #35dcff; --blue: #4f7cff; --violet: #9368ff; --green: #45e6a3; --amber: #ffc46b; } * { box-sizing: border-box; } html { scroll-behavior: smooth; } html, body { background: var(--bg-0) !important; } body { color: var(--text) !important; } .gradio-container, .gradio-container button, .gradio-container input, .gradio-container textarea, .gradio-container select { font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; } .gradio-container { max-width: 1600px !important; margin: 0 auto !important; min-height: 100vh; color: var(--text) !important; background: radial-gradient(circle at 13% -8%, rgba(53,220,255,.15), transparent 31%), radial-gradient(circle at 87% 3%, rgba(147,104,255,.18), transparent 30%), radial-gradient(circle at 52% 106%, rgba(69,230,163,.07), transparent 34%), linear-gradient(145deg, #04050a 0%, #070a12 48%, #080b16 100%) !important; position: relative; } .gradio-container::before { content: ""; position: fixed; inset: 0; pointer-events: none; opacity: .16; background-image: linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px); background-size: 46px 46px; mask-image: linear-gradient(to bottom, black, transparent 88%); } .main-shell { padding: 28px 26px 44px; position: relative; z-index: 1; } .hero { position: relative; overflow: hidden; border: 1px solid rgba(255,255,255,.11); background: linear-gradient(130deg, rgba(16,21,38,.97), rgba(7,10,18,.94) 62%, rgba(10,12,22,.97)); border-radius: 28px; padding: 42px 44px 39px; box-shadow: 0 32px 95px rgba(0,0,0,.48), inset 0 1px 0 rgba(255,255,255,.045); margin-bottom: 18px; } .hero::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; background: linear-gradient(90deg, transparent, var(--cyan), var(--violet), transparent); box-shadow: 0 0 34px rgba(53,220,255,.42); } .hero::after { content: ""; position: absolute; width: 610px; height: 610px; right: -245px; top: -300px; border-radius: 50%; background: radial-gradient(circle at 48% 48%, rgba(53,220,255,.10), transparent 34%), conic-gradient(from 0deg, rgba(53,220,255,.18), rgba(147,104,255,.18), rgba(69,230,163,.08), rgba(53,220,255,.18)); animation: heroDrift 14s ease-in-out infinite alternate; } @keyframes heroDrift { from { transform: translate3d(0,0,0) scale(1); opacity: .7; } to { transform: translate3d(-24px,16px,0) scale(1.04); opacity: .9; } } .hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 28px; align-items: end; position: relative; z-index: 1; } .eyebrow { display: inline-flex; align-items: center; gap: 9px; color: #c4f3ff; font-size: 11px; font-weight: 900; letter-spacing: .17em; text-transform: uppercase; } .eyebrow-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 18px rgba(69,230,163,.75); } .hero h1 { margin: 12px 0 12px; max-width: 990px; color: #fff; font-size: clamp(42px, 5vw, 68px); line-height: 1.02; letter-spacing: -.04em; font-weight: 950; } .hero p { max-width: 960px; color: #aab5ca; font-size: 15px; line-height: 1.72; margin: 0; } .hero-orbit { width: 176px; height: 176px; border: 1px solid rgba(255,255,255,.09); border-radius: 30px; background: linear-gradient(145deg, rgba(53,220,255,.06), rgba(147,104,255,.05)); position: relative; overflow: hidden; box-shadow: inset 0 0 50px rgba(53,220,255,.035); } .hero-orbit::before, .hero-orbit::after { content: ""; position: absolute; border-radius: 50%; inset: 24px; border: 1px solid rgba(255,255,255,.11); animation: orbitSpin 12s linear infinite; } .hero-orbit::after { inset: 56px; border-color: rgba(53,220,255,.38); animation-direction: reverse; animation-duration: 7s; box-shadow: 0 0 28px rgba(53,220,255,.13); } .hero-orbit-core { position: absolute; width: 17px; height: 17px; left: 50%; top: 50%; transform: translate(-50%, -50%); border-radius: 5px; background: linear-gradient(135deg, var(--cyan), var(--violet)); box-shadow: 0 0 30px rgba(53,220,255,.62); animation: corePulse 2.6s ease-in-out infinite; } @keyframes orbitSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes corePulse { 50% { transform: translate(-50%,-50%) scale(1.17); } } .badges { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 22px; } .badge { border: 1px solid rgba(255,255,255,.105); background: rgba(255,255,255,.035); padding: 8px 11px; border-radius: 999px; color: #aeb9ce; font-size: 11px; backdrop-filter: blur(12px); transition: transform .18s ease, border-color .18s ease, background .18s ease; } .badge:hover { transform: translateY(-2px); border-color: rgba(53,220,255,.25); background: rgba(53,220,255,.055); } .badge strong { color: #eefbff; margin-right: 4px; } .badge-accent { border-color: rgba(53,220,255,.22); background: rgba(53,220,255,.055); color: #c6f3ff; } .workflow-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 0 0 18px; } .workflow-step { position: relative; overflow: hidden; min-height: 79px; border: 1px solid var(--stroke); border-radius: 17px; padding: 14px 15px; background: linear-gradient(145deg, rgba(255,255,255,.038), rgba(255,255,255,.018)); transition: transform .2s ease, border-color .2s ease, background .2s ease, box-shadow .2s ease; } .workflow-step:hover { transform: translateY(-3px); border-color: rgba(255,255,255,.15); box-shadow: 0 12px 30px rgba(0,0,0,.2); } .workflow-step span { display: block; color: #68758d; font-size: 10px; font-weight: 900; letter-spacing: .12em; } .workflow-step strong { display: block; color: #f1f5ff; font-size: 13px; margin-top: 5px; } .workflow-step small { display: block; color: #7f8ba0; font-size: 11px; margin-top: 3px; } .workflow-step:nth-child(1) { border-top-color: rgba(53,220,255,.58); } .workflow-step:nth-child(2) { border-top-color: rgba(69,230,163,.58); } .workflow-step:nth-child(3) { border-top-color: rgba(255,196,107,.58); } .workflow-step:nth-child(4) { border-top-color: rgba(147,104,255,.64); } .app-panel { background: rgba(9,13,24,.79) !important; border: 1px solid var(--stroke) !important; border-radius: 24px !important; box-shadow: 0 24px 65px rgba(0,0,0,.34), inset 0 1px 0 rgba(255,255,255,.028); overflow: hidden; backdrop-filter: blur(18px); padding-top: 0 !important; } .side-column { gap: 18px !important; } .sidebar-card { background: linear-gradient(145deg, rgba(17,21,37,.9), rgba(9,13,23,.9)); border: 1px solid var(--stroke); border-radius: 18px; padding: 22px; box-shadow: inset 0 1px 0 rgba(255,255,255,.025), 0 16px 45px rgba(0,0,0,.20); transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease; } .sidebar-card + .sidebar-card { margin-top: 20px; } .sidebar-card:hover { transform: translateY(-2px); border-color: rgba(53,220,255,.15); box-shadow: 0 18px 46px rgba(0,0,0,.24); } .sidebar-card h3 { margin: 0 0 18px; color: #fff; font-size: 13px; } .sidebar-card p, .sidebar-card li { color: var(--muted); font-size: 12px; line-height: 1.82; } .sidebar-card ol { margin: 16px 0 0; padding-left: 20px; } .sidebar-card li + li { margin-top: 13px; } .sidebar-card code { color: #c5f5ff; background: rgba(53,220,255,.07); border: 1px solid rgba(53,220,255,.12); padding: 2px 5px; border-radius: 6px; } .runtime-line { display: flex; align-items: center; justify-content: space-between; gap: 22px; padding: 18px 0; border-bottom: 1px solid rgba(255,255,255,.06); } .runtime-line:last-child { border-bottom: 0; padding-bottom: 2px; } .runtime-line span { color: #718099; font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; min-width: 88px; } .runtime-line strong { color: #eaf0fb; font-size: 11px; text-align: right; max-width: 68%; overflow-wrap: anywhere; line-height: 1.55; } .status-card { border: 1px solid rgba(53,220,255,.16); background: linear-gradient(145deg, rgba(53,220,255,.065), rgba(147,104,255,.035)); border-radius: 18px; padding: 16px; color: #acb8cc; min-height: 98px; box-shadow: inset 0 1px 0 rgba(255,255,255,.028), 0 16px 40px rgba(0,0,0,.18); } .status-row { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #667085; box-shadow: 0 0 0 4px rgba(102,112,133,.08); } .status-card.active .status-dot { background: var(--green); box-shadow: 0 0 0 4px rgba(69,230,163,.08), 0 0 18px rgba(69,230,163,.55); } .status-kicker { color: #718099; font-size: 9px; font-weight: 900; letter-spacing: .13em; } .status-card strong { display: block; color: #fff; font-size: 15px; margin-bottom: 5px; } .status-details { display: block; color: #8e9aaf; font-size: 11px; line-height: 1.45; } .section-head { margin-bottom: 18px; padding: 2px 2px 0; } .section-head .section-kicker { color: var(--cyan); font-size: 10px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase; } .section-head h2 { margin: 6px 0 5px; font-size: 22px; color: #fff; letter-spacing: -.025em; } .section-head p { margin: 0; color: #7f8aa0; font-size: 12px; line-height: 1.55; } #main-tabs [role="tablist"] { padding: 20px 22px 21px !important; gap: 14px !important; min-height: 88px !important; align-items: center !important; border-top: 1px solid rgba(255,255,255,.045) !important; border-bottom: 2px solid rgba(255,255,255,.10) !important; background: linear-gradient(180deg, rgba(255,255,255,.028), rgba(255,255,255,.012)) !important; } #main-tabs button[role="tab"] { margin: 0 !important; padding: 16px 24px !important; min-height: 54px !important; min-width: 180px !important; display: inline-flex !important; align-items: center !important; justify-content: center !important; border: 1px solid rgba(255,255,255,.09) !important; border-radius: 14px !important; color: #a7b0c2 !important; background: rgba(255,255,255,.018) !important; font-size: 14px !important; font-weight: 700 !important; transition: background .18s ease, border-color .18s ease, color .18s ease, transform .18s ease !important; } #main-tabs button[role="tab"]::before, #main-tabs button[role="tab"]::after { display: none !important; content: none !important; } #main-tabs button[role="tab"]:hover { color: #fff !important; background: rgba(255,255,255,.045) !important; transform: translateY(-1px); } #main-tabs button[role="tab"][aria-selected="true"] { color: #fff !important; background: linear-gradient(135deg, rgba(53,220,255,.13), rgba(147,104,255,.11)) !important; border-color: rgba(53,220,255,.31) !important; box-shadow: 0 8px 22px rgba(0,0,0,.2), 0 0 18px rgba(53,220,255,.055) !important; } .tab-body { padding: 34px 28px 32px !important; } #load-button, #train-button, #compare-button, #code-button, #agent-button { font-weight: 900 !important; color: #041017 !important; background: linear-gradient(135deg, #74e9ff 0%, #35dcff 42%, #927fff 100%) !important; border: 0 !important; border-radius: 12px !important; box-shadow: 0 10px 28px rgba(53,220,255,.15), inset 0 1px 0 rgba(255,255,255,.35) !important; transition: transform .16s ease, filter .16s ease, box-shadow .16s ease !important; } #load-button:hover, #train-button:hover, #compare-button:hover, #code-button:hover, #agent-button:hover { transform: translateY(-1px); filter: brightness(1.07); box-shadow: 0 14px 34px rgba(53,220,255,.21), 0 0 28px rgba(147,104,255,.08) !important; } #agent-button { min-height: 50px !important; font-size: 14px !important; } button.secondary, button:not(.primary) { border-radius: 11px !important; } .gradio-container textarea, .gradio-container input, .gradio-container select { color: #eef3ff !important; } .gradio-container .wrap, .gradio-container .form, .gradio-container [data-testid="block-info"] { border-color: rgba(255,255,255,.075) !important; } .gradio-container .block { border-radius: 15px !important; } .gradio-container label span { color: #9ca8bc !important; } .gradio-container [data-testid="file-upload"] { border: 1px dashed rgba(53,220,255,.24) !important; background: linear-gradient(145deg, rgba(53,220,255,.035), rgba(147,104,255,.025)) !important; border-radius: 16px !important; transition: border-color .22s ease, background .22s ease, box-shadow .22s ease; } .gradio-container [data-testid="file-upload"]:hover { border-color: rgba(53,220,255,.43) !important; background: linear-gradient(145deg, rgba(53,220,255,.055), rgba(147,104,255,.035)) !important; box-shadow: inset 0 0 34px rgba(53,220,255,.025), 0 10px 26px rgba(0,0,0,.14); } #dataset-preview, #dataset-schema, #feature-importance, #leaderboard { margin-top: 18px !important; overflow: visible !important; } #dataset-preview [data-testid="block-info"], #dataset-schema [data-testid="block-info"], #feature-importance [data-testid="block-info"], #leaderboard [data-testid="block-info"] { position: relative !important; inset: auto !important; transform: none !important; display: block !important; width: 100% !important; margin: 0 0 9px !important; padding: 0 2px !important; line-height: 1.35 !important; overflow: visible !important; clip: auto !important; white-space: normal !important; } .gradio-container table { border-collapse: separate !important; border-spacing: 0 !important; } .gradio-container th { background: #111626 !important; color: #c9d3e6 !important; border-color: rgba(255,255,255,.07) !important; font-size: 11px !important; } .gradio-container td { background: rgba(9,12,22,.84) !important; color: #abb7cb !important; border-color: rgba(255,255,255,.055) !important; font-size: 11px !important; } .gradio-container tbody tr:hover td { background: rgba(53,220,255,.035) !important; color: #d7e2f5 !important; } .result-tabs [role="tablist"] { gap: 6px !important; margin-top: 8px !important; } .result-tabs button[role="tab"] { border-radius: 9px !important; font-weight: 800 !important; } .info-note { margin-top: 15px; padding: 12px 14px; border: 1px solid rgba(255,196,107,.18); border-left: 3px solid var(--amber); border-radius: 12px; background: rgba(255,196,107,.045); color: #b9b3a5; font-size: 11px; line-height: 1.55; } .metric-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 8px 0 20px; } .metric-chip { border: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.025); border-radius: 14px; padding: 13px 14px; } .metric-chip span { display: block; color: #718099; font-size: 9px; font-weight: 900; letter-spacing: .09em; text-transform: uppercase; } .metric-chip strong { display: block; color: #edf4ff; font-size: 12px; margin-top: 5px; } .footer-note { color: #5f6b80; font-size: 10px; text-align: center; margin-top: 18px; letter-spacing: .05em; } @media (prefers-reduced-motion: reduce) { .hero::after, .hero-orbit::before, .hero-orbit::after, .hero-orbit-core { animation: none !important; } } @media (max-width: 980px) { .hero-grid { grid-template-columns: 1fr; } .hero-orbit { display: none; } .workflow-strip { grid-template-columns: repeat(2, minmax(0,1fr)); } .metric-strip { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 800px) { .main-shell { padding: 14px 10px 28px; } .hero { padding: 28px 21px 26px; border-radius: 22px; } .hero h1 { font-size: 42px; } .tab-body { padding: 20px 15px 22px !important; } #main-tabs [role="tablist"] { padding: 14px !important; min-height: 74px !important; gap: 10px !important; overflow-x: auto; flex-wrap: nowrap !important; } #main-tabs button[role="tab"] { min-width: 170px !important; padding: 14px 20px !important; } } @media (max-width: 560px) { .hero h1 { font-size: 36px; } .workflow-strip, .metric-strip { grid-template-columns: 1fr; } } /* ========================================================= SPECTRAL OBSIDIAN UI Presentation-only redesign. No ML / agent logic changed. ========================================================= */ :root { --obsidian: #050408; --obsidian-2: #0a0710; --surface: rgba(18, 13, 24, .84); --surface-strong: rgba(24, 16, 31, .95); --surface-soft: rgba(255, 255, 255, .035); --line: rgba(255, 255, 255, .09); --line-bright: rgba(255, 255, 255, .16); --rose: #ff5f87; --rose-soft: rgba(255, 95, 135, .13); --gold: #ffd37a; --gold-soft: rgba(255, 211, 122, .12); --mint: #61f3c2; --mint-soft: rgba(97, 243, 194, .10); --lilac: #a98bff; --lilac-soft: rgba(169, 139, 255, .12); --ice: #dffcff; --text-strong: #fffafc; --text-body: #c7becd; --text-dim: #807487; } /* Full canvas */ html, body { background: var(--obsidian) !important; } .gradio-container { max-width: 1640px !important; color: var(--text-strong) !important; background: radial-gradient(circle at 10% -8%, rgba(255,95,135,.20), transparent 30%), radial-gradient(circle at 93% 2%, rgba(169,139,255,.17), transparent 29%), radial-gradient(circle at 74% 102%, rgba(97,243,194,.08), transparent 32%), radial-gradient(circle at 12% 92%, rgba(255,211,122,.055), transparent 28%), linear-gradient(145deg, #050408 0%, #08060d 48%, #0a0710 100%) !important; } .gradio-container::before { opacity: .22 !important; background-image: linear-gradient(rgba(255,255,255,.018) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.018) 1px, transparent 1px), radial-gradient(circle, rgba(255,255,255,.04) 1px, transparent 1px) !important; background-size: 54px 54px, 54px 54px, 18px 18px !important; mask-image: linear-gradient(to bottom, black 0%, rgba(0,0,0,.7) 58%, transparent 95%) !important; } .main-shell { padding: 34px 30px 50px !important; } /* Hero */ .hero { border-radius: 34px !important; padding: 50px 50px 46px !important; margin-bottom: 18px !important; border: 1px solid rgba(255,255,255,.11) !important; background: linear-gradient(125deg, rgba(31,17,35,.97), rgba(10,8,15,.96) 56%, rgba(15,10,23,.97)) !important; box-shadow: 0 38px 120px rgba(0,0,0,.56), inset 0 1px 0 rgba(255,255,255,.055), inset 0 0 90px rgba(255,95,135,.025) !important; } .hero::before { height: 2px !important; background: linear-gradient(90deg, transparent 2%, var(--rose) 21%, var(--gold) 44%, var(--mint) 66%, var(--lilac) 84%, transparent 98%) !important; box-shadow: 0 0 24px rgba(255,95,135,.28), 0 0 44px rgba(169,139,255,.18) !important; } .hero::after { width: 720px !important; height: 720px !important; right: -285px !important; top: -365px !important; background: radial-gradient(circle at 50% 50%, rgba(255,95,135,.10), transparent 34%), conic-gradient( from 15deg, rgba(255,95,135,.23), rgba(255,211,122,.10), rgba(97,243,194,.10), rgba(169,139,255,.22), rgba(255,95,135,.23) ) !important; filter: blur(1px); } .hero-grid { gap: 38px !important; align-items: center !important; } .eyebrow { color: #ffd9e4 !important; font-size: 10px !important; letter-spacing: .20em !important; background: rgba(255,95,135,.07); border: 1px solid rgba(255,95,135,.16); border-radius: 999px; padding: 8px 11px; } .eyebrow-dot { background: var(--mint) !important; box-shadow: 0 0 0 4px rgba(97,243,194,.08), 0 0 18px rgba(97,243,194,.72) !important; } .hero h1 { margin: 18px 0 14px !important; max-width: 1040px !important; font-size: clamp(46px, 5.3vw, 76px) !important; line-height: .98 !important; letter-spacing: -.052em !important; font-weight: 950 !important; color: #fffafa !important; text-shadow: 0 8px 38px rgba(0,0,0,.32); } .hero p { max-width: 1020px !important; color: #c3b8c8 !important; font-size: 15.5px !important; line-height: 1.78 !important; } /* Hero signal rail */ .hero-signal-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; max-width: 800px; margin-top: 22px; } .hero-signal { position: relative; overflow: hidden; border: 1px solid rgba(255,255,255,.075); border-radius: 14px; padding: 12px 13px; background: rgba(255,255,255,.027); backdrop-filter: blur(14px); } .hero-signal::before { content: ""; position: absolute; width: 58px; height: 58px; right: -20px; top: -27px; border-radius: 50%; background: radial-gradient(circle, rgba(255,95,135,.18), transparent 70%); } .hero-signal:nth-child(2)::before { background: radial-gradient(circle, rgba(97,243,194,.16), transparent 70%); } .hero-signal:nth-child(3)::before { background: radial-gradient(circle, rgba(169,139,255,.18), transparent 70%); } .hero-signal span { display: block; color: #776d7d; font-size: 8.5px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase; } .hero-signal strong { display: block; color: #fff9fb; font-size: 11px; margin-top: 5px; } /* Hero visual */ .hero-orbit { width: 194px !important; height: 194px !important; border-radius: 38px !important; border: 1px solid rgba(255,255,255,.10) !important; background: radial-gradient(circle at 50% 50%, rgba(255,95,135,.055), transparent 45%), linear-gradient(145deg, rgba(255,95,135,.055), rgba(169,139,255,.055)) !important; box-shadow: inset 0 0 58px rgba(169,139,255,.035), 0 18px 60px rgba(0,0,0,.25) !important; } .hero-orbit::before { inset: 27px !important; border-color: rgba(255,211,122,.20) !important; box-shadow: inset 0 0 18px rgba(255,211,122,.025); } .hero-orbit::after { inset: 61px !important; border-color: rgba(97,243,194,.36) !important; box-shadow: 0 0 28px rgba(97,243,194,.10), inset 0 0 18px rgba(97,243,194,.05) !important; } .hero-orbit-core { width: 20px !important; height: 20px !important; border-radius: 7px !important; background: linear-gradient(135deg, var(--rose), var(--gold) 48%, var(--mint)) !important; box-shadow: 0 0 22px rgba(255,95,135,.42), 0 0 44px rgba(97,243,194,.20) !important; } /* Badges */ .badges { gap: 8px !important; margin-top: 18px !important; } .badge { color: #bcb2c2 !important; background: rgba(255,255,255,.028) !important; border-color: rgba(255,255,255,.085) !important; padding: 8px 12px !important; } .badge strong { color: #fff8fa !important; } .badge-accent { color: #ffdbe5 !important; border-color: rgba(255,95,135,.22) !important; background: rgba(255,95,135,.065) !important; } .badge:hover { border-color: rgba(255,95,135,.26) !important; background: rgba(255,95,135,.055) !important; } /* Workflow */ .workflow-strip { gap: 12px !important; margin-bottom: 20px !important; } .workflow-step { min-height: 100px !important; padding: 17px 17px 15px !important; border-radius: 21px !important; border: 1px solid rgba(255,255,255,.075) !important; background: linear-gradient(145deg, rgba(255,255,255,.037), rgba(255,255,255,.014)) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.028), 0 12px 32px rgba(0,0,0,.12); } .workflow-step::before { content: ""; position: absolute; left: 16px; right: 16px; top: 0; height: 2px; border-radius: 999px; background: var(--rose); opacity: .8; box-shadow: 0 0 18px rgba(255,95,135,.28); } .workflow-step:nth-child(2)::before { background: var(--gold); box-shadow: 0 0 18px rgba(255,211,122,.20); } .workflow-step:nth-child(3)::before { background: var(--mint); box-shadow: 0 0 18px rgba(97,243,194,.20); } .workflow-step:nth-child(4)::before { background: var(--lilac); box-shadow: 0 0 18px rgba(169,139,255,.25); } .workflow-step:hover { transform: translateY(-5px) !important; border-color: rgba(255,255,255,.13) !important; background: linear-gradient(145deg, rgba(255,255,255,.052), rgba(255,255,255,.021)) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.04), 0 20px 45px rgba(0,0,0,.25) !important; } .workflow-step span { color: #756b7c !important; font-size: 9px !important; letter-spacing: .15em !important; } .workflow-step strong { color: #fff9fb !important; font-size: 14px !important; margin-top: 8px !important; } .workflow-step small { color: #8e8495 !important; line-height: 1.4; margin-top: 5px !important; } /* Main content panel */ .app-panel { position: relative; border-radius: 29px !important; border: 1px solid rgba(255,255,255,.085) !important; background: linear-gradient(160deg, rgba(17,12,23,.91), rgba(9,7,13,.88)) !important; box-shadow: 0 30px 82px rgba(0,0,0,.40), inset 0 1px 0 rgba(255,255,255,.035) !important; backdrop-filter: blur(22px); } .app-panel::after { content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit; box-shadow: inset 0 0 70px rgba(255,95,135,.012), inset 0 0 100px rgba(169,139,255,.01); } /* Navigation tabs */ #main-tabs [role="tablist"] { padding: 18px !important; gap: 9px !important; min-height: 80px !important; border-bottom: 1px solid rgba(255,255,255,.075) !important; background: linear-gradient(180deg, rgba(255,255,255,.028), rgba(255,255,255,.008)) !important; } #main-tabs button[role="tab"] { min-width: 182px !important; min-height: 48px !important; padding: 13px 20px !important; color: #9e93a5 !important; border: 1px solid rgba(255,255,255,.065) !important; border-radius: 15px !important; background: rgba(255,255,255,.018) !important; font-size: 13px !important; font-weight: 800 !important; letter-spacing: -.012em !important; } #main-tabs button[role="tab"]:hover { color: #fff9fb !important; border-color: rgba(255,95,135,.20) !important; background: rgba(255,95,135,.04) !important; } #main-tabs button[role="tab"][aria-selected="true"] { color: #fff !important; border-color: rgba(255,95,135,.30) !important; background: linear-gradient(135deg, rgba(255,95,135,.13), rgba(169,139,255,.085)) !important; box-shadow: inset 0 0 0 1px rgba(255,255,255,.018), 0 10px 28px rgba(0,0,0,.20), 0 0 22px rgba(255,95,135,.05) !important; } .tab-body { padding: 38px 32px 36px !important; } /* Section headers */ .section-head { position: relative; margin-bottom: 24px !important; padding: 0 0 18px 0 !important; border-bottom: 1px solid rgba(255,255,255,.06); } .section-head::after { content: ""; position: absolute; left: 0; bottom: -1px; width: 84px; height: 2px; border-radius: 999px; background: linear-gradient(90deg, var(--rose), var(--gold)); box-shadow: 0 0 16px rgba(255,95,135,.18); } .section-head .section-kicker { display: inline-flex; align-items: center; gap: 7px; width: fit-content; color: #ffd8e3 !important; font-size: 9px !important; font-weight: 900 !important; letter-spacing: .14em !important; padding: 6px 9px; border-radius: 999px; border: 1px solid rgba(255,95,135,.14); background: rgba(255,95,135,.055); } .section-head h2 { margin: 11px 0 6px !important; color: #fff9fb !important; font-size: 25px !important; line-height: 1.18; letter-spacing: -.035em !important; } .section-head p { max-width: 920px; color: #93889b !important; font-size: 12.5px !important; line-height: 1.66 !important; } /* Sidebar */ .side-column { gap: 16px !important; } .sidebar-card { position: relative; overflow: hidden; border-radius: 22px !important; padding: 23px !important; border: 1px solid rgba(255,255,255,.075) !important; background: linear-gradient(150deg, rgba(24,16,30,.92), rgba(11,8,15,.90)) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.03), 0 18px 48px rgba(0,0,0,.20) !important; } .sidebar-card::after { content: ""; position: absolute; width: 150px; height: 150px; right: -95px; top: -95px; border-radius: 50%; background: radial-gradient(circle, rgba(255,95,135,.09), transparent 70%); pointer-events: none; } .sidebar-card + .sidebar-card { margin-top: 16px !important; } .sidebar-card:hover { border-color: rgba(255,95,135,.16) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.035), 0 22px 55px rgba(0,0,0,.27) !important; } .sidebar-card h3 { color: #fff9fb !important; font-size: 12px !important; font-weight: 900 !important; letter-spacing: .02em; } .sidebar-card p, .sidebar-card li { color: #9b90a2 !important; } .sidebar-card li::marker { color: var(--rose); font-weight: 800; } .sidebar-card code { color: #ffe2ea !important; border-color: rgba(255,95,135,.13) !important; background: rgba(255,95,135,.06) !important; } .runtime-line { padding: 17px 0 !important; border-bottom-color: rgba(255,255,255,.055) !important; } .runtime-line span { color: #756a7c !important; } .runtime-line strong { color: #f8eef9 !important; } /* Workspace status */ .status-card { border-radius: 22px !important; min-height: 105px !important; padding: 18px !important; border: 1px solid rgba(97,243,194,.13) !important; background: linear-gradient(145deg, rgba(97,243,194,.055), rgba(255,95,135,.035)) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.025), 0 18px 44px rgba(0,0,0,.18) !important; } .status-card.active .status-dot { background: var(--mint) !important; box-shadow: 0 0 0 5px rgba(97,243,194,.07), 0 0 20px rgba(97,243,194,.56) !important; } .status-kicker { color: #7c7183 !important; } .status-card strong { color: #fff9fb !important; } .status-details { color: #978b9e !important; } /* Buttons */ #load-button, #train-button, #compare-button, #code-button, #agent-button { min-height: 47px !important; border: 0 !important; border-radius: 14px !important; color: #16070d !important; font-weight: 950 !important; letter-spacing: -.012em !important; background: linear-gradient(135deg, #ff8ba8 0%, #ff648b 42%, #ffd37a 100%) !important; box-shadow: 0 12px 30px rgba(255,95,135,.16), inset 0 1px 0 rgba(255,255,255,.48) !important; } #train-button:hover, #compare-button:hover, #code-button:hover, #load-button:hover, #agent-button:hover { transform: translateY(-2px) !important; filter: brightness(1.06) saturate(1.04) !important; box-shadow: 0 16px 38px rgba(255,95,135,.22), 0 0 28px rgba(255,211,122,.06) !important; } /* Center and evenly space the three primary ML Modeling actions only. */ .model-action-row { width: 100% !important; max-width: 880px !important; margin: 24px auto 0 !important; display: flex !important; justify-content: center !important; align-items: center !important; gap: clamp(28px, 4vw, 48px) !important; } .model-action-row > *, .model-action-row #train-button, .model-action-row #compare-button, .model-action-row #code-button { flex: 0 1 260px !important; width: 260px !important; max-width: 260px !important; min-width: 0 !important; margin: 0 !important; } @media (max-width: 820px) { .model-action-row { gap: 16px !important; } .model-action-row > *, .model-action-row #train-button, .model-action-row #compare-button, .model-action-row #code-button { flex: 1 1 0 !important; width: auto !important; max-width: none !important; min-width: 0 !important; } } @media (max-width: 620px) { .model-action-row { flex-direction: column !important; gap: 12px !important; max-width: 420px !important; } .model-action-row > *, .model-action-row #train-button, .model-action-row #compare-button, .model-action-row #code-button { width: 100% !important; max-width: 420px !important; flex: 0 0 auto !important; } } /* Secondary buttons */ .gradio-container button.secondary, .gradio-container button:not(.primary) { border-radius: 13px !important; color: #c9bfce !important; border: 1px solid rgba(255,255,255,.075) !important; background: rgba(255,255,255,.025) !important; } .gradio-container button.secondary:hover, .gradio-container button:not(.primary):hover { color: #fff !important; border-color: rgba(255,95,135,.17) !important; background: rgba(255,95,135,.035) !important; } /* Inputs */ .gradio-container textarea, .gradio-container input, .gradio-container select { color: #fff7fa !important; } .gradio-container .block { border-radius: 17px !important; } .gradio-container [data-testid="block-info"] { color: #a99daf !important; } .gradio-container [data-testid="file-upload"] { min-height: 120px; border: 1px dashed rgba(255,95,135,.24) !important; border-radius: 19px !important; background: linear-gradient(145deg, rgba(255,95,135,.035), rgba(169,139,255,.025)) !important; transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease, background .22s ease !important; } .gradio-container [data-testid="file-upload"]:hover { transform: translateY(-2px); border-color: rgba(255,95,135,.42) !important; background: linear-gradient(145deg, rgba(255,95,135,.055), rgba(169,139,255,.038)) !important; box-shadow: inset 0 0 35px rgba(255,95,135,.02), 0 13px 34px rgba(0,0,0,.16) !important; } /* Metric strip */ .metric-strip { gap: 11px !important; margin: 12px 0 22px !important; } .metric-chip { position: relative; overflow: hidden; min-height: 79px; border-radius: 18px !important; padding: 15px !important; border: 1px solid rgba(255,255,255,.07) !important; background: linear-gradient(145deg, rgba(255,255,255,.032), rgba(255,255,255,.013)) !important; } .metric-chip::before { content: ""; position: absolute; left: 0; top: 0; width: 3px; height: 100%; background: var(--rose); opacity: .75; } .metric-chip:nth-child(2)::before { background: var(--gold); } .metric-chip:nth-child(3)::before { background: var(--mint); } .metric-chip:nth-child(4)::before { background: var(--lilac); } .metric-chip span { color: #766c7c !important; font-size: 8.5px !important; } .metric-chip strong { color: #fff8fa !important; font-size: 11.5px !important; line-height: 1.45; } /* Tables */ .gradio-container table { border-collapse: separate !important; border-spacing: 0 !important; } .gradio-container th { background: #17101d !important; color: #eadfea !important; border-color: rgba(255,255,255,.065) !important; font-size: 10.5px !important; font-weight: 850 !important; } .gradio-container td { background: rgba(11,8,15,.88) !important; color: #b5aabb !important; border-color: rgba(255,255,255,.045) !important; font-size: 10.5px !important; } .gradio-container tbody tr:hover td { background: rgba(255,95,135,.035) !important; color: #eee4ef !important; } /* Dataset labels */ #dataset-preview, #dataset-schema, #feature-importance, #leaderboard { margin-top: 18px !important; overflow: visible !important; } #dataset-preview [data-testid="block-info"], #dataset-schema [data-testid="block-info"], #feature-importance [data-testid="block-info"], #leaderboard [data-testid="block-info"] { display: block !important; position: relative !important; inset: auto !important; transform: none !important; margin: 0 0 9px !important; padding: 0 2px !important; width: 100% !important; color: #fff8fa !important; font-size: 12px !important; font-weight: 800 !important; line-height: 1.35 !important; white-space: normal !important; overflow: visible !important; clip: auto !important; } /* Code / JSON outputs */ .gradio-container pre, .gradio-container code { font-feature-settings: "liga" 1, "calt" 1; } /* Accordions */ .gradio-container details { border-radius: 18px !important; border-color: rgba(255,255,255,.07) !important; background: rgba(255,255,255,.018) !important; } .gradio-container details:hover { border-color: rgba(255,95,135,.15) !important; box-shadow: 0 12px 32px rgba(0,0,0,.14) !important; } /* Info note */ .info-note { border-radius: 15px !important; border: 1px solid rgba(255,211,122,.15) !important; border-left: 3px solid var(--gold) !important; background: rgba(255,211,122,.035) !important; color: #b9adb7 !important; padding: 14px 15px !important; } .info-note strong { color: #ffe5aa; } .info-note code { color: #fff0c8; background: rgba(255,211,122,.055); border: 1px solid rgba(255,211,122,.10); padding: 2px 5px; border-radius: 6px; } /* Footer */ .footer-note { color: #655b6b !important; font-size: 9px !important; letter-spacing: .14em !important; margin-top: 23px !important; } /* ========================================================= GRADIO FLOATING-UI / OUTPUT CLIPPING FIXES - Dropdown menus use floating positioning. backdrop-filter on an ancestor creates a new containing block and can shift the popup by the panel's page offset. - The original app-panel rule also used overflow:hidden, which can clip dropdowns and first-line Markdown headings. ========================================================= */ .app-panel { overflow: visible !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } #main-tabs, #main-tabs [role="tabpanel"], #main-tabs .tab-body, .model-controls-row, .model-control { overflow: visible !important; } .model-controls-row { position: relative !important; z-index: 40 !important; } .model-control { position: relative !important; z-index: 41 !important; } .model-control:focus-within { z-index: 1000 !important; } /* Keep Gradio/Floating-UI dropdown option panels above the rest of the model tab. */ .gradio-container [role="listbox"] { z-index: 100000 !important; } /* Second-pass stacking/layout fixes from browser screenshots. 1) Gradio 6 renders Dropdown options as a fixed