ae384fe618
- tts.py: replace piper subprocess with HTTP POST to madcat-tts /v1/audio/speech (chatterbox voice cloning) - chat.js: replace whisper server upload with browser Web Speech API (webkitSpeechRecognition) - chat.css: style persona picker — appearance:none select, themed with CSS vars, mobile responsive - main.py: default TTS voice → bt7274-en
580 lines
14 KiB
CSS
580 lines
14 KiB
CSS
/* chat.saiden.dev
|
|
*
|
|
* Default look: clean, generic, neutral chat. Inter, soft grey, no cursive.
|
|
* Personality is the result of calibration, not the starting point.
|
|
*
|
|
* Once calibrated, the body gets data-* attributes:
|
|
* data-palette = default | rose | morning | evening | sage | paper | ink
|
|
* data-typography = sans | serif-warm | serif-formal | mixed-modern | mono
|
|
* data-density = airy | normal | dense
|
|
* data-labels = block | cursive | none | prefix
|
|
*
|
|
* Each combination is a different room.
|
|
*/
|
|
|
|
/* ===================== DEFAULT TOKENS (neutral) ===================== */
|
|
:root {
|
|
/* surfaces */
|
|
--bg: #f4f4f3;
|
|
--bg-soft: #ececea;
|
|
--surface: #e3e3e1;
|
|
|
|
/* text */
|
|
--ink: #1f2024;
|
|
--ink-muted: #6a6a6f;
|
|
--ink-faint: #a8a8ac;
|
|
|
|
/* accents (low-saturation by default) */
|
|
--coral: #6a6a6f; /* default accent is neutral grey */
|
|
--red: #8a4a3e;
|
|
--gold: #9a8460;
|
|
|
|
/* lines */
|
|
--line: #d6d6d3;
|
|
|
|
/* font stacks (default = sans-only) */
|
|
--serif: 'Source Serif Pro', Georgia, serif;
|
|
--serif-warm: 'Cormorant Garamond', Georgia, serif;
|
|
--hand: 'Caveat', 'Brush Script MT', cursive;
|
|
--sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
--mono: 'JetBrains Mono', Menlo, monospace;
|
|
|
|
/* derived families — overridden by data-typography */
|
|
--font-body: var(--sans);
|
|
--font-label: var(--sans);
|
|
|
|
/* spacing scale — overridden by data-density */
|
|
--msg-gap: 1.5rem;
|
|
--max-col: 36rem;
|
|
--body-size: 1rem;
|
|
--label-size: 0.72rem;
|
|
--bt-size: 1.05rem;
|
|
|
|
/* prompt baseline */
|
|
--line-thickness: 1px;
|
|
}
|
|
|
|
/* ===================== PALETTES ===================== */
|
|
|
|
body[data-palette="rose"] {
|
|
--bg: #f5ebe0;
|
|
--bg-soft: #f8e8db;
|
|
--surface: #f0d9c7;
|
|
--ink: #3d2820;
|
|
--ink-muted: #8b6f60;
|
|
--ink-faint: #b89a87;
|
|
--coral: #e07856;
|
|
--red: #c54f3d;
|
|
--line: #e8d4c0;
|
|
}
|
|
|
|
body[data-palette="morning"] {
|
|
--bg: #faf3e3;
|
|
--bg-soft: #f4ead0;
|
|
--surface: #ecdfb8;
|
|
--ink: #3a2f1a;
|
|
--ink-muted: #7a6a4a;
|
|
--ink-faint: #b6a684;
|
|
--coral: #d99b4a;
|
|
--red: #b5703a;
|
|
--line: #e7d6a8;
|
|
}
|
|
|
|
body[data-palette="evening"] {
|
|
--bg: #ece1de;
|
|
--bg-soft: #e4d2cd;
|
|
--surface: #d8bdb6;
|
|
--ink: #2e1b1d;
|
|
--ink-muted: #7d5a59;
|
|
--ink-faint: #b08c8a;
|
|
--coral: #b04a55;
|
|
--red: #84313e;
|
|
--line: #d6bbb6;
|
|
}
|
|
|
|
body[data-palette="sage"] {
|
|
--bg: #ecede4;
|
|
--bg-soft: #e1e3d4;
|
|
--surface: #cdd1bd;
|
|
--ink: #25291e;
|
|
--ink-muted: #5d6451;
|
|
--ink-faint: #97a085;
|
|
--coral: #6f8861;
|
|
--red: #58683f;
|
|
--line: #cfd4be;
|
|
}
|
|
|
|
body[data-palette="paper"] {
|
|
--bg: #f7f4ed;
|
|
--bg-soft: #efeada;
|
|
--surface: #e1d9c2;
|
|
--ink: #1d1c19;
|
|
--ink-muted: #6b6759;
|
|
--ink-faint: #a8a292;
|
|
--coral: #8b5d2f;
|
|
--red: #6a3f1b;
|
|
--line: #d8cfb6;
|
|
}
|
|
|
|
body[data-palette="ink"] {
|
|
--bg: #1d1d1f;
|
|
--bg-soft: #26262a;
|
|
--surface: #2f2f34;
|
|
--ink: #e8e6df;
|
|
--ink-muted: #9d9a90;
|
|
--ink-faint: #65635c;
|
|
--coral: #d8a572;
|
|
--red: #b87653;
|
|
--line: #353539;
|
|
}
|
|
|
|
/* ===================== TYPOGRAPHY SETS ===================== */
|
|
|
|
body[data-typography="sans"] {
|
|
--font-body: var(--sans);
|
|
--font-label: var(--sans);
|
|
}
|
|
body[data-typography="serif-warm"] {
|
|
--font-body: var(--serif-warm);
|
|
--font-label: var(--hand);
|
|
--bt-size: 1.25rem;
|
|
}
|
|
body[data-typography="serif-formal"] {
|
|
--font-body: var(--serif);
|
|
--font-label: var(--sans);
|
|
--bt-size: 1.15rem;
|
|
}
|
|
body[data-typography="mixed-modern"] {
|
|
--font-body: var(--sans);
|
|
--font-label: var(--hand);
|
|
}
|
|
body[data-typography="mono"] {
|
|
--font-body: var(--mono);
|
|
--font-label: var(--mono);
|
|
--bt-size: 0.95rem;
|
|
}
|
|
|
|
/* ===================== DENSITY ===================== */
|
|
body[data-density="airy"] { --msg-gap: 2.3rem; --max-col: 38rem; --body-size: 1.05rem; }
|
|
body[data-density="normal"] { --msg-gap: 1.5rem; --max-col: 36rem; --body-size: 1rem; }
|
|
body[data-density="dense"] { --msg-gap: 1rem; --max-col: 34rem; --body-size: 0.95rem; }
|
|
|
|
/* ===================== RESET ===================== */
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
html, body { margin: 0; padding: 0; }
|
|
html {
|
|
font-size: 16px;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
text-rendering: optimizeLegibility;
|
|
}
|
|
|
|
body {
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
font-family: var(--font-body);
|
|
font-weight: 400;
|
|
font-size: var(--body-size);
|
|
line-height: 1.55;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* ===================== LAYOUT ===================== */
|
|
.page {
|
|
max-width: var(--max-col);
|
|
margin: 0 auto;
|
|
padding: 3rem 1.5rem 0 1.5rem;
|
|
position: relative;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* ---------- top-nav strip (recalibrate · sign out · sigil) ---------- */
|
|
.topnav {
|
|
position: fixed;
|
|
top: 1.25rem;
|
|
right: 1.25rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
z-index: 10;
|
|
}
|
|
.topnav__link {
|
|
font-family: var(--sans);
|
|
font-size: 0.62rem;
|
|
font-weight: 400;
|
|
letter-spacing: 0.16em;
|
|
text-transform: uppercase;
|
|
color: var(--ink-faint);
|
|
text-decoration: none;
|
|
background: transparent;
|
|
border: none;
|
|
padding: 0;
|
|
cursor: pointer;
|
|
opacity: 0.45;
|
|
transition: opacity 400ms ease, color 400ms ease;
|
|
}
|
|
.topnav__link:hover,
|
|
.topnav__link:focus-visible {
|
|
opacity: 1;
|
|
color: var(--ink);
|
|
outline: none;
|
|
}
|
|
.topnav__link:disabled {
|
|
opacity: 0.25;
|
|
cursor: progress;
|
|
}
|
|
.topnav__sep {
|
|
color: var(--ink-faint);
|
|
opacity: 0.35;
|
|
font-size: 0.7rem;
|
|
}
|
|
|
|
.sigil {
|
|
width: 14px;
|
|
height: 14px;
|
|
opacity: 0.35;
|
|
transition: opacity 600ms ease;
|
|
user-select: none;
|
|
margin-left: 0.4rem;
|
|
}
|
|
.sigil:hover { opacity: 0.85; }
|
|
.sigil img { width: 100%; height: 100%; display: block; }
|
|
|
|
/* ---------- persona picker (inline in topnav) ---------- */
|
|
.topnav__persona-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
}
|
|
|
|
.topnav__persona-label {
|
|
font-family: var(--sans);
|
|
font-size: 0.58rem;
|
|
font-weight: 400;
|
|
letter-spacing: 0.16em;
|
|
text-transform: uppercase;
|
|
color: var(--ink-faint);
|
|
opacity: 0.45;
|
|
cursor: default;
|
|
user-select: none;
|
|
}
|
|
|
|
.topnav__persona-select {
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
border: 1px solid var(--ink-faint);
|
|
border-radius: 3px;
|
|
background: var(--bg-soft);
|
|
color: var(--ink-muted);
|
|
font-family: var(--sans);
|
|
font-size: 0.62rem;
|
|
font-weight: 400;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
padding: 0.2rem 1.3rem 0.2rem 0.45rem;
|
|
cursor: pointer;
|
|
outline: none;
|
|
opacity: 0.55;
|
|
transition: opacity 400ms ease, color 400ms ease, border-color 400ms ease;
|
|
|
|
/* custom dropdown arrow */
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' fill='none'%3E%3Cpath d='M1 1l3 3 3-3' stroke='%236a6a6f' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 0.4rem center;
|
|
}
|
|
.topnav__persona-select:hover {
|
|
opacity: 1;
|
|
color: var(--ink);
|
|
border-color: var(--ink-muted);
|
|
}
|
|
.topnav__persona-select:focus-visible {
|
|
opacity: 1;
|
|
color: var(--ink);
|
|
border-color: var(--coral);
|
|
}
|
|
|
|
.topnav__persona-status {
|
|
font-family: var(--sans);
|
|
font-size: 0.58rem;
|
|
font-weight: 400;
|
|
letter-spacing: 0.12em;
|
|
color: var(--coral);
|
|
opacity: 0.7;
|
|
transition: opacity 400ms ease;
|
|
user-select: none;
|
|
}
|
|
.topnav__persona-status:empty { display: none; }
|
|
|
|
@media (max-width: 600px) {
|
|
.topnav__persona-label { display: none; }
|
|
.topnav__persona-select { font-size: 0.58rem; padding: 0.15rem 1.1rem 0.15rem 0.35rem; }
|
|
}
|
|
|
|
/* ===================== CONVERSATION ===================== */
|
|
.conversation {
|
|
flex: 1 0 auto;
|
|
padding-bottom: 2rem;
|
|
}
|
|
|
|
.msg {
|
|
margin: var(--msg-gap) 0;
|
|
opacity: 0;
|
|
transform: translateY(6px);
|
|
animation: appear 500ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
}
|
|
|
|
.msg__label {
|
|
font-family: var(--font-label);
|
|
font-weight: 400;
|
|
color: var(--ink-muted);
|
|
font-size: var(--label-size);
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 0.45rem;
|
|
user-select: none;
|
|
}
|
|
|
|
/* Cursive label override */
|
|
body[data-labels="cursive"] .msg__label {
|
|
font-family: var(--hand);
|
|
font-size: 1rem;
|
|
letter-spacing: 0.01em;
|
|
text-transform: none;
|
|
}
|
|
body[data-labels="none"] .msg__label { display: none; }
|
|
body[data-labels="prefix"] .msg__label {
|
|
display: inline;
|
|
margin-right: 0.5em;
|
|
font-weight: 600;
|
|
text-transform: none;
|
|
}
|
|
|
|
.msg__body {
|
|
color: var(--ink);
|
|
font-size: var(--bt-size);
|
|
line-height: 1.6;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
.msg--user .msg__body {
|
|
color: var(--ink-muted);
|
|
font-size: var(--body-size);
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.msg--system .msg__body {
|
|
color: var(--ink-faint);
|
|
font-size: 0.74rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.16em;
|
|
font-family: var(--sans);
|
|
font-weight: 300;
|
|
}
|
|
.msg--system .msg__label { display: none; }
|
|
|
|
.msg--calibration .msg__body {
|
|
color: var(--ink);
|
|
font-size: calc(var(--bt-size) * 1.02);
|
|
font-style: italic;
|
|
line-height: 1.65;
|
|
}
|
|
.msg--calibration .msg__label { display: none; }
|
|
.msg--calibration { margin: 1.5rem 0; }
|
|
|
|
/* repeat-label hide */
|
|
.msg[data-hide-label="true"] .msg__label { display: none; }
|
|
.msg[data-hide-label="true"] { margin-top: 0.8rem; }
|
|
|
|
/* ===================== THINKING ===================== */
|
|
.thinking {
|
|
color: var(--coral);
|
|
font-size: 0.65rem;
|
|
margin: 1.5rem 0;
|
|
user-select: none;
|
|
animation: pulse 1.8s ease-in-out infinite;
|
|
}
|
|
.thinking::before { content: "●"; }
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 0.30; }
|
|
50% { opacity: 1.0; }
|
|
}
|
|
@keyframes appear {
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
/* typewriter cursor */
|
|
.caret {
|
|
display: inline-block;
|
|
width: 0.5ch;
|
|
margin-left: 0.05ch;
|
|
color: var(--coral);
|
|
animation: caret 800ms ease-out forwards;
|
|
}
|
|
.caret::after { content: "▍"; }
|
|
@keyframes caret {
|
|
0% { opacity: 1; }
|
|
100% { opacity: 0; }
|
|
}
|
|
|
|
/* ===================== PROMPT ===================== */
|
|
.prompt {
|
|
position: sticky;
|
|
bottom: 0;
|
|
background: var(--bg);
|
|
padding: 1.5rem 0 2.5rem 0;
|
|
z-index: 5;
|
|
}
|
|
.prompt__line {
|
|
border: none;
|
|
border-top: var(--line-thickness) solid var(--line);
|
|
margin: 0 0 0.85rem 0;
|
|
}
|
|
.prompt__row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
.prompt__input {
|
|
flex: 1;
|
|
border: none;
|
|
background: transparent;
|
|
outline: none;
|
|
font-family: var(--font-body);
|
|
font-weight: 400;
|
|
font-size: var(--body-size);
|
|
color: var(--ink);
|
|
padding: 0;
|
|
min-width: 0;
|
|
}
|
|
.prompt__input::placeholder {
|
|
color: var(--ink-faint);
|
|
font-style: italic;
|
|
}
|
|
.prompt__input:focus { caret-color: var(--coral); }
|
|
|
|
/* ===================== MIC ===================== */
|
|
.prompt__mic {
|
|
background: transparent;
|
|
border: none;
|
|
cursor: pointer;
|
|
color: var(--ink-faint);
|
|
padding: 0.4rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
transition: color 200ms ease, background 200ms ease, transform 200ms ease;
|
|
}
|
|
.prompt__mic:hover { color: var(--ink-muted); }
|
|
.prompt__mic:active { transform: scale(0.95); }
|
|
.prompt__mic.recording {
|
|
color: var(--coral);
|
|
background: rgba(0, 0, 0, 0.04);
|
|
animation: mic-pulse 1.2s ease-in-out infinite;
|
|
}
|
|
.prompt__mic.transcribing {
|
|
color: var(--gold);
|
|
animation: mic-spin 1.2s linear infinite;
|
|
}
|
|
.prompt__mic.empty {
|
|
color: var(--red);
|
|
animation: mic-empty 0.7s ease;
|
|
}
|
|
@keyframes mic-pulse {
|
|
0%, 100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.18); }
|
|
50% { box-shadow: 0 0 0 8px rgba(0, 0, 0, 0); }
|
|
}
|
|
@keyframes mic-spin { to { transform: rotate(360deg); } }
|
|
@keyframes mic-empty {
|
|
0% { transform: translateX(0); }
|
|
20% { transform: translateX(-2px); }
|
|
40% { transform: translateX(2px); }
|
|
60% { transform: translateX(-2px); }
|
|
80% { transform: translateX(2px); }
|
|
100% { transform: translateX(0); }
|
|
}
|
|
|
|
/* ===================== CHOICE TILES ===================== */
|
|
.choices {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.55rem;
|
|
margin: 1rem 0 0.25rem 0;
|
|
}
|
|
.choice {
|
|
background: var(--bg-soft);
|
|
border: 1px solid var(--line);
|
|
color: var(--ink);
|
|
font-family: var(--font-body);
|
|
font-size: 0.95rem;
|
|
font-style: normal;
|
|
padding: 0.5rem 0.95rem;
|
|
border-radius: 999px;
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
transition: background 220ms ease, color 220ms ease,
|
|
border-color 220ms ease, transform 220ms ease, opacity 220ms ease;
|
|
}
|
|
.choice:hover {
|
|
background: var(--surface);
|
|
border-color: var(--coral);
|
|
}
|
|
.choice:active { transform: scale(0.97); }
|
|
.choice:disabled { cursor: default; opacity: 0.45; }
|
|
.choice--selected {
|
|
background: var(--coral);
|
|
color: var(--bg);
|
|
border-color: var(--coral);
|
|
opacity: 1 !important;
|
|
}
|
|
.choice--other {
|
|
font-style: italic;
|
|
color: var(--ink-muted);
|
|
background: transparent;
|
|
}
|
|
.choice__icon { font-size: 1.05rem; line-height: 1; display: inline-flex; }
|
|
.choice__label { line-height: 1; }
|
|
|
|
/* ===================== DENIED PAGE ===================== */
|
|
.denied {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 100vh;
|
|
padding: 2rem;
|
|
text-align: center;
|
|
}
|
|
.denied__title {
|
|
font-family: var(--font-body);
|
|
font-size: 1.7rem;
|
|
color: var(--ink);
|
|
font-weight: 500;
|
|
margin: 0 0 1rem 0;
|
|
}
|
|
.denied__body {
|
|
font-family: var(--font-body);
|
|
font-size: 1rem;
|
|
color: var(--ink-muted);
|
|
max-width: 28rem;
|
|
line-height: 1.6;
|
|
}
|
|
.denied__link {
|
|
font-family: var(--sans);
|
|
font-size: 0.78rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.14em;
|
|
color: var(--red);
|
|
text-decoration: none;
|
|
margin-top: 3rem;
|
|
display: inline-block;
|
|
border-bottom: 1px solid var(--line);
|
|
padding-bottom: 0.15rem;
|
|
}
|
|
.denied__link:hover { border-color: var(--red); }
|