"""audio·brief design tokens — lifted from Audio Brief.dc.html (Crate Dock).
Three semantic colour families:
- coral #FF6A3D — generative (prompts, gens, variants, "create")
- mint #5BE0C8 — measured (BPM, key, sections, loudness, "observe")
- amber #FFC24B — anchor (your favourited take we blend from)
Fonts: Space Grotesk for body/heading, JetBrains Mono for numbers + labels.
Background system: near-black (#0F1115) → panel (#121419) → card (#14171D) →
input (#171A20). Borders step from #20242C (faint) to #2A2F38 (chip).
The theme exposes Gradio's tokens; the CSS adds layout primitives the
design needs that Gradio doesn't model (mono labels, metric tile grid,
brand mark, pollen pill). All custom classes prefixed `dc-`.
"""
from __future__ import annotations
import gradio as gr
# ---------------------------------------------------------------------------
# Pollinations App Key — public client identifier for audio-brief, issued at
# auth.pollinations.ai. `pk_` prefix = publishable, safe to commit (Stripe-
# style). Embedded in the OAuth authorize URL so Pollinations knows which
# registered app is asking for consent and scopes the issued user-key to it.
# The redirect URI registered alongside this key MUST match the production
# URL the OAuth flow lands on — currently `https://kalamishere-audio-brief.hf.space/`.
# ---------------------------------------------------------------------------
POLLINATIONS_APP_KEY = "pk_dM3MSkFzNdenZCd5"
# ---------------------------------------------------------------------------
# Colour ramps — c500 anchors the brand colour; c50→c950 fade for hover/text
# ---------------------------------------------------------------------------
CORAL = gr.themes.Color(
c50="#FFE7DD",
c100="#FFD0BC",
c200="#FFB89A",
c300="#FFA279",
c400="#FF8C5A",
c500="#FF6A3D", # brand coral
c600="#E55731",
c700="#CC4424",
c800="#A23217",
c900="#78210B",
c950="#140B07", # dark text on coral button
)
MINT = gr.themes.Color(
c50="#E1FBF6",
c100="#C2F5EA",
c200="#A2EFDE",
c300="#83E9D3",
c400="#5BE0C8", # brand mint (light)
c500="#5BE0C8", # brand mint
c600="#42C7AE",
c700="#2BB89E",
c800="#1B8C76",
c900="#0F5949",
c950="#06201B",
)
# Warm-grey neutral — matches design's panel + text greys.
ZINC = gr.themes.Color(
c50="#F2EFE9", # primary text (cream)
c100="#E3E0D9",
c200="#C9CDD4", # secondary text
c300="#99A0AB", # muted text
c400="#7A828D",
c500="#5E6671", # faint label text
c600="#4A5158",
c700="#3A3F47",
c800="#2A2F38", # chip border
c900="#20242C", # divider border
c950="#0F1115", # page bg
)
# ---------------------------------------------------------------------------
# Theme object
# ---------------------------------------------------------------------------
THEME = gr.themes.Base(
primary_hue=CORAL,
secondary_hue=MINT,
neutral_hue=ZINC,
radius_size=gr.themes.sizes.radius_lg,
spacing_size=gr.themes.sizes.spacing_md,
text_size=gr.themes.sizes.text_md,
font=[gr.themes.GoogleFont("Space Grotesk"), "system-ui", "sans-serif"],
font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace"],
).set(
# surfaces
body_background_fill="#0F1115",
body_text_color="#F2EFE9",
body_text_color_subdued="#99A0AB",
background_fill_primary="#0F1115",
background_fill_secondary="#121419",
block_background_fill="#14171D",
block_border_color="#232831",
block_border_width="1px",
block_radius="14px",
block_label_background_fill="transparent",
block_label_text_color="#99A0AB",
block_label_text_size="11px",
block_label_text_weight="600",
block_title_text_color="#F2EFE9",
block_title_text_weight="600",
panel_background_fill="#121419",
panel_border_color="#20242C",
border_color_primary="#232831",
border_color_accent="#FF6A3D",
# buttons
button_primary_background_fill="#FF6A3D",
button_primary_background_fill_hover="#FF8C5A",
button_primary_text_color="#140B07",
button_primary_border_color="#FF6A3D",
button_secondary_background_fill="#171A20",
button_secondary_background_fill_hover="#1B1F26",
button_secondary_text_color="#C9CDD4",
button_secondary_border_color="#2A2F38",
button_cancel_background_fill="#171A20",
button_cancel_text_color="#99A0AB",
button_cancel_border_color="#2A2F38",
button_large_radius="9px",
button_small_radius="7px",
# inputs
input_background_fill="#0F1115",
input_background_fill_focus="#121419",
input_border_color="#232831",
input_border_color_focus="#FF6A3D",
input_placeholder_color="#5E6671",
input_radius="9px",
slider_color="#FF6A3D",
# tables / dataframes
table_border_color="#232831",
table_even_background_fill="#14171D",
table_odd_background_fill="#121419",
table_row_focus="rgba(255,106,61,0.08)",
table_text_color="#C9CDD4",
# code / markdown
code_background_fill="#0F1115",
link_text_color="#5BE0C8",
link_text_color_hover="#FF8C5A",
# accent token used by various states
color_accent="#5BE0C8",
color_accent_soft="rgba(91,224,200,0.14)",
)
# ---------------------------------------------------------------------------
# CSS — what Gradio's theme tokens don't cover.
# Adds: font import, scrollbar, brand mark, pollen pill, metric tiles,
# inline-coloured number helpers, label mono-uppercase.
# ---------------------------------------------------------------------------
CUSTOM_CSS = """
/* ---- Fonts (Gradio's font= already injects these, kept as belt-and-braces) */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
body { font-family: 'Space Grotesk', system-ui, sans-serif !important; }
code, kbd, pre, .mono, .dc-mono { font-family: 'JetBrains Mono', ui-monospace, monospace !important; }
/* ---- Palette system (v3 design handoff) -------------------------------
Three named worlds the user toggles in the top bar. Implemented as a
class on
(`pal-studio` / `pal-console` / `pal-dub`) that
defines a token set; every surface styles from var(--token) so a
single class swap re-themes the tree.
The 350ms cross-fade requested in the brief is intentionally NOT used
here — animating background-color through a var() that resolves via a
class swap stalls mid-transition in-engine (renders half-painted).
Instant swap is correct and reliable. See design/README.md §⚠.
Default below `:root` matches Console so var() resolves even before
the JS class-swap runs on first paint.
*/
:root, body.pal-console {
--paper:#13141A; --paper2:#181A22; --paper3:#1C1F28; --input:#1F232D;
--ink:#F2EFE9; --ink2:#C9CDD4; --ink3:#99A0AB; --label:#5E6671;
--line:#23262F; --line2:#1D2027; --chipline:#2E323C;
--coral:#FF6A3D; --coralb:#FF8C5A; --onCoral:#140B07;
--amber:#FFC24B; --metric:#5BE0C8; --mint:#5BE0C8;
--secIntro:#2BB89E; --secBuild:#5BE0C8; --secCore:#FF6A3D; --secOutro:#FF8C5A;
--coralTint: rgba(255,106,61,0.08);
--coralTintHover: rgba(255,106,61,0.14);
--amberTint: rgba(255,194,75,0.10);
--drop: 0 24px 60px rgba(0,0,0,.40);
}
/* Studio (light) was the v3 design's primary new palette but shipped with
multiple legibility regressions on Gradio v6 — browser-default button
backgrounds beating our transparent rule, brand wordmark losing
contrast, cost pip washing out, native button text inheriting the
wrong color. Dropped from the toggle for now; spec preserved below
for a dedicated Studio pass (will need Gradio-native button + input
overrides at .pal-studio scope to beat user-agent styles).
----
body.pal-studio {
--paper:#FBF8F1; --paper2:#F3EDE1; --paper3:#EAE2D2; --input:#FCFAF4;
--ink:#0E1A1E; --ink2:#45565A; --ink3:#7A878A; --label:#8A969A;
--line:rgba(14,26,30,0.14); --line2:rgba(14,26,30,0.09); --chipline:rgba(14,26,30,0.20);
--coral:#D9461F; --coralb:#E8633A; --onCoral:#FBF8F1;
--amber:#BC841C; --metric:#157567; --mint:#1C9482;
--secIntro:#157567; --secBuild:#1C9482; --secCore:#D9461F; --secOutro:#E8633A;
--coralTint: rgba(217,70,31,0.07);
--coralTintHover: rgba(217,70,31,0.13);
--amberTint: rgba(188,132,28,0.10);
--drop: 0 1px 2px rgba(14,26,30,.10), 0 14px 40px rgba(14,26,30,.08);
}
*/
body.pal-dub {
--paper:#1B1612; --paper2:#241D17; --paper3:#2E2620; --input:#332A22;
--ink:#E8DECB; --ink2:#C2B7A0; --ink3:#8C8270; --label:#6E6453;
--line:#372E25; --line2:#2A231C; --chipline:#473C30;
--coral:#FF7A4D; --coralb:#FF9468; --onCoral:#1B1612;
--amber:#FFB94B; --metric:#7BE5CC; --mint:#7BE5CC;
--secIntro:#3FB89E; --secBuild:#7BE5CC; --secCore:#FF7A4D; --secOutro:#FF9468;
--coralTint: rgba(255,122,77,0.10);
--coralTintHover: rgba(255,122,77,0.16);
--amberTint: rgba(255,185,75,0.12);
--drop: 0 22px 50px rgba(0,0,0,.55);
}
/* ---- Dub-only character pass — make it actually feel like vinyl, not
just "Console but warmer". Each rule is scoped to body.pal-dub so the
Console look is untouched. Pieces:
1. Subtle paper-grain noise overlay on body (fractalNoise SVG data
URI, ~3% opacity) so card stock reads as material, not glass.
2. Brand wordmark dot flips mint → amber — Console's mint dot is a
"measured" cue; Dub leans warmer, amber matches the anchor.
3. Coral buttons gain an inset bottom shadow so they read as
stamped/inked rather than flat. Hover lifts the stamp.
4. Card-edge highlight (1px top inner glow + a slightly heavier
border) — gives cards a worn-pressboard feel.
5. Metric numbers bump to 700 weight — the readout reads as
chunky-typeset rather than the lighter Console face.
6. Top-bar bottom border thickens to 2px → reads as a turntable
platter rim under the brand.
*/
body.pal-dub::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9999;
opacity: 0.04;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;utf8,");
background-size: 180px 180px;
}
body.pal-dub .dc-brand .dot { color: var(--amber); }
body.pal-dub .gr-button.gr-button-primary,
body.pal-dub .gr-button-primary,
body.pal-dub button[class*="primary"] {
box-shadow: inset 0 -2px 0 rgba(0,0,0,0.35), 0 1px 0 rgba(255,180,120,0.10) !important;
text-shadow: 0 1px 0 rgba(0,0,0,0.20);
}
body.pal-dub .gr-button.gr-button-primary:hover,
body.pal-dub .gr-button-primary:hover,
body.pal-dub button[class*="primary"]:hover {
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.30), 0 2px 0 rgba(255,180,120,0.14) !important;
}
body.pal-dub .dc-metric,
body.pal-dub .dc-anchor-player,
body.pal-dub .dc-variants-prompt-card,
body.pal-dub .dc-derived-card,
body.pal-dub .dc-variant-title {
box-shadow: inset 0 1px 0 rgba(255,210,170,0.04);
border-width: 1px;
}
body.pal-dub .dc-metric-v { font-weight: 700; letter-spacing: -0.01em; }
body.pal-dub .dc-topbar { border-bottom-width: 2px; border-bottom-color: var(--line); }
body.pal-dub .dc-crate-strip label,
body.pal-dub .dc-crate-strip .wrap label {
box-shadow: inset 0 1px 0 rgba(255,210,170,0.05);
}
/* Anchor card in the variants row reads as the actual record on the
mat — slightly warmer tint than Console's plain amber wash. */
body.pal-dub .dc-variant.anchor,
body.pal-dub .dc-tile.anchor {
background: linear-gradient(180deg, var(--amberTint) 0%, var(--paper3) 100%) !important;
border-color: color-mix(in srgb, var(--amber) 55%, transparent) !important;
}
/* ---- Scrollbar — slim, neutral */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: var(--chipline); border-radius: 4px; }
::-webkit-scrollbar-track { background: transparent; }
/* ---- Page container — palette-driven base, cap content width so the
layout stays focused on wide monitors. Gradio v6 wraps content in
`.wrap > main.contain` (no .gradio-container class). 1200px feels
right for composer + crate; waveform + grids fill this width.
Below 1200px viewport, the container naturally shrinks.
The explicit width:100% on html/body/wrap defends against a
Gradio v6 layout collapse: when a top-level state-changing
element re-renders (e.g. the topbar gr.HTML refreshing after
OAuth completes), the outer flex container can fall back to
min-content width — which then shrinks to the widest single
child (the 360px-capped Generate button). Pinning the chain to
100% width keeps it filling the viewport across re-renders. */
html, body, .wrap, gradio-app, gradio-app > div, .gradio-container {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
transform: none !important;
zoom: 1 !important;
}
/* Stop any horizontal overflow so the centered main.contain doesn't
sit off-axis — 100vw includes scrollbar width on Chromium/Brave,
so anything pinned to 100vw drifts the layout right by the scroll
gutter (~15px). Stay with 100% (respects scrollbar). */
html, body { overflow-x: hidden !important; }
html { zoom: 1 !important; -webkit-text-size-adjust: 100% !important; }
/* Belt-and-braces: if Gradio's .wrap is a flex container,
margin:0 auto on main.contain won't center — assert it explicitly. */
.wrap { display: block !important; }
main.contain, .wrap > main {
background: transparent !important;
color: var(--ink);
width: 100% !important;
max-width: 1280px !important;
margin: 0 auto !important;
padding: 28px 24px !important;
box-sizing: border-box !important;
}
body {
background: var(--paper) !important;
color: var(--ink);
position: relative;
/* Soft brand-axis gradients on the body bg — coral at top-right
(generative axis), mint at bottom-left (measured axis). Each
sits at ~5% opacity so the surface stays Console-dark but reads
as a composed page rather than a flat black plane. Designer
cleanup pass: gives the eye warmth without competing with the
Generate CTA. */
background-image:
radial-gradient(60% 50% at 95% 0%, color-mix(in srgb, var(--coral) 14%, transparent), transparent 60%),
radial-gradient(60% 60% at 5% 100%, color-mix(in srgb, var(--mint) 9%, transparent), transparent 65%) !important;
background-attachment: fixed !important;
}
/* ---- Gradio native surface overrides — needed so block/input/button
backgrounds re-paint per palette (the gr.themes.Base values were
baked at construction time, so we re-assert via the class). */
body .block, body .panel { background: var(--paper2) !important; border-color: var(--line) !important; }
body .form, body .gr-box { background: var(--paper3) !important; border-color: var(--line) !important; }
body input[type="text"], body textarea, body .input-container { background: var(--input) !important; color: var(--ink) !important; border-color: var(--line) !important; }
body .gr-button-primary, body button[class*="primary"] {
background: var(--coral) !important;
color: var(--onCoral) !important;
border-color: var(--coral) !important;
}
body .gr-button-secondary, body button[class*="secondary"] {
background: var(--input) !important;
color: var(--ink2) !important;
border-color: var(--chipline) !important;
}
/* Hide Gradio's footer ("Use via API" etc.) — clutter */
footer { display: none !important; }
/* ---- Action button width cap — primary buttons should size to content,
not stretch to the row width. ~360px is the design's big-CTA width.
Prevents the "Use for analysis" button from ballooning to 1900px on
a wide monitor when its sibling chip strip is full-width.
Override via `elem_classes=["dc-full-button"]` on buttons that DO
want to span the row (Generate / Regenerate on the prompt card). */
.gr-button.lg, .gr-button-lg, button.lg, button.gr-button-large {
max-width: 360px !important;
margin-left: 0 !important;
}
.dc-full-button button, button.dc-full-button {
max-width: 100% !important;
width: 100% !important;
}
/* Primary "Use for analysis →" in the crate row — cap its growth */
.dc-crate-row .gr-button-primary, .dc-crate-row button[class*="primary"] {
max-width: 320px !important;
flex: 0 0 auto !important;
}
/* ---- Headings — Space Grotesk weight/letter-spacing per design */
h1, h2, h3 {
font-family: 'Space Grotesk', sans-serif !important;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--ink);
}
h1 { font-size: 22px; letter-spacing: -0.02em; }
h2 { font-size: 16px; }
h3 { font-size: 13px; color: var(--ink2); }
/* ---- Brand wordmark — used in top bar HTML block */
.dc-brand {
display: inline-flex;
align-items: center;
gap: 9px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
font-size: 16px;
letter-spacing: -0.01em;
color: var(--ink);
}
.dc-brand .dot { color: var(--mint); margin: 0 1px; }
.dc-brand-bars {
display: inline-flex;
align-items: flex-end;
gap: 2px;
height: 18px;
}
.dc-brand-bars > span { width: 3px; border-radius: 1px; display: inline-block; }
.dc-brand-bars .b1 { height: 7px; background: var(--coral); }
.dc-brand-bars .b2 { height: 16px; background: var(--coral); }
.dc-brand-bars .b3 { height: 10px; background: var(--mint); }
.dc-brand-bars .b4 { height: 13px; background: var(--mint); }
/* ---- Palette toggle — circular swatch buttons. Each circle's interior
paints the palette's paper color, the border ring uses that palette's
accent (coral for Console, amber for Dub). Active = brighter ring +
outer halo + faint scale; inactive dims to 55% so the active swatch
reads loud. Hover restores full opacity. JS in the palette-swap
script (top of app) updates body class + persists to localStorage. */
.dc-palette-toggle {
display: inline-flex;
align-items: center;
gap: 8px;
user-select: none;
padding: 0 4px;
}
.dc-palette-toggle button {
appearance: none !important;
cursor: pointer !important;
padding: 0 !important;
width: 26px !important;
height: 26px !important;
flex-shrink: 0 !important;
border-radius: 50% !important;
background: var(--swatch-fill, var(--coral)) !important;
border: 1.5px solid rgba(255,255,255,0.22) !important;
box-shadow: none;
opacity: 0.7;
transition: opacity 120ms ease, transform 120ms ease, box-shadow 160ms ease;
}
.dc-palette-toggle button[data-pal="console"] {
/* Console = coral solid (matches the brand's primary axis) */
--swatch-fill: #FF6A3D;
}
.dc-palette-toggle button[data-pal="dub"] {
/* Dub = amber solid (the anchor / vinyl colour) */
--swatch-fill: #FFB94B;
}
.dc-palette-toggle button:hover { opacity: 0.95; transform: scale(1.06); }
.dc-palette-toggle button.active {
opacity: 1;
transform: scale(1.10);
border-color: rgba(255,255,255,0.45) !important;
box-shadow: 0 0 0 2px var(--paper),
0 0 0 4px color-mix(in srgb, var(--swatch-fill) 70%, transparent),
0 6px 16px color-mix(in srgb, var(--swatch-fill) 28%, transparent);
}
/* Strip the Gradio .block chrome from gr.HTML elements that hold pure
script/style tags. They were rendering as visible blank bars because
Gradio still paints the block's background/border even when there's
no DOM content. */
.dc-script-only,
.dc-script-only > .block,
.dc-script-only > div,
.gradio-html.dc-script-only {
display: none !important;
}
/* Off-screen hide for the wallet-bridge textbox. NOT display:none and
NOT visible=False on the gr.Textbox — both pull the element out of
the DOM, so the popup OAuth bridge JS can't find it to write the
sk_... key. Off-screen + 1px + opacity 0 keeps the input mounted,
focusable by JS, and addressable by getElementById('wallet-bridge-key'). */
.dc-wallet-bridge-hidden {
position: fixed !important;
left: -9999px !important;
top: auto !important;
width: 1px !important;
height: 1px !important;
overflow: hidden !important;
opacity: 0 !important;
pointer-events: none !important;
}
/* ---- Pollen balance pill — doubles as wallet button */
.dc-pollen-pill {
display: inline-flex;
align-items: center;
gap: 7px;
background: var(--input);
border: 1px solid var(--chipline);
border-radius: 20px;
padding: 6px 13px;
cursor: pointer;
transition: border-color 120ms, background 120ms;
user-select: none;
}
.dc-pollen-pill:hover { border-color: var(--coral); }
.dc-pollen-pill .diamond { color: var(--amber); font-size: 13px; line-height: 1; }
.dc-pollen-pill .balance {
font-family: 'JetBrains Mono', monospace;
font-weight: 600; font-size: 13px; color: var(--ink);
}
.dc-pollen-pill .lbl {
font-family: 'JetBrains Mono', monospace;
font-weight: 500; font-size: 10px; color: var(--label);
}
/* Not-connected state — coral CTA tint to invite the click */
.dc-pollen-pill.not-connected {
background: var(--coralTint);
border-color: var(--coral);
}
.dc-pollen-pill.not-connected:hover {
background: var(--coralTintHover);
border-color: var(--coral);
}
.dc-pollen-pill.not-connected .diamond { color: var(--coralb); }
.dc-pollen-pill.not-connected .balance { color: var(--coralb); }
.dc-pollen-pill.not-connected .lbl { color: var(--coral); opacity: 0.7; }
/* ---- Session spend pill — running total ◆ pollen this visit. Sits to the
left of the wallet pill. Muted by default (it's reference info, not
a CTA); only shown when there's actual spend > 0. */
.dc-session-pill {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
background: transparent;
border: 1px solid var(--line2);
border-radius: 14px;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--label);
user-select: none;
}
.dc-session-pill .amt { font-weight: 600; color: var(--ink3); }
.dc-session-pill .diamond { color: var(--amber); opacity: 0.7; font-size: 11px; }
.dc-session-pill .lbl { font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; }
/* ---- Inline cost pip — small inline annotation next to the Generate /
Regenerate buttons. Reads "~0.04 ◆ per call · flat". */
.dc-cost-pip {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 10px;
background: var(--paper3);
border: 1px solid var(--line2);
border-radius: 7px;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--ink3);
margin: 8px 0;
width: fit-content;
}
.dc-cost-pip .amt { color: var(--ink2); font-weight: 600; }
.dc-cost-pip .diamond { color: var(--amber); }
.dc-cost-pip .sep { color: var(--ink3); }
/* ---- Variation HOLD chips — placeholder for the CFG control Pollinations
doesn't expose yet. Entire group disabled at 0.45 opacity so users
can see the shape coming, but can't click. Reactivate when Pollinations
adds a CFG/guidance param to /audio/{text}. */
.dc-var-hold {
opacity: 0.45;
pointer-events: none;
user-select: none;
margin: 10px 0;
}
.dc-var-hold .head {
display: flex; align-items: center; gap: 8px;
margin-bottom: 6px;
}
.dc-var-hold .head .label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--label);
}
.dc-var-hold .head .tag {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--label);
padding: 2px 8px;
border: 1px solid var(--line2);
border-radius: 6px;
background: var(--paper3);
}
.dc-var-hold .chips { display: flex; gap: 6px; }
/* ---- Two-column regen controls — Variant Duration | Variants ------- */
.dc-regen-control-row {
align-items: stretch !important;
gap: 16px !important;
margin-top: 10px !important;
}
.dc-regen-control-card {
border: 1px solid var(--line) !important;
border-radius: 12px !important;
background: var(--paper2) !important;
padding: 14px 16px !important;
}
.dc-regen-control-card .dc-label {
margin-bottom: 8px;
}
/* Suppress the giant default radio fieldset margin so the choices sit
right under the label inside the card. */
.dc-regen-control-card fieldset {
margin-top: 0 !important;
}
/* The .info text under each radio (small grey hint) keeps a tight
line-height so the cards stay roughly equal in height. */
.dc-regen-control-card .info {
margin-top: 8px !important;
line-height: 1.35 !important;
}
/* ---- TRANSFORM tab engine selector — Morpho vs Local SA3 ---------- */
.dc-transform-engine .wrap,
.dc-transform-engine > div {
display: flex !important;
flex-direction: row !important;
gap: 8px !important;
margin: 0 0 14px !important;
}
.dc-transform-engine label {
flex: 1 1 0 !important;
padding: 10px 14px !important;
border: 1px solid var(--chipline) !important;
border-radius: 10px !important;
background: var(--paper2) !important;
color: var(--ink2) !important;
font-family: 'JetBrains Mono', monospace !important;
font-size: 12px !important;
cursor: pointer !important;
transition: border-color 120ms, color 120ms, background 120ms !important;
}
.dc-transform-engine label:hover {
border-color: var(--ink3) !important;
color: var(--ink) !important;
}
.dc-transform-engine label.selected {
border-color: var(--coral) !important;
color: var(--coral) !important;
background: color-mix(in srgb, var(--coral) 10%, var(--paper2)) !important;
}
.dc-transform-engine input[type="radio"] {
display: none !important;
}
/* ---- Regen history tabs — radio rendered as a horizontal tab strip
above the variants row. Each tab is one saved regen batch
(`MATCH·1`, `LOOSE·1`, `MATCH·2`, etc.). Click → replay that
batch into the variants cards + prompt-used card. */
.dc-regen-tabs .wrap,
.dc-regen-tabs > div {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
gap: 6px !important;
margin: 14px 0 6px !important;
}
.dc-regen-tabs label {
padding: 6px 12px !important;
background: var(--paper3) !important;
border: 1px solid var(--line) !important;
border-radius: 6px !important;
font-family: 'JetBrains Mono', monospace !important;
font-size: 11px !important;
font-weight: 600 !important;
letter-spacing: 0.08em !important;
color: var(--ink3) !important;
cursor: pointer !important;
transition: background 120ms, border-color 120ms, color 120ms;
}
.dc-regen-tabs label:hover {
background: var(--input) !important;
color: var(--ink) !important;
border-color: var(--coral) !important;
}
.dc-regen-tabs label.selected {
background: var(--coralTint) !important;
border-color: color-mix(in srgb, var(--coral) 60%, transparent) !important;
color: var(--coralb) !important;
}
.dc-regen-tabs input[type="radio"] {
display: none !important;
}
/* ---- Variants prompt-used card — sits above the ANCHOR + 5 VARIANTS
title and echoes the derived prompt that produced the batch. Helps
users see at a glance which lens / wording landed which 5 gens. */
.dc-variants-prompt-card {
background: var(--paper3);
border: 1px solid var(--line);
border-radius: 8px;
padding: 10px 14px;
margin: 14px 0 6px;
}
.dc-variants-prompt-card .head {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.12em;
color: var(--label);
margin-bottom: 6px;
}
.dc-variants-prompt-card .body {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
line-height: 1.55;
color: var(--ink2);
white-space: pre-wrap;
}
/* ---- Variant cards (anchor + 5 variants in one row) — each is a
Column containing a custom HTML title + an Audio component, so
they all line up at the same height regardless of how the audio
widget grows. Title carries the BPM/Harm/Rhyt bar breakdown on
three left-aligned lines + the v-name in the bottom-right. */
.dc-variant-cell {
min-width: 0; /* let columns shrink in a tight row */
}
.dc-variant-title {
background: var(--paper3);
border: 1px solid var(--line);
border-radius: 8px 8px 0 0;
border-bottom: none;
padding: 6px 10px;
min-height: 28px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
white-space: nowrap;
overflow: hidden;
}
.dc-variant-title .bars {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
line-height: 1.2;
color: var(--label); /* track behind the meter — muted grey */
text-align: left;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.dc-variant-title .bars .fill {
color: var(--mint); /* mint — measured axis, the metering colour */
font-weight: 600;
}
.dc-variant-title .bars.placeholder {
color: var(--ink3); /* faded — pre-regen state */
}
.dc-variant-title .bars.anchor-label {
font-size: 12px;
color: var(--amber); /* amber for the anchor */
font-weight: 600;
letter-spacing: 0.05em;
}
.dc-variant-title .name {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--label);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
}
/* The Audio sits directly under the title — kill its rounded top so
they read as one card. */
.dc-variant-cell .audio-container,
.dc-variant-cell [class*="audio"] > div:first-child {
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
border-top: none !important;
}
/* ---- Prompt-lens chip row (Analysis tab, above derived prompt textbox).
Three radio options rendered as horizontally-arranged chips that
indicate decreasing fidelity to the measured arc via the leading
freedom-bars glyphs (▮▮▮▮ MATCH / ▮▮▯▯ LOOSE / ▮▯▯▯ FREE). Visual
coherence with the variant card bars is intentional — both use the
same glyph language for "how much constraint the LLM has". */
.dc-lens-chips .wrap,
.dc-lens-chips > div {
display: flex !important;
flex-direction: row !important;
gap: 8px !important;
margin: 4px 0 12px !important;
}
.dc-lens-chips label {
flex: 1 !important;
padding: 8px 12px !important;
background: var(--paper3) !important;
border: 1px solid var(--line) !important;
border-radius: 8px !important;
cursor: pointer !important;
font-family: 'JetBrains Mono', monospace !important;
font-size: 11px !important;
color: var(--ink2) !important;
text-align: center !important;
line-height: 1.45 !important;
transition: background 120ms, border-color 120ms, color 120ms;
}
.dc-lens-chips label:hover {
background: var(--input) !important;
border-color: var(--coral) !important;
color: var(--ink) !important;
}
.dc-lens-chips label.selected {
background: var(--coralTint) !important;
border-color: color-mix(in srgb, var(--coral) 60%, transparent) !important;
color: var(--coralb) !important;
}
.dc-lens-chips input[type="radio"] {
display: none !important;
}
/* ---- Anchor player (Analysis tab) — raw HTML5