from __future__ import annotations import gradio as gr import json from api import register_api from data_loading import ( AXIS_NOTES, CATEGORY_COMING_SOON, DATA_DIR, DATASET_LABELS, DATASET_NOTES, PROTOCOL_NOTES, SYSTEM_CATEGORY_LABELS, SYSTEM_CATEGORY_NOTES, TASK_LABELS, TASK_NOTES, available_categories, ) from pages import PAGES, render_page from views import CARE_LABELS, CARE_NOTES, METRIC_LABELS, METRIC_NOTES from website_texts import COI_HTML, TITLE def _choice_hints() -> dict[str, str]: """Control label -> the hover text explaining it. Keyed by the rendered label, because that is all the DOM gives `taStampTitles` to match on. Covers the chip bars and the checkboxes alike: Gradio's own ``info`` renders as standing text under the control and its markup shifts between versions, so nothing here uses it. Built from the same dicts the controls are built from, so a new choice cannot end up without an explanation by accident. """ hints: dict[str, str] = {} for labels, notes in ( (TASK_LABELS, TASK_NOTES), (DATASET_LABELS, DATASET_NOTES), (CARE_LABELS, CARE_NOTES), (METRIC_LABELS, METRIC_NOTES), ): for key, label in labels.items(): if key in notes: hints[label] = notes[key] hints["🤖 Models"] = "Always on: TabArena is a model benchmark first." hints["One per model"] = ( "Keep only each model's best-performing variant, one row per model — as the win-rate " "matrix does. With it off, every variant gets its own row, so you can read what " "tuning bought." ) hints["Include imputed models"] = PROTOCOL_NOTES["imputed"] hints["TabArena-Lite (single split)"] = PROTOCOL_NOTES["lite"] # A category with no entrant yet says so, matching the disabled state the page renders. available = available_categories(str(DATA_DIR)) for key, label in SYSTEM_CATEGORY_LABELS.items(): hints[label] = SYSTEM_CATEGORY_NOTES[key] if key in available else CATEGORY_COMING_SOON return hints CSS = """ /* Use the full page width instead of gradio's narrow centered column. */ .gradio-container { max-width: 100% !important; } /* Leave room for the fixed selection bar (.ta-selbar sits 18px off the bottom and is ~42px tall). Without this the page still scrolls to its end, but the end sits underneath the bar, which reads as not being able to get to the bottom. */ .gradio-container { padding-bottom: 78px !important; } /* And room at the top for the two corner chips, which are fixed and so reserve none of their own. They sit side by side on the left and reach far enough across to meet the title, which otherwise starts underneath them at every width. */ .gradio-container { padding-top: 46px !important; } /* --- Colour emoji ---------------------------------------------------------- Gradio's own font stack ends "… "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"" — the colour emoji fonts sit *after* the generic `sans-serif`, which matches everything, so the browser never reaches them and resolves emoji through its own fallback instead. On Linux that commonly lands on the monochrome Noto Emoji, which is why 🧠⚡ / 🤖 / 🥇 render flat there and in colour on macOS and Windows. Same stack in Gradio 5, so this is long-standing rather than new. Naming the colour fonts before the generic fixes it for every emoji on the page; Latin glyphs are unaffected because those fonts carry none. Overriding the two variables rather than `font-family` directly is what makes it stick for Gradio's components: its own rules set `font-family: var(--font)` / `var(--font-sans)` on individual elements, which would beat a container-level declaration. Raw HTML (`gr.HTML`) has no such rule and is handled by the element-level block below. */ :root, .gradio-container, html body { --font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; --font-sans: var(--font); font-family: var(--font); } /* A colour-emoji family restricted to emoji codepoints. The emoji fonts have to lead the stack below to win over the browser's own fallback, but they must not serve anything else: Noto Color Emoji carries a SPACE glyph 1.25 em wide (2550/2048 units, i.e. emoji-width, against ~0.2 em in a text font), so leading with the raw family names stretched every gap between words wherever that font is installed — Latin letters fell through to IBM Plex Sans, but U+0020 did not, because the emoji font *does* have it. Binding the fonts through `unicode-range` keeps them first for emoji while spaces and Latin resolve from the text font. */ @font-face { font-family: "TA Color Emoji"; src: local("Apple Color Emoji"), local("Segoe UI Emoji"), local("Noto Color Emoji"), local("Twemoji Mozilla"); unicode-range: U+00A9, U+00AE, U+203C, U+2049, U+2122, U+2139, U+2194-21AA, U+231A-231B, U+2328, U+23CF, U+23E9-23FA, U+24C2, U+25AA-25FE, U+2600-27BF, U+2934-2935, U+2B00-2BFF, U+3030, U+303D, U+3297, U+3299, U+200D, U+20E3, U+FE0E-FE0F, U+1F000-1FAFF, U+E0020-E007F; } /* Overriding the variables above fixes Gradio's own components (buttons, tabs), which resolve `font-family: var(--font)` per element. It does not reach content inside `gr.HTML`, which has no per-element rule of its own — so the elements we write by hand are listed here and get the colour fonts forced. The emoji family leads and `!important` settles the cascade; every other character, space included, resolves from IBM Plex Sans because the family above answers only for emoji codepoints. Add a selector here if an emoji shows up flat somewhere new. */ .ta-card-ico, .ta-path-ico, .ta-pill, .ta-lb-title, .ta-figbar-title, .ta-section-head h2, .ta-jump, .ta-viewbtn, .coi-badge, .ta-legend, .ta-lbtable td.ta-type-cell, .ta-verified, .ta-link-icon, .ta-cap, .coi-cta, .markdown-text h1, .markdown-text h2, .markdown-text h3, .markdown-text h4 { font-family: "TA Color Emoji", "IBM Plex Sans", ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif !important; } /* Gradio 6 pads every anchor inside a gr.HTML / gr.Markdown block: .gradio-container-6-22-0 .gradio-style a { padding: 2px 8px; text-align: center } That is a link-button style, and it lands on inline links too, which is where the gaps around "(see paper)" / "(see code)" in the hero cards came from. Reset for the links we write as running text — they are the ones with no class of their own — at a specificity that beats Gradio's two-class selector whatever the stylesheet order turns out to be. The pill-shaped links keep their own padding (below, where the same Gradio rule is why they have to say `!important`). */ .gradio-container .gradio-style a:not([class]) { padding: 0; } .markdown-text-box { padding: 4px; border-radius: 2px; } /* Intro tagline as a full-width card inside the hero group, above the stat boxes. Tinted with the app accent (blue) so it stands out from the neutral stat cards. */ .ta-intro { flex: 1 1 100%; padding: 11px 16px; border: 1px solid rgba(110, 140, 245, 0.5); border-radius: 10px; background: linear-gradient(135deg, rgba(110, 140, 245, 0.22), rgba(110, 140, 245, 0.07)); text-align: center; font-size: 1.05em; font-weight: 600; line-height: 1.4; color: #e6ebff; } /* --- Subset filter rows ---------------------------------------------------- The two content axes (task, dataset size) and the two view modifiers are one control cluster, so they are drawn as three rows of the same panel: same frame, same height, and a small uppercase label on the left saying which axis the row switches. Before this the tab bars were bare text above a bordered toggle box, which read as two unrelated controls. Gradio 6 renders a Tabs as .tabs > .tab-wrapper > .tab-container > button and marks the active tab .selected, styling it with a 2px underline. Here the row frame lives on .tab-wrapper and the choices are flat chips with the active one filled. Note .tab-wrapper holds a *second*, visually hidden .tab-container that Gradio measures to decide which tabs go into its overflow menu, which is why the chip rules deliberately hit every .tab-container: styling only the visible copy would make it mis-measure. */ .tab-buttons { gap: 0 !important; /* Cancel the column gap the surrounding Blocks layout adds between the rows, then set the row spacing here. */ margin: 0 0 calc(5px - var(--layout-gap)) !important; } .tab-buttons .tab-wrapper { height: auto; align-items: center; margin-bottom: 0; padding: 5px 12px 5px 14px; background: #ffffff0a; border: 1px solid #ffffff26; border-radius: 10px; } /* The rule Gradio draws under a tab bar; the row frame replaces it. */ .tab-buttons .tab-container::after { display: none; } .tab-buttons .tab-container { gap: 3px; height: auto; } .tab-buttons .tab-container > button { /* One neutral slate, and how strongly a chip is tinted says how deep in the axis it sits: the row's "all" chip is the whole set, the next level is a subset of it, and the lightest chips are subsets of a subset. Peers share a step, so nothing in the row reads as ranked above anything else — Small and Medium are the same tint, and so are Binary and Multiclass. Selection is the one place a colour changes hue, and it is the app accent, the same as everywhere else. */ --depth: 0.62; height: auto; padding: 5px 12px; font-size: 0.86em; font-weight: 600; color: #cbd5ef; background: rgba(158, 176, 208, calc(0.3 * var(--depth))); border: none; border-radius: 8px; transition: background .14s ease, color .14s ease; } .tab-buttons .tab-container > button:hover:not(.selected) { background: rgba(158, 176, 208, calc(0.62 * var(--depth))); color: #ffffff; } .tab-buttons .tab-container > button.selected { color: #ffffff; background: rgba(110, 140, 245, 0.92); box-shadow: 0 1px 3px #0000005c; } /* The depth steps. Gradio gives the tabs no per-tab class, so they are addressed by position — the nth-child order is the insertion order of TASK_LABELS / DATASET_LABELS: all, classification, regression, binary, multiclass and all, small, medium. Chips 4 and 5 of the task row are the two classification flavours, one level further in than Classification itself. */ .axis-tasks .tab-container > button:nth-child(1), .axis-datasets .tab-container > button:nth-child(1) { --depth: 1; } .axis-tasks .tab-container > button:nth-child(n+4) { --depth: 0.34; } /* The filled chip is the selection cue; Gradio's underline would sit inside it. */ .tab-buttons .tab-container > button.selected::after { display: none; } /* The row labels: one style, one width, so the three rows line up on the left. */ .axis-tasks .tab-wrapper::before, .axis-datasets .tab-wrapper::before, .axis-care .tab-wrapper::before, .axis-metric .tab-wrapper::before, .view-toggles::before { flex: 0 0 auto; min-width: 74px; font-size: 0.68em; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.5; white-space: nowrap; align-self: center; } .axis-tasks .tab-wrapper::before { content: "Task"; } .axis-datasets .tab-wrapper::before { content: "Datasets"; } .axis-care .tab-wrapper::before { content: "🎯 I care about"; } .axis-metric .tab-wrapper::before { content: "Measured by"; } /* Third row of the same panel: the view modifiers (imputation / Lite). */ .view-toggles { margin: 0 0 16px 0; padding: 7px 12px 7px 14px; gap: 14px; align-items: center; background: #ffffff0a; border: 1px solid #ffffff26; border-radius: 10px; } .view-toggles::before { content: "View"; } .view-toggles label span { font-size: 0.86em !important; } /* --- The control band at the top of the page ------------------------------- "Who's competing?" and "I care about". These sit above everything because they change every number below them: each entrant pool is its own evaluation (see views/pages), not a filter over a shared table. Styled heavier than the view toggles for that reason. */ .ta-controls { margin: 4px 0 10px 0; padding: 8px 14px; gap: 0 !important; background: #ffffff10; border: 1px solid #ffffff33; border-left: 3px solid rgba(240, 163, 90, 0.7); border-radius: 12px; } .ta-controls .wrap { gap: 4px 10px !important; } .ta-controls label span { font-size: 0.86em !important; } /* One row per group. The caption column is a fixed width so every row's controls start on the same vertical line: that is what makes the card scan as a list rather than a jumble. Rows are separated by a hairline instead of whitespace, which keeps the whole card compact. */ .ta-controlrow { gap: 10px; align-items: center; flex-wrap: wrap; margin: 0 !important; min-height: 0 !important; padding: 5px 0; } .ta-controlrow + .ta-controlrow, .ta-controls .tab-buttons + .ta-controlrow, .ta-controlrow + .tab-buttons, .ta-controls .tab-buttons + .tab-buttons { border-top: 1px solid #ffffff14; } /* Every row caption is drawn the same way: a ::before on the row for the checkbox rows, a ::before on the tab-wrapper for the chip bars. Same width, weight and opacity, so the four captions form one column down the left of the card. */ .ta-row-entrants::before, .ta-row-protocol::before { content: ""; flex: 0 0 auto; width: 150px; align-self: center; font-size: 0.7em; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.6; white-space: nowrap; } .ta-row-entrants::before { content: "🥊 Who’s competing?"; } .ta-row-protocol::before { content: "⚙️ Protocol"; } /* Hints do not stand under the controls: five of them below a row of chips is more noise than the chips themselves. `main.taStampTitles` moves each one into a native `title`, so it shows on hover instead, and the ? badge is what says the text is there at all. */ .ta-controls span[data-testid="block-info"] { display: none !important; } .ta-controlrow .ta-catchip label::after, .metric-select .ta-catchip label::after { content: "?"; flex: 0 0 auto; width: 14px; height: 14px; margin-left: 2px; border: 1px solid currentColor; border-radius: 50%; opacity: 0.45; font-size: 0.66em; font-weight: 700; line-height: 12px; text-align: center; } .ta-controlrow .ta-catchip label:hover::after, .metric-select .ta-catchip label:hover::after { opacity: 0.85; } /* Chip-bar buttons carry a tooltip too; a dotted underline hints at it without a badge on every chip, which at five per row would be louder than the chips. */ .ta-controls .tab-buttons button[title] { text-decoration: underline dotted #ffffff40 1px; text-underline-offset: 3px; } /* The chip bars sit inside the control card, which already draws a frame: drop their own border so the card does not read as boxes within a box, and align their label column with the other rows' captions. */ .ta-controls .tab-buttons { margin: 0 !important; } .ta-controls .tab-buttons .tab-wrapper { padding: 5px 0; gap: 10px; background: transparent; border: none; } .ta-controls .tab-buttons .tab-container { gap: 4px; } .ta-controls .axis-tasks .tab-wrapper::before, .ta-controls .axis-datasets .tab-wrapper::before, .ta-controls .axis-care .tab-wrapper::before, .ta-controls .axis-metric .tab-wrapper::before { width: 150px; min-width: 150px; font-size: 0.7em; letter-spacing: 0.09em; opacity: 0.6; } /* "I care about" and "Measured by" are two halves of one choice, so they read as one group: the emoji sits on the first row only, the second caption is indented and quieter as a continuation of it, and the hairline that separates every other row is dropped between them. */ .ta-controls .axis-care + .axis-metric { border-top: none !important; padding-top: 0 !important; } .ta-controls .axis-care .tab-wrapper { padding-bottom: 1px; } .ta-controls .axis-metric .tab-wrapper { padding-top: 1px; } .ta-controls .axis-metric .tab-wrapper::before { text-indent: 14px; opacity: 0.42; } /* Phones. The caption column is 150px of a ~326px card, so the controls beside it get less room than their own labels need: the entrant chips came out as unreadable slivers, three of the four chip bars collapsed to an ellipsis, and the protocol checkboxes were clipped mid-word. Below this width the caption takes a line of its own and the controls get the whole card; a chip bar scrolls sideways rather than shrinking its chips, which is what it does anyway when it runs out of room, only legibly. */ @media (max-width: 640px) { .ta-row-entrants::before, .ta-row-protocol::before, .ta-controls .axis-tasks .tab-wrapper::before, .ta-controls .axis-datasets .tab-wrapper::before, .ta-controls .axis-care .tab-wrapper::before, .ta-controls .axis-metric .tab-wrapper::before { flex: 0 0 100%; width: 100%; min-width: 0; margin-bottom: 3px; } .ta-controls .tab-buttons .tab-wrapper { flex-wrap: wrap; } .ta-controls .tab-buttons .tab-container { flex: 1 1 100%; min-width: 0; overflow-x: auto; scrollbar-width: thin; } .ta-controls .tab-buttons .tab-container button { flex: 0 0 auto; white-space: nowrap; } /* Two lines beat losing the second half of a label, and two columns beat four slivers: four entrant checkboxes across a phone leave each one about forty pixels of text. */ .ta-controlrow .ta-catchip { flex: 1 1 132px; min-width: 132px; } .ta-controlrow .ta-catchip label { white-space: normal; } .ta-controls { padding: 8px 10px; } } /* Each caption explains its axis on hover (main.taStampTitles). Say so: the same dotted underline the chips use, a help cursor, and a brightening on hover, so "there is more here" reads identically wherever a tooltip exists. `text-decoration` has to be set on the pseudo-element itself; it does not inherit onto ::before from the row. */ .ta-row-entrants::before, .ta-row-protocol::before, .ta-controls .tab-buttons .tab-wrapper::before { text-decoration: underline dotted #ffffff55 1px; text-underline-offset: 3px; cursor: help; transition: opacity .14s ease; } .ta-row-entrants:hover::before, .ta-row-protocol:hover::before, .ta-controls .tab-buttons .tab-wrapper:hover::before { opacity: 0.95; } /* No frame around these. Gradio draws the checkbox *label* as a bordered button -- its theme literally calls it "the surrounding button of a checkbox" -- which on top of the checkbox itself read as a second control. Overriding the theme variables rather than the rules is what makes it stick: Gradio's own selectors carry the component's svelte hash, so a bare `border: none` loses on specificity. The padding stays, so the whole label is the click target rather than just the 12px box. */ .ta-controlrow .ta-catchip { position: relative; overflow: visible; --checkbox-label-background-fill: transparent; --checkbox-label-background-fill-hover: transparent; --checkbox-label-background-fill-selected: transparent; --checkbox-label-border-color: transparent; --checkbox-label-border-color-hover: transparent; --checkbox-label-border-color-selected: transparent; --checkbox-label-border-width: 0px; --checkbox-label-shadow: none; --checkbox-label-shadow-hover: none; --checkbox-label-shadow-active: none; } .ta-controlrow .ta-catchip label { display: flex; align-items: center; gap: 7px; padding: 4px 12px 4px 0 !important; border: none !important; border-radius: 0 !important; background: none !important; box-shadow: none !important; color: #cfd6ea; cursor: pointer; transition: color .14s ease; } .ta-controlrow .ta-catchip label:hover { color: #eef2ff; } .ta-controlrow .ta-catchip label span { cursor: pointer; } .ta-controlrow .ta-catchip input { cursor: pointer; } /* Checked reads as the accent fill the tab chips use for their selected state. */ /* Checked reads as brighter and heavier text; the box itself already carries the state. */ .ta-controlrow .ta-catchip label:has(input:checked) { color: #eef2ff; font-weight: 600; } /* The overview column matching a selector, washed orange across the whole cell. Layered as a background-image rather than a background-color: each cell carries its heat shade as an inline `background`, which encodes the value, and replacing it would throw that away. A translucent flat gradient sits on top instead, so the column reads as selected and still reads as hot or cold. `!important` is needed because the inline shorthand also resets background-image. */ .ta-overview th.ta-col-sel { border-top: 2px solid rgba(240, 163, 90, 0.95) !important; background-image: linear-gradient(rgba(240, 163, 90, 0.2), rgba(240, 163, 90, 0.2)) !important; color: #ffd9b0 !important; } .ta-overview td.ta-col-sel { background-image: linear-gradient(rgba(240, 163, 90, 0.26), rgba(240, 163, 90, 0.26)) !important; } /* --- Where the reader is actually looking ---------------------------------- Everything pinned to a corner of the screen positions against these two, never against the viewport directly. On a page that owns its scrollbar they are the viewport, so the rules below come out exactly as `position: fixed` would have placed them anyway. Embedded in a Hugging Face Space they are not: HF sizes the Space iframe to the app's whole content and lets the *outer* page scroll, so our viewport is the entire six-thousand-pixel document and a fixed element pins to the top of that instead of to the screen. `taTrackViewport` below recovers the visible band and keeps these two up to date. */ :root { --ta-vp-top: 0px; --ta-vp-h: 100vh; /* Where the COI chip starts: past the contents chip beside it. Replaced with the measured width once the page has laid out; the default is a sensible width for its label. */ --ta-coi-left: 132px; } /* Sticky summary of the current selection, revealed once the control card scrolls away (see main.taWatchControls). Bottom-centre rather than a corner: it is a status line for the whole page, and the top-right corner already belongs to the COI badge. */ .ta-selbar { position: fixed; left: 50%; top: calc(var(--ta-vp-h) - 18px); z-index: 60; display: flex; align-items: center; gap: 7px; max-width: min(94vw, 1100px); padding: 8px 14px; border: 1px solid #ffffff2e; border-radius: 999px; background: rgba(24, 24, 28, 0.94); box-shadow: 0 8px 26px #0009; color: #dfe5f5; font-family: inherit; cursor: pointer; overflow-x: auto; /* Hidden until the observer says the controls are off screen. `top` anchors the bar's own top edge, so it is pulled back up by its full height to sit on the line above. */ opacity: 0; pointer-events: none; transform: translate(-50%, calc(-100% + 12px)) translateY(var(--ta-vp-top)); /* The band offset rides in the same transform, so following the screen costs no layout; only opacity and the reveal slide are transitioned, or every scroll would ease. */ transition: opacity .16s ease; } .ta-selbar.ta-show { opacity: 1; pointer-events: auto; transform: translate(-50%, -100%) translateY(var(--ta-vp-top)); } .ta-selbar:hover { border-color: rgba(140, 168, 255, 0.8); } .ta-selbar-lead { flex: 0 0 auto; font-size: 0.66em; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.5; } .ta-selchip { flex: 0 0 auto; padding: 3px 9px; border-radius: 999px; background: rgba(158, 176, 208, 0.16); font-size: 0.8em; font-weight: 600; white-space: nowrap; } .ta-selbar-go { flex: 0 0 auto; margin-left: 3px; padding: 3px 10px; border-radius: 999px; background: rgba(110, 140, 245, 0.34); color: #eef2ff; font-size: 0.78em; font-weight: 700; white-space: nowrap; } /* Contents row under the subset blurb: which figures follow, in the order they will appear. The order changes with "I care about", so this doubles as a reminder of what that did. */ .ta-contents { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 2px 0 10px 0; } .ta-contents-lead { margin-right: 2px; font-size: 0.7em; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.55; } .ta-jumpchip { padding: 4px 11px !important; border: 1px solid #ffffff2e; border-radius: 999px; background: rgba(158, 176, 208, 0.14); color: #cbd5ef !important; font-size: 0.82em; font-weight: 600; text-decoration: none !important; transition: background .14s ease, border-color .14s ease; } .ta-jumpchip:hover { background: rgba(110, 140, 245, 0.3); border-color: rgba(140, 168, 255, 0.85); color: #eef2ff !important; } /* The models-vs-systems warning. It appears the moment a system joins the field, and it is the one thing on the page a reader must not skim past, so it is styled as an alert rather than a quote: red rule, red wash, and a heading at body-text weight instead of the muted grey the info panels use. */ /* Nothing inside draws its own frame or fill; the single box is the wrapper below. Applies to every descendant, not just the direct children: Gradio tints nested block elements, which showed through as pale bands across the warning. */ .ta-warnbox *, .ta-warnbox .prose { border: none !important; background: transparent !important; background-color: transparent !important; box-shadow: none !important; } .ta-warnbox > *, .ta-warnbox .prose { padding: 0 !important; } .ta-warnbox hr { display: none !important; } .ta-warnbox { margin: 6px 0 14px 0; padding: 14px 18px; /* The colour lives in the box rather than the text, but muted: a desaturated red-brown that sits close to the page background instead of a saturated fill. The left rule and the ⚠️ carry the urgency, so the fill only has to mark the block as separate. */ border: 1px solid rgba(170, 140, 140, 0.22); border-left: 5px solid #b05e62; border-radius: 10px; background: rgba(62, 54, 55, 0.5) !important; } .ta-warnbox h3 { margin: 0 0 8px 0 !important; color: #ffffff !important; font-size: 1.08em !important; font-weight: 700 !important; } .ta-warnbox p { margin: 0 0 8px 0 !important; color: #e8e2e2 !important; font-size: 0.95em; line-height: 1.5; } .ta-warnbox p:last-child { margin-bottom: 0 !important; } .ta-warnbox strong { color: #ffffff !important; } /* Models is locked on rather than unavailable, so it reads as the brightest thing in the row: full strength, and a default cursor rather than the not-allowed one the dimmed categories get. Both are non-interactive, and telling them apart at a glance is the point. */ .ta-controlrow .ta-catchip.ta-always label { color: #eef2ff; font-weight: 600; opacity: 1; cursor: default; } .ta-controlrow .ta-catchip.ta-always, .ta-controlrow .ta-catchip.ta-always * { cursor: default !important; } /* A category with no entrant yet. Dimmed and not-allowed rather than hidden, so the reader can see the axis exists and that a submission is what is missing. */ .ta-soon { opacity: 0.42; } .ta-soon, .ta-soon * { cursor: not-allowed !important; } .ta-soon label:hover { color: #cfd6ea; } /* The one-line consequence of each selection, so the effect is stated. */ .ta-controlnote { display: flex; flex-wrap: wrap; gap: 4px 26px; margin: 0 0 14px 2px; font-size: 0.85em; opacity: 0.72; } /* --- Figure panel with an interactive / static view switch ----------------- One card per figure: a header row (title + toggle) above two stacked views, exactly one of which is visible. Both are in the DOM so the toggle is instant; see main.taSwitchView and views._switchable_figure. */ .ta-figpanel { margin: 18px 0 22px 0; padding: 0; overflow: hidden; border: 1px solid #ffffff33; border-left: 3px solid rgba(110, 140, 245, 0.55); border-radius: 12px; background: #ffffff14; gap: 0 !important; } /* A titled header strip, full-bleed across the card: the earlier borderless version left the three figure blocks running into one another, so it was hard to see where one ended. The toggles sit right beside the title, where the eye already is — pushed to the far edge they read as decoration and get missed. */ .ta-figbar { display: flex; align-items: center; gap: 4px 12px; flex-wrap: wrap; margin: 0; padding: 10px 15px; background: #ffffff21; border-bottom: 1px solid #ffffff38; border-radius: 9px 9px 0 0; } .ta-figbar-title { font-weight: 650; font-size: 1.1em; letter-spacing: 0.01em; align-self: baseline; } /* The subset qualifier: present, but it should not compete with the name. */ .ta-figbar-sub { font-size: 0.85em; opacity: 0.6; font-weight: 400; align-self: baseline; } .ta-viewbtn { flex: 0 0 auto; cursor: pointer; /* Gradio's stylesheet gives every button but the last a 4px bottom margin, which under centre alignment lifts it 2px above its neighbours. */ margin: 0 !important; padding: 5px 14px; font-size: 0.85em; font-weight: 600; color: #cdd7ff; background: rgba(110, 140, 245, 0.18); border: 1px solid rgba(110, 140, 245, 0.55); border-radius: 999px; transition: background .15s ease, border-color .15s ease; } .ta-viewbtn:hover { background: rgba(110, 140, 245, 0.34); border-color: rgba(110, 140, 245, 0.95); } /* The way into the controls, so it carries more weight than its neighbours. */ .ta-editbtn { font-size: 0.95em; font-weight: 700; padding: 8px 18px; color: #ffffff; background: rgba(110, 140, 245, 0.9); border-color: rgba(110, 140, 245, 1); } .ta-editbtn:hover { background: rgba(130, 158, 255, 1); border-color: rgba(150, 175, 255, 1); } /* The chart / image itself, inset from the card edge. */ .ta-figview { padding: 0 13px 13px 13px; } /* The per-dataset browser fills its panel: it is an application, not a figure, so the figure inset -- and the padding Gradio puts on the HTML block inside it -- is dead width. */ .ta-figview-flush { padding: 0 3px 7px 3px !important; } .ta-figview-flush .html-container { padding: 0 !important; } /* Download controls: pinned to the right of the header and deliberately louder than the view toggles, since exporting the figure is what paper view is for. */ .ta-exportgroup { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; } .ta-exportgroup[hidden] { display: none !important; } .ta-exportlabel { font-size: 0.82em; font-weight: 700; letter-spacing: 0.04em; color: #7ee0b8; } .ta-exportbtn { color: #063; background: #7ee0b8; border-color: #7ee0b8; } .ta-exportbtn:hover { background: #a6efcd; border-color: #a6efcd; } .ta-hidden { display: none !important; } /* A Gradio button that exists only to carry a click to the server; the control the reader sees is plain HTML inside a panel's title bar (see views.make_per_dataset_block). Moved out of sight rather than `display: none`, which would take it out of the layout Gradio measures. */ .ta-offscreen-btn { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; min-width: 0 !important; opacity: 0; pointer-events: none; } /* The static figure spans the panel and rescales with it — Gradio's default image box would letterbox the very wide bar figures inside a fixed height. */ .ta-figpanel .image-container, .ta-figpanel .image-frame { width: 100% !important; height: auto !important; max-height: none !important; } .ta-figpanel .image-frame img { width: 100% !important; height: auto !important; max-height: none !important; object-fit: contain; } /* Row of external links/buttons (e.g. on a linked-leaderboard page). Rendered as real anchors so they open in a new tab instead of navigating inside the embedded Hugging Face Space iframe. */ .link-row { display: flex; margin: 12px 0; gap: 12px; align-items: center; flex-wrap: wrap; } .ta-link-btn { display: inline-block; padding: 10px 20px !important; border-radius: 8px; font-weight: 600; text-decoration: none; border: 1px solid transparent; transition: background .15s ease, border-color .15s ease; } .ta-link-btn.primary { background: rgba(110, 140, 245, 0.85); border-color: rgba(110, 140, 245, 1); color: #ffffff; } .ta-link-btn.primary:hover { background: rgba(110, 140, 245, 1); } .ta-link-btn.secondary { background: #ffffff14; border-color: #ffffff3d; color: #e6ebff; } .ta-link-btn.secondary:hover { background: #ffffff24; border-color: #ffffff5c; } /* Compact "Metric:" selector panel above the overview table. */ .metric-select { margin: -18px 0 0 0; padding: 6px 14px; gap: 12px; align-items: center; background: #ffffff0a; border: 1px solid #ffffff26; border-radius: 8px; } .metric-select::before { content: "📈 Aggregation:"; font-size: 0.85em; font-weight: 600; opacity: 0.7; white-space: nowrap; } /* Beside the metric dropdown, and on its own line once there is no room for both. Without a floor it shrank instead of wrapping: on a phone the dropdown's 200px left this 84px, and a one-line note became a 205px-tall ribbon one or two words wide. */ .metric-tldr { flex: 1 1 260px; min-width: 260px; font-size: 0.85em; opacity: 0.75; font-style: italic; } .metric-tldr p { margin: 0; } @media (max-width: 640px) { .metric-tldr { min-width: 100%; } } /* Pull the overview (type legend + table) up tight under the aggregation box. */ .ta-overview-block { margin-top: -8px; } /* "Jump to detailed results" pill link. */ .ta-jump { display: inline-block; margin: 0; font-size: 0.9em; padding: 4px 14px !important; border: 1px solid #ffffff2e; border-radius: 999px; text-decoration: none; opacity: 0.85; } .ta-jump:hover { opacity: 1; border-color: #ffffff5c; } /* Section header: title (and optional jump link) on one row, summary directly below. */ .ta-section-head { margin: 10px 0 6px 0; } .ta-section-head h2 { margin: 0; } .ta-section-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; } .ta-section-sub { margin: 3px 0 0 0; font-size: 0.95em; opacity: 0.8; line-height: 1.4; } /* Info topic pills + the single reveal panel (replaces the stacked accordions). */ .info-pills { gap: 8px; flex-wrap: wrap; justify-content: center; margin: -6px 0 2px 0; } .info-pills button { border-radius: 999px !important; flex: 0 0 auto !important; font-weight: 600 !important; font-size: 1em !important; padding: 8px 20px !important; color: #cdd7ff !important; background: rgba(110, 140, 245, 0.18) !important; border: 1px solid rgba(110, 140, 245, 0.55) !important; } .info-pills button:hover { background: rgba(110, 140, 245, 0.32) !important; border-color: rgba(110, 140, 245, 0.9) !important; } .info-pills button.primary { background: rgba(110, 140, 245, 0.85) !important; border-color: rgba(110, 140, 245, 1) !important; color: #ffffff !important; } .info-panel { margin: 6px 0 12px 0; padding: 4px 18px; border: 1px solid #ffffff1f; border-radius: 12px; background: #ffffff08; } /* --- The full leaderboard table, as one card ------------------------------- Title strip, then the filters, then the column key, then the table itself. The controls and the key used to sit outside the table (the key in its own floating panel, the filters inside the old third-party widget); keeping them in the same bordered card is what makes them read as belonging to it. */ .ta-lb { margin: 16px 0 10px 0; padding: 0; overflow: visible; border: 1px solid #ffffff33; border-left: 3px solid rgba(110, 140, 245, 0.55); border-radius: 12px; background: #ffffff10; gap: 0 !important; } .ta-lb-bar { display: flex; align-items: baseline; flex-wrap: wrap; gap: 3px 12px; padding: 11px 16px; background: #ffffff21; border-bottom: 1px solid #ffffff38; border-radius: 9px 9px 0 0; } .ta-lb-title { font-weight: 650; font-size: 1.25em; letter-spacing: 0.01em; } .ta-lb-sub { font-size: 0.85em; opacity: 0.6; } /* One padded band for the filters, so four controls fit on a line without looking cramped. Nothing here may set pointer-events, position or z-index: these are live Gradio inputs and must stay clickable. */ .ta-lb-controls { padding: 12px 16px 2px 16px; gap: 18px; align-items: flex-start; } .ta-lb .ta-lb-imputed { padding: 0 16px 6px 16px; } .ta-lb .ta-legend { padding: 4px 16px 0 16px; } .ta-lb .ta-scroll { margin: 4px 16px 0 16px; max-height: 720px; } .ta-lb .ta-cap { padding: 0 16px 10px 16px; } /* The line above the per-dataset browser, and the same line standing in for it while the section is collapsed. */ .ta-pd-teaser { font-size: 0.92em; opacity: 0.78; margin: 2px 2px 10px; line-height: 1.5; } /* --- Chip selectors, matching the plot explorers' edit view ------------------ The same shape, dot and pressed treatment as the method chips in the generated *_explorer.html: a pill with a family-colored dot, no fill until selected, then a tinted background and a matching border. Variables are the explorers' own dark-theme values (the site forces dark). These are real Gradio inputs underneath. The native box is visually hidden but left in the layout and in the label, so a click on the chip still reaches it; nothing here sets pointer-events, position or z-index on anything clickable. Both `:has(input:checked)` and Gradio's own `.selected` drive the pressed look, so a change to either survives. */ .ta-chips, .ta-btns, .ta-famchip { --line: #2e2e33; --muted: #9b9a92; --pt-muted: #55555c; --chip-bg: #232327; --fam: #9b9a92; } .ta-btns-imputed { --fam: #e6c14d; } .ta-chips label { display: inline-flex !important; align-items: center; gap: 6px; /* Spacing lives on the chips themselves rather than as a gap on Gradio's internal container, so this does not depend on Gradio's DOM. */ margin: 0 5px 5px 0 !important; padding: 5px 11px 5px 9px !important; font: 500 12.5px/1 system-ui, sans-serif !important; color: #f0efea; background: none !important; border: 1px solid var(--line) !important; border-radius: 999px !important; box-shadow: none !important; cursor: pointer; transition: border-color 120ms ease, background-color 120ms ease; } .ta-chips label::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--pt-muted); flex: none; } .ta-chips label:hover { border-color: var(--muted) !important; } .ta-chips label:has(input:checked), .ta-chips label.selected { border-color: var(--fam) !important; background: color-mix(in srgb, var(--fam) 13%, transparent) !important; font-weight: 650 !important; } .ta-chips label:has(input:checked)::before, .ta-chips label.selected::before { background: var(--fam); } /* Visually hidden, still hit-testable through its label. */ .ta-chips label input[type="checkbox"], .ta-chips label input[type="radio"] { width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important; border: 0 !important; opacity: 0; flex: none; } /* The chip rows carry their own label above; keep Gradio's block label small. */ .ta-chips > .block-label, .ta-chips span[data-testid="block-info"] { font-size: 0.85em; } /* The family chip that heads each row of model chips: the explorers' .famchip — uppercase, dashed until selected, then solid in the family's colour. */ .ta-famchip label { display: inline-flex !important; align-items: center; gap: 6px; margin: 0 !important; padding: 5px 11px !important; font: 650 10.5px/1.3 system-ui, sans-serif !important; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); background: var(--chip-bg) !important; border: 1px dashed var(--line) !important; border-radius: 999px !important; box-shadow: none !important; cursor: pointer; white-space: nowrap; } .ta-famchip label::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--fam); flex: none; } .ta-famchip label:hover { border-color: var(--fam) !important; color: #f0efea; } .ta-famchip label:has(input:checked), .ta-famchip label.selected { border: 1px solid var(--fam) !important; background: color-mix(in srgb, var(--fam) 13%, transparent) !important; color: #f0efea; } .ta-famchip label input { width: 0 !important; height: 0 !important; margin: 0 !important; opacity: 0; } /* Family chip left, its models filling the rest of the row. */ .ta-chiprow { gap: 10px; align-items: flex-start; margin: 0 !important; padding: 0 16px; } /* --- Button-style toggles, as in the Leaderboard Overview explorer ----------- That explorer uses buttons rather than chips for the variants ("since they filter the series rather than the rows"), each carrying its variant colour from --var-*; see constants.variant_color. Same shape here. */ .ta-btns label { display: inline-flex !important; align-items: center; margin: 0 5px 5px 0 !important; padding: 6px 11px !important; font: 600 12.5px/1 system-ui, sans-serif !important; color: #f0efea; background: var(--chip-bg) !important; border: 1px solid var(--line) !important; border-radius: 7px !important; box-shadow: none !important; cursor: pointer; white-space: nowrap; transition: border-color 120ms ease, background-color 120ms ease; } .ta-btns label:hover { border-color: var(--muted) !important; } .ta-btns label:has(input:checked), .ta-btns label.selected { border-color: var(--fam) !important; background: color-mix(in srgb, var(--fam) 20%, #232327) !important; } .ta-btns label input { width: 0 !important; height: 0 !important; margin: 0 !important; opacity: 0; } /* The CSV export button sits at the right end of the card's title strip. */ .ta-csvbtn { margin-left: auto !important; } /* Sortable headers. The overview's info headers use a help cursor; here the same header is also the sort control, so pointer wins and the dotted underline is what still signals "hover me for a definition". */ .ta-lbtable thead th.ta-th-sort { cursor: pointer; user-select: none; white-space: nowrap; } .ta-lbtable thead th.ta-th-sort:hover { background: #262632; } .ta-lbtable thead th.ta-th-sort::after { content: "↕"; font-size: 0.72em; opacity: 0.28; margin-left: 5px; } .ta-lbtable thead th[aria-sort="ascending"]::after { content: "▲"; opacity: 0.85; } .ta-lbtable thead th[aria-sort="descending"]::after { content: "▼"; opacity: 0.85; } .ta-lbtable th.ta-th-left { text-align: left; } /* Two-emoji type symbols (🧠⚡, 🧠🔁) must never break across lines, in the table cell or in the legend chip that explains it. */ .ta-pill { white-space: nowrap; } .ta-lbtable td.ta-type-cell { white-space: nowrap; width: 1%; } /* The Elo interval rides along with the value but stays visibly secondary. */ .ta-ci { opacity: 0.5; font-weight: 400; font-size: 0.82em; } .ta-ci-head { opacity: 0.55; font-weight: 400; font-size: 0.82em; } /* Hero stat cards shown above the info boxes (emoji on the left of the text, compact). */ .ta-hero { display: flex; flex-wrap: wrap; gap: 10px; margin: -8px 0 0 0; } .ta-hero .ta-card { flex: 1 1 210px; min-width: 210px; display: flex; align-items: center; gap: 11px; padding: 9px 13px; border: 1px solid #ffffff1f; border-radius: 10px; background: linear-gradient(135deg, #ffffff12, #ffffff05); text-align: left; transition: transform .15s ease, border-color .15s ease; } .ta-hero .ta-card:hover { transform: translateY(-2px); border-color: #ffffff40; } .ta-hero .ta-card-ico { font-size: 1.5em; line-height: 1; flex: 0 0 auto; } .ta-hero .ta-card-body { min-width: 0; } .ta-hero .ta-card-num { font-size: 1.1em; font-weight: 700; line-height: 1.2; } .ta-hero .ta-card-lbl { font-size: 0.8em; opacity: 0.75; margin-top: 1px; line-height: 1.3; } .ta-hero .ta-card-lbl a { color: inherit; } /* "Your Benchmark?" invite page: two "path" cards side by side. */ .ta-paths { display: flex; flex-wrap: wrap; gap: 16px; margin: 18px 0 6px 0; } .ta-path { flex: 1 1 320px; min-width: 280px; padding: 18px 22px; border: 1px solid rgba(110, 140, 245, 0.45); border-radius: 12px; background: linear-gradient(135deg, rgba(110, 140, 245, 0.16), rgba(110, 140, 245, 0.04)); transition: transform .15s ease, border-color .15s ease; } .ta-path:hover { transform: translateY(-2px); border-color: rgba(110, 140, 245, 0.85); } .ta-path-ico { font-size: 1.9em; line-height: 1; } .ta-path h3 { margin: 8px 0 8px 0; font-size: 1.18em; } .ta-path p { margin: 0; opacity: 0.88; line-height: 1.55; } /* Soft "independent benchmarks" note on the invite page (mirrors the RamanBench callout). */ .ta-invite-note { margin: 14px 0 4px 0; padding: 11px 16px; border: 1px solid rgba(110, 140, 245, 0.4); border-left: 4px solid rgba(110, 140, 245, 0.85); border-radius: 8px; background: rgba(110, 140, 245, 0.08); font-size: 0.95em; line-height: 1.5; opacity: 0.95; } /* --- Conflict-of-interest corner hint + CSS-only popup --------------------- A small pill pinned to the top-right corner; clicking it reveals a modal. Opening and closing it is the checkbox hack, so that much needs no JS; where the corner *is* comes from `--ta-vp-top` / `--ta-vp-h` (see the top of this stylesheet). */ /* Jump menu, same CSS-only pattern as the COI badge below and pinned beside it. A menu rather than a modal: every entry is one click and the page keeps its place until you pick one. */ /* Positioned with a transform rather than by moving `top`: the band is republished on every scroll, and a transform is composited while a `top` change costs a layout pass, which is what made the chips visibly trail the page. */ .toc-widget { position: fixed; top: 12px; left: 14px; z-index: 70; transform: translateY(var(--ta-vp-top)); will-change: transform; } .toc-toggle { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .toc-badge { display: inline-block; padding: 5px 12px; border: 1px solid rgba(110, 140, 245, 0.55); border-radius: 999px; background: rgba(110, 140, 245, 0.18); color: #cdd7ff; font-size: 0.82em; font-weight: 600; cursor: pointer; user-select: none; } .toc-badge:hover { background: rgba(110, 140, 245, 0.34); border-color: rgba(110, 140, 245, 0.95); } .toc-menu { display: none; position: absolute; top: calc(100% + 6px); left: 0; min-width: 268px; padding: 6px; border: 1px solid #ffffff2e; border-radius: 10px; background: rgba(24, 24, 28, 0.97); box-shadow: 0 10px 30px #000a; } .toc-toggle:checked ~ .toc-menu { display: block; } /* Picking an entry closes the menu: while it is open this label covers the page, so the click that lands on a link also reaches the label underneath and unchecks the toggle. CSS-only, so it still works inside the Space iframe. */ .toc-toggle:checked ~ .toc-backdrop { display: block; } /* Sized in multiples of the viewport rather than pinned to its edges: the transform on `.toc-widget` makes that element the containing block for anything fixed inside it, so `inset: 0` would shrink this to the chip and stop closing the menu. */ .toc-backdrop { display: none; position: fixed; top: -150vh; left: -150vw; width: 400vw; height: 400vh; z-index: -1; } .toc-menu a { display: block; padding: 7px 10px !important; border-radius: 7px; color: #dfe5f5 !important; font-size: 0.86em; font-weight: 600; text-align: left !important; text-decoration: none !important; } .toc-menu a:hover { background: rgba(110, 140, 245, 0.28); } /* Anchors sit under the fixed corner chips; scroll them clear. The figure panels are targets too (the "Below:" row links to each one), and they are addressed by prefix because their ids carry the subset they belong to. */ #ta-controls-anchor, #ta-overview-section, #lb-detailed, #ta-perdataset-section, #ta-appendix-section, #ta-agentic-section, #ta-version-section, [id^="ta-fig-"] { scroll-margin-top: 58px; } /* Anchor navigation is the only jump that works inside the Space (a scripted scroll cannot move a cross-origin parent), so the easing has to come from CSS rather than from `scrollIntoView`. */ html { scroll-behavior: smooth; } /* Pinned to the same corner as the badge that toggles it, not left wherever in the document it happens to sit. Clicking the badge focuses this checkbox, and a browser scrolls a focused element into view: parked near the top of the page, opening the popup threw the reader back to the top of the leaderboard. */ .coi-toggle { position: fixed; top: 10px; left: var(--ta-coi-left); transform: translateY(var(--ta-vp-top)); opacity: 0; width: 0; height: 0; pointer-events: none; } .coi-badge { position: fixed; top: 10px; /* Beside the contents chip, not in the opposite corner. `--ta-coi-left` is set from the measured width of that chip (see `taPlaceChips`), since its label is not fixed. */ left: var(--ta-coi-left); transform: translateY(var(--ta-vp-top)); will-change: transform; z-index: 1000; display: inline-flex; align-items: center; gap: 6px; cursor: pointer; padding: 6px 13px; font-size: 0.85em; font-weight: 600; color: #cdd7ff; background: rgba(110, 140, 245, 0.2); border: 1px solid rgba(110, 140, 245, 0.6); border-radius: 999px; user-select: none; transition: background .15s ease, border-color .15s ease; } .coi-badge:hover { background: rgba(110, 140, 245, 0.34); border-color: rgba(110, 140, 245, 0.95); } /* Two chips and a title share a 390px screen; give the chips less of it. Placed after both badge rules rather than with the rest of the phone layout, which sits earlier in this sheet and would lose to them on source order. */ @media (max-width: 640px) { .toc-badge, .coi-badge { padding: 4px 9px; font-size: 0.74em; } } .coi-overlay { display: none; position: fixed; top: var(--ta-vp-top); left: 0; right: 0; height: var(--ta-vp-h); z-index: 1001; align-items: flex-start; justify-content: center; padding: 32px 20px; overflow-y: auto; background: rgba(0, 0, 0, 0.66); } .coi-toggle:checked ~ .coi-overlay { display: flex; } .coi-backdrop { position: absolute; inset: 0; cursor: default; } .coi-modal { position: relative; width: 100%; max-width: min(1040px, 94vw); margin: 0 auto; /* Fixed base font (in rem) so the popup does not inherit Gradio's smaller in-app font; all sizes below scale from this. */ font-size: 1.06rem; padding: 34px 44px 38px; border-radius: 16px; background: #1b1b24; border: 1px solid rgba(110, 140, 245, 0.45); box-shadow: 0 18px 55px rgba(0, 0, 0, 0.55); color: #eef1ff; line-height: 1.7; } .coi-modal h2 { margin: 0 0 6px 0; font-size: 1.85em; line-height: 1.25; } .coi-modal h3 { margin: 26px 0 8px 0; font-size: 1.28em; color: #cdd7ff; } .coi-modal p, .coi-modal li { font-size: 1em; opacity: 0.96; } .coi-modal ul { margin: 8px 0; padding-left: 24px; } .coi-modal li { margin: 7px 0; } .coi-modal a { color: #9db4ff; } .coi-lead { font-size: 1.18em !important; opacity: 1 !important; line-height: 1.55; } .coi-tldr { margin: 16px 0 4px 0; padding: 16px 20px; border: 1px solid rgba(110, 140, 245, 0.4); border-left: 4px solid rgba(110, 140, 245, 0.85); border-radius: 8px; background: rgba(110, 140, 245, 0.1); font-size: 1.05em; line-height: 1.6; } .coi-x { position: absolute; top: 14px; right: 20px; font-size: 2em; line-height: 1; cursor: pointer; opacity: 0.55; user-select: none; } .coi-x:hover { opacity: 1; } .coi-cta { display: block; width: fit-content; margin: 28px auto 0; text-align: center; padding: 12px 24px !important; border-radius: 8px; font-weight: 600; font-size: 1.02em; text-decoration: none; color: #ffffff !important; background: rgba(110, 140, 245, 0.85); border: 1px solid rgba(110, 140, 245, 1); } .coi-cta:hover { background: rgba(110, 140, 245, 1); } /* On wider screens, give the prose a touch more size still. */ @media (min-width: 900px) { .coi-modal { font-size: 1.12rem; } } /* BeyondArena "What do the subsets mean?" expander: larger label + blue highlight box. */ .beyond-subsets-accordion { border: 1px solid #5aa9e6 !important; border-radius: 10px !important; background: rgba(90, 169, 230, 0.08) !important; } .beyond-subsets-accordion .label-wrap, .beyond-subsets-accordion .label-wrap span, .beyond-subsets-accordion > button { font-size: 1.15rem !important; font-weight: 600 !important; color: #8cc4f0 !important; } """ # Gradio 6 ships this inside `window.gradio_config` and the client appends it to # once the config is read — early, but *after* the bundle has picked a # theme, which is why the block below overrides that choice rather than pre-empting # it. (`THEME` in main() handles the frame before the bundle runs.) HEAD = """ """ # The one frame `HEAD` cannot reach. Gradio's served `index.html` paints a splash # from the theme's *light* body colours and only swaps to the dark pair when the # viewer's OS asks for dark — so a light-mode visitor got a white flash before the # bundle (and the dark-forcing block in `HEAD`) had loaded at all. Point the light # pair at the dark values and that first frame is dark for everyone. Nothing else # reads them: the app always renders under `.dark`, which has its own pair. # # Written out rather than referenced: `set()` rejects a `*…_dark` value, since it # normally resolves the dark half of a pair by itself. These two are what # `gr.themes.Default()` resolves `body_background_fill_dark` / `body_text_color_dark` # to (`neutral_950` / `neutral_100`); the background also appears in `HEAD`'s