"""THOX brand v2 Gradio theme -- the single source for every Space in this repo. CANONICAL COPY. `ci/test_theme_parity.py` asserts every Space's copy is byte-identical to this file. Edit here, then run `python build.py` (which re-copies it) -- editing a Space's copy directly will fail CI. WHY THIS FILE EXISTS -------------------- Seven Spaces each carried their own inline theme. Two defects were present in every one of them, measured on the live fleet: 1. The stylesheet forced `.gradio-container { background: #09090B !important }` while Gradio still rendered its LIGHT palette. Loading `?__theme=light` produced black body text on the forced near-black canvas: #000000 on #09090B = 1.06:1 Invisible. Never pin one theme's colour; let the theme drive it. 2. Buttons and links were stock Gradio blue (`--color-accent` #3B82F6, `--link-text-color` #2563EB), so nothing in the fleet's UI was actually THOX. Fixing that in seven places would have drifted. It lives here instead. CONTRAST -- from ttracx/thox-design-system (standards/brand-v2.md, ADR-0001) --------------------------------------------------------------------------- The reflex pairing is wrong and must not be "fixed" back: #FFFFFF on #05A451 = 3.26:1 FAILS WCAG AA #000000 on #05A451 = 6.44:1 PASSES <- primary button, both themes Light Dark #03763B on #FFFFFF 5.74 #45e887 on #09090B 12.45 links #52525B on #FFFFFF 7.73 #A1A1AA on #09090B 7.76 subdued text #FFFFFF on #03763B 5.74 #000000 on #05A451 6.44 primary hover Plain #05A451 is only 3.26:1 on white, so light-surface text uses brand.deep (#03763B). Gradio's own `--body-text-color-subdued` default (#BBBBC2) is about 1.9:1 on white, so it is pinned in both modes here. #10B981 / #34D399 are DEPRECATED v1 emeralds. Purple #A855F7 is MagStack-only and neon #00FF88 is device-illumination-only -- neither belongs in UI chrome. """ from __future__ import annotations import gradio as gr THOX_GREEN = "#05A451" # brand.primary THOX_ACCENT = "#45e887" # accent on dark THOX_DEEP = "#03763B" # brand.deep -- accessible green on light surfaces THOX_FOCUS = "#37C77A" # brand.light -- 9.11:1 on the dark canvas THOX_HUE = gr.themes.Color( c50="#E6F7EE", c100="#C2EBD6", c200="#8FDCB6", c300="#5CCB95", c400=THOX_FOCUS, c500=THOX_GREEN, c600="#048A44", c700=THOX_DEEP, c800="#026030", c900="#064E2E", c950="#04331E", ) THOX_THEME = gr.themes.Base( primary_hue=THOX_HUE, neutral_hue=gr.themes.colors.zinc, ).set( # Primary action: brand green with BLACK ink in both themes (6.44:1). button_primary_background_fill=THOX_GREEN, button_primary_background_fill_dark=THOX_GREEN, button_primary_text_color="#000000", button_primary_text_color_dark="#000000", button_primary_background_fill_hover=THOX_DEEP, button_primary_background_fill_hover_dark=THOX_ACCENT, button_primary_text_color_hover="#FFFFFF", # on #03763B = 5.74:1 button_primary_text_color_hover_dark="#000000", # Plain green is only 3.26:1 on white, so light links use brand.deep. link_text_color=THOX_DEEP, link_text_color_dark=THOX_ACCENT, link_text_color_hover="#024F27", link_text_color_hover_dark=THOX_GREEN, # Gradio's default subdued grey fails AA on white; pin both modes. body_text_color_subdued="#52525B", # 7.73:1 on white body_text_color_subdued_dark="#A1A1AA", # 7.76:1 on #09090B background_fill_primary_dark="#09090B", background_fill_secondary_dark="#18181B", border_color_primary_dark="#3F3F46", ) # Shared chrome. Colour resolves through a Gradio variable or a per-theme # override, so it follows the active theme instead of pinning one. # `body.dark` is how Gradio 5 marks dark mode -- not html.dark, not data-theme. THOX_CSS = f""" :root {{ --thox-green: {THOX_GREEN}; --thox-accent: {THOX_ACCENT}; --thox-deep: {THOX_DEEP}; --thox-brand-ink: var(--thox-deep); }} .dark, body.dark {{ --thox-brand-ink: var(--thox-accent); }} #thox-header {{ border-left: 3px solid var(--thox-green); padding: 0.6rem 0 0.6rem 0.9rem; margin-bottom: 0.5rem; }} #thox-header h1 {{ color: var(--thox-brand-ink); font-size: 1.15rem; margin: 0; letter-spacing: .02em; }} #thox-header p {{ color: var(--body-text-color-subdued); font-size: .85rem; margin: .25rem 0 0; }} #thox-header code {{ color: var(--thox-brand-ink); }} /* Amber is semantic, so it is pinned per theme rather than taken from a Gradio variable -- the dark-mode #FBBF24 is only 1.7:1 on white. */ #thox-caveat {{ border-left: 3px solid #B45309; background: rgba(180,83,9,.07); padding: .55rem .8rem; margin: .4rem 0 .6rem; border-radius: 4px; color: #92400E; font-size: .82rem; line-height: 1.45; }} .dark #thox-caveat, body.dark #thox-caveat {{ border-left-color: #F59E0B; background: rgba(245,158,11,.08); color: #FBBF24; }} :is(button, a, input, textarea, select):focus-visible {{ outline: 2px solid var(--thox-brand-ink); outline-offset: 2px; }} ::selection {{ background: var(--thox-green); color: #000000; }} @media (prefers-reduced-motion: reduce) {{ *, *::before, *::after {{ animation-duration: .01ms !important; transition-duration: .01ms !important; }} }} """