wavereader / ui /theme.py
lucashudsn's picture
finished!!
c5672b8
Raw History Blame Contribute Delete
18.8 kB
"""Lo-fi wave~reader theme (page-blue bg, ink-blue IBM Plex Mono).
One CSS string for the single-page app: instrument-panel blocks on the
#eef6fd page, pill chips (engines / days / badges / skills), left-set
type everywhere. Identity note: the mono face changed from Courier New
to IBM Plex Mono (self-hosted font via Google Fonts, Courier fallback
when offline) — same ink, more designed.
"""
from __future__ import annotations
APP_CSS = """
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');
/* wave~reader lo-fi theme: page blue everywhere, ink-blue mono type */
.gradio-container, .gradio-container-4x, main, body {
background: #eef6fd !important;
color: #0b2c5c !important;
font-family: 'IBM Plex Mono', 'Courier New', Courier, monospace !important;
}
.gradio-container h1, .gradio-container h2, .gradio-container h3,
.gradio-container p, .gradio-container span, .gradio-container label,
.gradio-container .markdown, .gradio-container .prose {
color: #0b2c5c !important;
font-family: 'IBM Plex Mono', 'Courier New', Courier, monospace !important;
text-align: left !important;
}
/* markdown blocks: never justify, no oversized empty boxes */
.gradio-container .markdown { text-align: left !important; min-height: 0 !important; }
.gradio-container p { margin: 2px 0 !important; }
/* Gradio paints em/strong/li/code near-white by default — always inherit the ink */
.gradio-container em, .gradio-container i,
.gradio-container strong, .gradio-container b,
.gradio-container li, .gradio-container ul, .gradio-container ol,
.gradio-container code {
color: inherit !important;
}
.hero-title {
font-size: 2.1em !important;
font-weight: 700 !important;
letter-spacing: 1px;
text-transform: lowercase;
margin-bottom: 0 !important;
}
.hero-sub { font-size: 0.78em !important; margin: 0 !important; opacity: 0.75; }
/* hero band: title + toggle on one line, engine strip below, rule under */
.hero-band { padding: 2px 0 6px !important; border-bottom: 2px solid #c9dff2; margin-bottom: 8px; }
.hero-row { align-items: center !important; flex-wrap: nowrap !important; overflow: visible !important; }
.hero-right { display: flex !important; justify-content: flex-end; align-items: center; }
button, select, input, textarea {
font-family: 'IBM Plex Mono', 'Courier New', Courier, monospace !important;
}
/* primary (orange) buttons -> ink blue */
.gradio-container {
--button-primary-background-fill: #0b2c5c !important;
--button-primary-background-fill-hover: #13407e !important;
--button-primary-text-color: #ffffff !important;
--button-primary-border-color: #0b2c5c !important;
}
.gradio-container button.primary,
.gradio-container .gr-button-primary,
button.primary, button.lg.primary {
background: #0b2c5c !important;
border-color: #0b2c5c !important;
color: #ffffff !important;
}
.gradio-container button.primary:hover,
.gradio-container .gr-button-primary:hover,
button.primary:hover, button.lg.primary:hover {
background: #13407e !important;
border-color: #13407e !important;
color: #ffffff !important;
}
/* blocks match the page bg — padding + ink borders define them */
.gradio-container {
--body-text-color: #0b2c5c !important;
--background-fill-primary: #eef6fd !important;
--background-fill-secondary: #eef6fd !important;
--block-background-fill: #eef6fd !important;
--block-border-color: #0b2c5c !important;
--block-label-background-fill: #eef6fd !important;
--block-label-text-color: #0b2c5c !important;
--input-background-fill: #ffffff !important;
--input-border-color: #0b2c5c !important;
--input-placeholder-color: #4a6fa5 !important;
--code-background-fill: #d6e9f8 !important;
--table-background-fill: #eef6fd !important;
--table-border-color: #0b2c5c !important;
--table-odd-background-fill: #eef6fd !important;
--table-even-background-fill: #eef6fd !important;
--chatbot-code-background-fill: #eef6fd !important;
--button-secondary-background-fill: #eef6fd !important;
--button-secondary-background-fill-hover: #d6e9f8 !important;
--button-secondary-text-color: #0b2c5c !important;
--button-secondary-border-color: #0b2c5c !important;
--button-cancel-background-fill: #eef6fd !important;
--button-cancel-text-color: #0b2c5c !important;
--button-cancel-border-color: #0b2c5c !important;
--block-border-width: 2px !important;
--block-shadow: none !important;
--block-title-text-size: 14px !important;
--checkbox-background-color-selected: #0b2c5c !important;
--checkbox-border-color-selected: #0b2c5c !important;
--checkbox-label-background-fill: #ffffff !important;
--checkbox-label-background-fill-selected: #0b2c5c !important;
--checkbox-label-border-color: #0b2c5c !important;
--checkbox-label-border-color-selected: #0b2c5c !important;
--checkbox-label-text-color: #0b2c5c !important;
--checkbox-label-text-color-selected: #ffffff !important;
--slider-color: #0b2c5c !important;
}
.gradio-container .gr-box, .gradio-container .gr-panel,
.gradio-container .block, .gradio-container .form,
.gradio-container .gr-group, .gradio-container .gr-block {
background: #eef6fd !important;
border-color: #0b2c5c !important;
border-width: 2px !important;
border-radius: 12px !important;
padding: 10px !important;
gap: 6px !important;
}
.gradio-container input, .gradio-container textarea,
.gradio-container select, .gradio-container .gr-textbox,
.gradio-container .gr-dropdown, .gradio-container .gr-radio,
.gradio-container .gr-checkbox, .gradio-container .gr-dataframe {
background: #ffffff !important;
border-color: #0b2c5c !important;
color: #0b2c5c !important;
}
/* dropdown value + its open option list: legible 14px type matching the
block labels. Gradio pins the open list's width to the field via an
inline style — widen it to fit its longest option so names like
"New South Wales" stay on one line instead of wrapping mid-word */
.gradio-container .secondary-wrap input,
ul.options .item {
font-size: 14px !important;
line-height: 1.4 !important;
}
ul.options {
width: fit-content !important;
min-width: fit-content !important;
max-width: min(90vw, 480px) !important;
}
ul.options .item {
width: auto !important; /* Gradio inline-pins each row to the field width */
white-space: nowrap !important;
word-break: normal !important;
}
.gradio-container table, .gradio-container thead,
.gradio-container tbody, .gradio-container th,
.gradio-container td, .gradio-container .table-wrap {
background: #eef6fd !important;
color: #0b2c5c !important;
}
.gradio-container tbody tr:nth-child(even) { background: #eef6fd !important; }
.gradio-container .message, .gradio-container .bubble,
.gradio-container .message-wrap {
background: #ffffff !important;
border-color: #0b2c5c !important;
color: #0b2c5c !important;
}
/* radio pill row (mode toggle): tight inline options */
.gradio-container .gr-radio { gap: 6px !important; }
.gradio-container .gr-radio label {
border: 2px solid #0b2c5c !important;
border-radius: 999px !important;
background: #ffffff !important;
color: #0b2c5c !important;
padding: 3px 10px !important;
font-size: 0.82em !important;
}
.gradio-container .gr-radio label.selected,
.gradio-container label:has(input[type="radio"]:checked),
.gradio-container label:has(input[type="checkbox"]:checked) {
background: #0b2c5c !important;
color: #ffffff !important;
}
.gradio-container .gr-radio label.selected span,
.gradio-container label:has(input:checked) span { color: #ffffff !important; }
/* accordions read as sections of one instrument */
.gradio-container details, .gradio-container .accordion-wrap, .gradio-container summary {
border-color: #0b2c5c !important;
color: #0b2c5c !important;
}
.gradio-container summary, .gradio-container .label-wrap span {
font-family: 'IBM Plex Mono', 'Courier New', Courier, monospace !important;
font-weight: 700 !important;
text-transform: lowercase !important;
letter-spacing: 0.5px !important;
color: #0b2c5c !important;
}
/* engine strip: lo-fi chips naming every engine, faint trailing note */
.engine-md { margin: 0 !important; }
.engine-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 2px 0; }
.engine-note { font-size: 0.68em; opacity: 0.65; margin-left: 4px; }
.engine-chip {
display: inline-block; border: 2px solid #0b2c5c; border-radius: 999px;
padding: 2px 10px; font-size: 0.72em; background: #ffffff; color: #0b2c5c;
white-space: nowrap;
}
/* spot badges: identity + hazards + surf cam */
.badge-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0; }
.badge-chip {
display: inline-block; border: 2px solid #0b2c5c; border-radius: 999px;
padding: 3px 10px; font-size: 0.78em; background: #ffffff; color: #0b2c5c;
}
.badge-warn { background: #fef7e0 !important; }
.badge-link { background: #d6e9f8 !important; text-decoration: none; font-weight: 600; }
.badge-link:hover { background: #0b2c5c !important; color: #ffffff !important; }
/* intel rail: tab row styled after the story's score/swell/wind strip —
bare text tabs (no block chrome), one line, orange underline marks the
selected one (colors measured off the live strip: #f97316 selected) */
.gradio-container .intel-tabs,
.gradio-container form:has(.intel-tabs),
.gradio-container .block:has(> .intel-tabs) {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
}
.intel-tabs { margin: 0 0 4px; border-bottom: 1px solid #c9dff2; }
.intel-tabs .wrap { display: inline-flex !important; flex-wrap: nowrap !important; gap: 0 !important; }
.gradio-container .intel-tabs label {
border: none !important;
border-bottom: 2px solid transparent !important;
border-radius: 0 !important;
background: transparent !important;
box-shadow: none !important;
color: #0b2c5c !important;
font-size: 14px !important;
font-weight: 400 !important;
padding: 4px 16px 6px !important;
margin: 0 0 -1px !important;
white-space: nowrap !important;
}
.gradio-container .intel-tabs label.selected,
.gradio-container .intel-tabs label:has(input[type="radio"]:checked) {
background: transparent !important;
color: #f97316 !important;
border-bottom: 2px solid #f97316 !important;
}
.gradio-container .intel-tabs label.selected span,
.gradio-container .intel-tabs label:has(input[type="radio"]:checked) span {
color: #f97316 !important;
}
/* spot description: the break's own words, right under the spot name */
.spot-desc { font-size: 0.85em; line-height: 1.55; margin: 2px 0 4px !important; }
.spot-desc-empty { opacity: 0.55; font-style: italic; }
/* page footer: the machinery line (engines + latencies) below the fold */
.page-foot { border-top: 2px solid #c9dff2; margin-top: 10px; }
.gradio-container .page-foot .form,
.gradio-container .page-foot .block {
border: none !important; background: transparent !important;
padding: 0 !important; box-shadow: none !important;
}
.gradio-container .page-foot label span { font-size: 0.72em; opacity: 0.7; }
.gradio-container .page-foot textarea {
background: transparent !important; border: none !important;
font-size: 0.8em !important; padding: 2px 2px !important; resize: none !important;
}
/* week hero: day chips with score-coloured left borders */
.day-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.day-chip {
display: inline-flex; flex-direction: column; gap: 0;
border: 1px solid #c9dff2; border-left: 5px solid #91cf60;
border-radius: 8px; padding: 4px 10px; background: #ffffff; color: #0b2c5c;
font-size: 0.8em; line-height: 1.5; min-width: 86px;
}
.day-chip b { font-size: 1.05em; }
.day-chip i { font-style: normal; opacity: 0.8; }
.hero-cap { font-size: 0.85em; font-weight: 700; margin-top: 4px; }
/* map skill legend chips */
.skill-legend { display: flex; flex-wrap: wrap; gap: 10px; margin: 2px 4px; }
.skill-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 0.75em; color: #0b2c5c; }
.skill-chip i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; border: 1px solid #0b2c5c; }
/* strip caption: how to read the instrument */
.strip-caption { font-size: 0.72em; opacity: 0.75; margin: 0 4px; }
/* lens column sticks while the story scrolls past */
.lens-col { position: sticky !important; top: 8px; align-self: flex-start !important; }
/* agent bar: full-width sidekick under the main row */
.agent-col { margin-top: 4px; }
/* messenger-style chat: input row pinned under the chat log */
.chat-input-row { align-items: flex-end !important; }
/* agent controls row: state/region filters + max-tool-calls slider,
one tight line (dropdowns mirror the lens) */
.agent-controls { align-items: flex-end !important; gap: 8px !important; }
.agent-controls .gr-dropdown, .agent-controls .gr-slider { flex-wrap: nowrap !important; }
.agent-controls .wrap { flex-wrap: nowrap !important; }
.ctx-line { font-size: 0.78em; opacity: 0.8; margin: 0 2px 4px !important; }
/* max-calls slider: ink-blue instrument, no number box — the thumb is the
value; min/max labels bracket the track */
.steps-slider .tab-like-container { display: none !important; }
.steps-slider .slider_input_container { align-items: center !important; margin-top: 4px !important; }
.steps-slider .min_value, .steps-slider .max_value {
font-size: 12px !important; font-weight: 600 !important;
color: #4a6fa5 !important; opacity: 1 !important;
}
.steps-slider input[type="range"] { height: 20px !important; }
.steps-slider input[type="range"]::-webkit-slider-runnable-track {
height: 8px !important; border-radius: 999px !important;
background: linear-gradient(to right, #0b2c5c var(--range_progress), #c9dff2 var(--range_progress)) !important;
}
.steps-slider input[type="range"]::-webkit-slider-thumb {
appearance: none !important;
height: 18px !important; width: 18px !important; margin-top: -5px !important;
background: #ffffff !important;
border: 2.5px solid #0b2c5c !important;
border-radius: 50% !important;
box-shadow: 0 1px 4px rgba(11, 44, 92, 0.3) !important;
transition: transform 0.12s ease !important;
}
.steps-slider input[type="range"]:hover::-webkit-slider-thumb,
.steps-slider input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.15); }
.steps-slider input[type="range"]::-moz-range-track {
height: 8px !important; border-radius: 999px !important; background: #c9dff2 !important;
}
.steps-slider input[type="range"]::-moz-range-progress {
height: 8px !important; border-radius: 999px !important; background: #0b2c5c !important;
}
.steps-slider input[type="range"]::-moz-range-thumb {
height: 14px !important; width: 14px !important;
background: #ffffff !important; border: 2.5px solid #0b2c5c !important;
border-radius: 50% !important;
box-shadow: 0 1px 4px rgba(11, 44, 92, 0.3) !important;
}
/* agent trace: live tool cards with ms timing bars + payload previews */
.trace { display: flex; flex-direction: column; gap: 6px; }
.trace-ask { font-size: 0.78em; opacity: 0.7; margin-bottom: 2px; }
.trace-card {
border: 2px solid #0b2c5c; border-radius: 10px; background: #ffffff;
padding: 6px 10px; font-size: 0.78em; color: #0b2c5c;
}
.trace-card.pending { border-style: dashed; opacity: 0.75; }
.trace-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.trace-head code { font-size: 0.95em; word-break: break-all; }
.trace-ms { margin-left: auto; opacity: 0.8; white-space: nowrap; font-weight: 600; }
.trace-bar {
height: 6px; background: #eef6fd; border: 1px solid #c9dff2;
border-radius: 999px; margin: 4px 0 2px; overflow: hidden;
}
.trace-bar i { display: block; height: 100%; background: #0b2c5c; }
.trace-summary { opacity: 0.85; margin-top: 2px; }
.trace-card details { margin-top: 3px; }
.trace-card pre {
background: #eef6fd; border: 1px solid #c9dff2; border-radius: 6px;
padding: 6px; font-size: 0.9em; overflow-x: auto;
white-space: pre-wrap; word-break: break-word; margin: 3px 0 0;
}
.trace-empty, .rank-empty { font-size: 0.8em; opacity: 0.6; }
/* verdict banner: the answer's contract line, front and centre */
.verdict-slot { border: none !important; padding: 0 !important; background: transparent !important; box-shadow: none !important; }
.verdict-banner {
border: 2px solid #0b2c5c; border-radius: 12px; background: #ffffff;
padding: 8px 14px; font-size: 1.02em; margin: 2px 0 6px;
}
.verdict-banner:empty { display: none; }
/* ranked leaderboard cards */
.rank-list { display: flex; flex-direction: column; gap: 6px; }
.rank-card {
display: flex; align-items: center; gap: 10px;
border: 2px solid #0b2c5c; border-radius: 10px; background: #ffffff;
padding: 6px 10px; font-size: 0.8em; color: #0b2c5c;
}
.rank-card .rank-num { font-weight: 700; min-width: 30px; }
.rank-card .rank-name { min-width: 0; }
.rank-card .rank-name i { opacity: 0.75; }
.rank-card .rank-score { margin-left: auto; font-weight: 700; white-space: nowrap; }
.rank-card .rank-time { opacity: 0.8; white-space: nowrap; }
/* chip buttons wrap instead of stretching one per row */
.chip-btn { white-space: normal !important; height: auto !important; min-height: 0 !important; }
/* mode toggle: sliding pill switch in the header — forecast vs agentic */
.mode-toggle {
display: inline-flex; align-items: center; gap: 0;
background: #ffffff; border: 1px solid #c9dff2; border-radius: 999px;
padding: 3px; width: fit-content; margin: 0 0 0 auto;
}
.mode-toggle .wrap { display: inline-flex !important; gap: 0 !important; }
.mode-toggle input[type="radio"],
.mode-toggle input[type="radio"] + * .circle,
.mode-toggle span.circle,
.intel-tabs input[type="radio"],
.intel-tabs input[type="radio"] + * .circle,
.intel-tabs span.circle { display: none !important; }
.mode-toggle label {
border-radius: 999px !important; padding: 4px 14px !important;
font-size: 0.78em; font-weight: 600; color: #0b2c5c; cursor: pointer;
border: none !important; box-shadow: none !important; background: transparent !important;
transition: background 0.18s ease, color 0.18s ease;
}
.mode-toggle label.selected {
background: #0b2c5c !important; color: #ffffff !important;
}
/* mobile: stack columns, shrink map */
@media (max-width: 700px) {
.gradio-container .gr-row { flex-wrap: wrap !important; }
.gradio-container .gr-column { min-width: 100% !important; }
.lens-col { position: static !important; }
.hero-title { font-size: 1.6em !important; }
}
"""