bol-tts-marathi / src /styles.css
shreyask's picture
ui: performance metrics card + voice ref-clip download + WAV download
3896c3f verified
/* ─── palette ─────────────────────────────────────────────────────────────
* Maharashtra Warli-art palette: gerua (geru / ΰ€—ΰ₯‡ΰ€°ΰ₯‚, ochre-red earth pigment
* traditional to Warli wall paintings) + warm cream + kumkum highlight.
* Aligned to the SVG header (`warli-strip.svg`) which uses #c34a19 β†’ #9f320f
* gradient on #fff8ec for the dancers/sun/microphones.
*
* Cream paper #FAF3E7
* Ivory card #F2E8D3
* Gerua (Warli red-ochre) #C34A19 ← was #E07A1F (too saffron-yellow)
* Gerua dark #9F320F ← matches SVG gradient endpoint
* Kumkum (deep red) #8E2E2E
* Ink brown #2E1D10
* Muted cocoa #8C6E56
* Warli white #FFF8EC ← matches SVG #fff8ec
* Sage (success) #6B8B4E
*/
:root {
--bg: #FAF3E7;
--card: #F2E8D3;
--card-border: #D9C9A7;
--accent: #C34A19; /* gerua β€” earth-pigment red, authentic Warli */
--accent-dark: #9F320F; /* deep gerua, matches SVG gradient bottom */
--accent-soft: #C34A1922;
--red: #8E2E2E;
--ink: #2E1D10;
--muted: #8C6E56;
--good: #6B8B4E;
--bad: #A63A3A;
--warli: #FFF8EC;
font-family: "Inter", -apple-system, "Segoe UI", sans-serif;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
background: var(--bg);
color: var(--ink);
min-height: 100vh;
line-height: 1.5;
}
/* ─── typography ──────────────────────────────────────────────────────────
* Yatra One: festival/display feel for title + ornamentals
* Tiro Devanagari Marathi: elegant serif for Devanagari body text
*/
.font-display { font-family: "Yatra One", "Tiro Devanagari Marathi", serif; }
.font-devanagari {
font-family: "Inter", "Tiro Devanagari Marathi", "Noto Sans Devanagari", serif;
font-weight: 400;
}
/* ─── warli border strip ─────────────────────────────────────────────────
* Tribal art band β€” dancers, hut, deer, microphones, sun motifs in white on
* saffron. Originals are 2172Γ—154 PNG; we display at fixed pixel height and
* stretch horizontally to the viewport (object-fit: cover).
*/
.warli-strip {
width: 100%;
margin-top: 24px;
display: flex;
justify-content: center;
overflow: hidden;
}
.warli-strip img {
/* Natural aspect (2172Γ—154 β‰ˆ 14:1). width:100% fills the viewport up to
* max-width; past that the strip caps and cream gutters appear on either
* side. No object-fit cropping, no distortion, triangle borders always
* visible. */
width: 100%;
height: auto;
max-width: 1600px;
display: block;
}
.warli-strip--bottom {
margin-top: 24px;
/* No rotation β€” the SVG already has triangle borders on BOTH the top and
* bottom edges of the strip, so the same image works for both header and
* footer. Rotating 180Β° would have flipped figures upside-down. */
}
/* ─── layout ──────────────────────────────────────────────────────────── */
main {
max-width: 860px;
margin: 0 auto;
padding: 40px 24px 80px;
}
header {
text-align: center;
margin-bottom: 32px;
}
header h1 {
font-family: "Yatra One", "Tiro Devanagari Marathi", serif;
font-size: 38px;
margin: 0 0 6px;
color: var(--red);
letter-spacing: 0;
}
header .sub {
margin: 0;
color: var(--muted);
font-size: 14px;
}
header .namaste {
font-family: "Tiro Devanagari Marathi", serif;
font-size: 18px;
color: var(--accent-dark);
margin-bottom: 8px;
display: block;
}
.card {
background: var(--card);
border: 1px solid var(--card-border);
border-radius: 14px;
padding: 18px 20px;
margin-bottom: 16px;
box-shadow: 0 1px 2px rgba(46, 29, 16, 0.04);
}
.status {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 13px;
color: var(--muted);
padding: 10px 14px;
}
.status.ready { color: var(--good); }
.status.error { color: var(--bad); }
.model-gate {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
border-left: 3px solid var(--accent);
}
.model-gate-text { font-size: 14px; color: var(--ink); line-height: 1.7; }
.model-gate-text strong { color: var(--red); }
.model-gate-sub { color: var(--muted); font-size: 12px; display: block; margin-top: 4px; }
.model-gate-variant {
display: block;
font-size: 13px;
cursor: pointer;
padding: 2px 0;
}
.model-gate-variant input[type=radio] { accent-color: var(--accent); margin-right: 6px; }
.model-gate button { flex-shrink: 0; }
label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
/* Row that puts the textarea label and the Transliterate utility button on
the same line, label flush left and button flush right. */
.text-label-row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
margin-bottom: 6px;
}
.text-label-row label { margin: 0; }
.text-tool {
background: transparent;
color: var(--accent-dark);
border: 1px solid var(--card-border);
border-radius: 999px;
padding: 3px 10px;
font-size: 12px;
font-family: "Inter", "Tiro Devanagari Marathi", sans-serif;
cursor: pointer;
transition: background 120ms, color 120ms, border-color 120ms;
}
.text-tool:hover {
background: var(--accent-soft);
border-color: var(--accent);
color: var(--accent-dark);
}
textarea {
width: 100%;
background: var(--warli);
color: var(--ink);
border: 1px solid var(--card-border);
border-radius: 10px;
padding: 12px 14px;
font-size: 19px;
font-family: "Inter", "Tiro Devanagari Marathi", "Noto Sans Devanagari", serif;
line-height: 1.55;
resize: vertical;
}
textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.examples { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 6px; align-items: center; }
.examples-label { color: var(--muted); font-size: 12px; margin-right: 4px; }
.chip {
background: transparent;
color: var(--ink);
border: 1px solid var(--card-border);
border-radius: 999px;
padding: 4px 10px;
font-size: 13px;
font-family: "Inter", "Tiro Devanagari Marathi", "Noto Sans Devanagari", serif;
cursor: pointer;
transition: background 120ms, color 120ms, border-color 120ms;
}
.chip:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); }
.controls {
display: grid;
grid-template-columns: 1fr 1fr auto;
gap: 14px;
align-items: end;
margin-top: 14px;
}
.controls select, .controls input[type=range] {
width: 100%;
background: var(--warli);
color: var(--ink);
border: 1px solid var(--card-border);
border-radius: 8px;
padding: 7px 10px;
}
.controls input[type=range] {
accent-color: var(--accent);
padding: 4px 0;
}
.speed-control { margin-bottom: 0; }
.speed-control-row {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 6px;
font-size: 13px;
color: var(--muted);
}
.speed-control-row #speed-val {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
color: var(--accent-dark);
font-variant-numeric: tabular-nums;
}
button.primary {
background: var(--accent);
color: #fff;
border: none;
border-radius: 8px;
padding: 9px 20px;
font-weight: 600;
cursor: pointer;
font-size: 14px;
font-family: "Inter", "Tiro Devanagari Marathi", sans-serif;
}
button.primary:hover { background: var(--accent-dark); }
button.primary:disabled { opacity: 0.45; cursor: default; }
.ab-test { margin-top: 10px; }
/* ─── audio output area ──────────────────────────────────────────────── */
/* ─── fused player: play/pause button + seekable waveform + time ─────── */
.player {
display: grid;
grid-template-columns: 48px 1fr;
gap: 12px;
align-items: center;
background: var(--warli);
border: 1px solid var(--card-border);
border-radius: 10px;
padding: 10px 12px;
margin-bottom: 14px;
}
.playpause {
width: 44px;
height: 44px;
border-radius: 50%;
background: var(--accent);
color: #fff;
border: none;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
padding: 0;
transition: background 120ms;
}
.playpause:hover { background: var(--accent-dark); }
.playpause.playing { font-size: 16px; }
.player-main {
position: relative;
display: flex;
flex-direction: column;
gap: 2px;
}
.waveform {
width: 100%;
height: 56px;
background: transparent;
cursor: pointer;
display: block;
}
.waveform:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-radius: 4px; }
.player-time {
display: flex;
justify-content: space-between;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 11px;
color: var(--muted);
font-feature-settings: "tnum";
padding: 0 2px;
}
/* ─── compact transcript (default view) β€” Marathi text with per-word hl ── */
.transcript-compact {
font-family: "Inter", "Tiro Devanagari Marathi", "Noto Sans Devanagari", serif;
font-size: 24px;
line-height: 1.7;
padding: 14px 16px;
border: 1px solid var(--card-border);
border-radius: 10px;
background: var(--warli);
color: var(--ink);
min-height: 60px;
}
.transcript-compact .word {
display: inline-block;
padding: 1px 4px;
border-radius: 4px;
cursor: pointer;
transition: background-color 150ms ease, color 150ms ease;
}
.transcript-compact .word:hover { background: var(--accent-soft); }
.transcript-compact .word:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.transcript-compact .word.active {
background: var(--accent);
color: #fff;
}
.transcript-compact .word.past { color: var(--muted); }
/* ─── expandable per-word detail (IPA + timing) ───────────────────────── */
.transcript-details {
margin-top: 10px;
}
.transcript-details > summary {
cursor: pointer;
color: var(--muted);
font-size: 12px;
padding: 4px 6px;
user-select: none;
}
.transcript-details > summary:hover { color: var(--accent-dark); }
.transcript-details[open] > summary { margin-bottom: 8px; }
/* ─── side-by-side Devanagari / IPA / timing columns ─────────────────── */
.sidebyside {
display: grid;
grid-template-columns: minmax(140px, 1.2fr) minmax(160px, 1.8fr) 2fr;
gap: 0;
border: 1px solid var(--card-border);
border-radius: 10px;
overflow: hidden;
background: var(--warli);
}
.sidebyside .col-head {
font-family: "Yatra One", serif;
font-size: 13px;
color: var(--red);
padding: 8px 12px;
border-bottom: 1px solid var(--card-border);
background: #EFE2C5;
letter-spacing: 0.02em;
}
.sidebyside .row {
display: contents;
}
.sidebyside .cell {
padding: 10px 12px;
border-bottom: 1px solid #E8DBBF;
display: flex;
align-items: center;
transition: background-color 180ms ease;
}
.sidebyside .row.active .cell { background: var(--accent-soft); }
.sidebyside .row.past .cell { color: var(--muted); }
.sidebyside .row:last-child .cell { border-bottom: none; }
.cell.devanagari {
font-family: "Inter", "Tiro Devanagari Marathi", "Noto Sans Devanagari", serif;
font-size: 22px;
font-weight: 500;
color: var(--ink);
}
.sidebyside .row.active .cell.devanagari { color: var(--red); }
.cell.ipa {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 14px;
color: var(--accent-dark);
}
.cell.timing {
position: relative;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
color: var(--muted);
padding: 10px 12px;
}
.cell.timing .bar {
position: absolute;
left: 10px;
right: 10px;
bottom: 6px;
height: 4px;
background: #E8DBBF;
border-radius: 2px;
overflow: hidden;
}
.cell.timing .bar-fill {
height: 100%;
background: var(--accent);
border-radius: 2px;
transform-origin: left center;
transition: transform 80ms linear;
}
.sidebyside .row.past .cell.timing .bar-fill {
background: var(--muted);
transform: scaleX(1);
}
.cell.timing .range {
font-feature-settings: "tnum";
margin-right: 10px;
}
/* ─── Marathi facts sidebar ──────────────────────────────────────────── */
.facts {
background: #EFE2C5;
border-left: 3px solid var(--accent);
padding: 10px 14px;
border-radius: 6px;
font-size: 13px;
color: var(--ink);
margin-top: 14px;
line-height: 1.55;
}
.facts strong { color: var(--red); font-weight: 600; }
.facts .ipa-inline {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
color: var(--accent-dark);
}
/* ─── misc ───────────────────────────────────────────────────────────── */
.details { margin-top: 12px; }
.details summary { cursor: pointer; color: var(--muted); font-size: 12px; }
.phonemes, .word-timings {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
color: var(--muted);
white-space: pre-wrap;
margin: 8px 0 0;
padding: 10px;
background: #EAE0C5;
border-radius: 6px;
max-height: 220px;
overflow: auto;
}
footer {
margin-top: 40px;
color: var(--muted);
font-size: 12px;
text-align: center;
}
footer a,
header p a { color: var(--accent-dark); text-decoration: underline; }
footer a:hover,
header p a:hover { color: var(--red); }
/* download button on the player β€” small circular, sits to the right of the waveform */
.audio-dl-btn {
flex: 0 0 auto;
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid var(--card-border);
background: var(--warli);
color: var(--accent-dark);
font-size: 16px;
line-height: 34px;
text-align: center;
text-decoration: none;
cursor: pointer;
transition: background 120ms, color 120ms, border-color 120ms;
align-self: center;
margin-left: 8px;
}
.audio-dl-btn:hover {
background: var(--accent-soft);
border-color: var(--accent);
color: var(--accent);
}
/* voice picker: "🎧 Reference clip" link sits above the <select>, right-aligned */
.voice-control { margin-bottom: 0; }
.voice-control-row {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 8px;
margin-bottom: 4px;
}
.voice-ref-link {
font-size: 11px;
color: var(--accent-dark);
text-decoration: none;
border-bottom: 1px dotted var(--accent-soft);
cursor: pointer;
transition: color 120ms, border-color 120ms;
}
.voice-ref-link:hover {
color: var(--accent);
border-bottom-color: var(--accent);
}
/* performance metrics card β€” 3-column grid below the output transcript */
.metrics-card {
margin-top: 18px;
}
.metrics-header {
font-size: 11px;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 12px;
font-weight: 600;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
@media (max-width: 600px) {
.metrics-grid { grid-template-columns: 1fr; }
}
.metric {
background: var(--warli);
border: 1px solid var(--card-border);
border-radius: 8px;
padding: 12px 14px;
}
.metric-highlight {
background: var(--accent-soft);
border-color: var(--accent);
}
.metric-label {
font-size: 12px;
color: var(--muted);
margin-bottom: 6px;
}
.metric-value {
font-size: 28px;
font-weight: 600;
color: var(--ink);
line-height: 1;
font-variant-numeric: tabular-nums;
}
.metric-highlight .metric-value { color: var(--accent-dark); }
.metric-unit {
font-size: 14px;
font-weight: 400;
color: var(--muted);
margin-left: 3px;
}
.metric-context {
font-size: 10px;
color: var(--muted);
margin-top: 6px;
letter-spacing: 0.2px;
}