Files
spark-control/image/app/static/style.css
T
Keysat 3d273223f2 v0.11.0:2 - pill sizing fix: match .tag exactly to .status "Healthy" pill
User feedback: every pill outside the Always-On Services cards was rendering
visually taller than the "Healthy" status pill they liked. Root cause was
the .tag additions in 0.11.0:1 (line-height: 1.5, display: inline-block)
that didn't match the .status pill on service cards (which has neither).

Dropped both additions, bumped font-size from 11px → 12px so .tag is now
pixel-identical to .status:
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);

Every pill on the dashboard (mode-cluster/mode-solo/cap/on-disk/not-on-disk/
custom-pill/.tag.ok/.tag.warn/.tag.bad) now renders at the same footprint
as the Healthy/Unhealthy/Starting pills on the service cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:46:57 -05:00

908 lines
26 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:root {
--bg: #0a0a0d;
--surface: #15151a;
--surface-2: #1c1c22;
--border: #25252c;
--text: #e6e6ea;
--muted: #7e7e8a;
--accent: #4ade80;
--warn: #f59e0b;
--error: #ef4444;
--info: #60a5fa;
--radius: 10px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
min-height: 100vh;
-webkit-font-smoothing: antialiased;
}
.muted { color: var(--muted); }
.small { font-size: 13px; }
.hidden { display: none !important; }
.spacer { flex: 1; }
.topbar {
position: sticky;
top: 0;
background: rgba(10, 10, 13, 0.85);
backdrop-filter: saturate(160%) blur(10px);
-webkit-backdrop-filter: saturate(160%) blur(10px);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 16px;
padding: 12px 20px;
z-index: 10;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 600; }
.logo-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 12px var(--accent); }
.current { flex: 1; text-align: right; font-size: 14px; }
.current strong { color: var(--accent); }
.topbar-btn {
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--text);
padding: 5px 10px;
border-radius: 6px;
font-size: 12px;
text-decoration: none;
transition: border-color 0.15s, background 0.15s;
}
.topbar-btn:hover { background: #24242c; border-color: var(--accent); color: var(--accent); }
main {
max-width: 880px;
margin: 0 auto;
padding: 24px 20px 80px;
}
.banner {
background: var(--surface);
border: 1px solid var(--warn);
color: var(--warn);
padding: 12px 16px;
border-radius: var(--radius);
margin-bottom: 16px;
font-size: 14px;
}
.banner em { font-style: normal; background: rgba(245, 158, 11, 0.15); padding: 2px 6px; border-radius: 4px; }
/* ===== Endpoint panel ===== */
.endpoint-panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 12px 16px;
margin-bottom: 16px;
}
.ep-title { margin-bottom: 8px; letter-spacing: 0.05em; text-transform: uppercase; }
.ep-row {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 0;
}
.ep-row + .ep-row { border-top: 1px solid var(--border); }
.ep-label {
color: var(--muted);
font-size: 12px;
min-width: 78px;
flex-shrink: 0;
}
.ep-value {
flex: 1;
font: 13px/1.4 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
background: var(--surface-2);
padding: 4px 8px;
border-radius: 5px;
border: 1px solid var(--border);
color: var(--text);
overflow-x: auto;
white-space: nowrap;
}
.copy-btn,
.icon-btn {
appearance: none;
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--muted);
padding: 4px 10px;
border-radius: 5px;
font: 12px/1 inherit;
cursor: pointer;
transition: color 0.15s, border-color 0.15s, background 0.15s;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
}
.icon-btn { padding: 5px 7px; }
.icon-btn svg { width: 14px; height: 14px; display: block; }
.copy-btn:hover,
.icon-btn:hover { color: var(--text); border-color: #34343c; }
.copy-btn.copied,
.icon-btn.copied {
color: var(--accent);
border-color: rgba(74, 222, 128, 0.4);
background: rgba(74, 222, 128, 0.08);
}
.icon-btn.copied svg { color: var(--accent); }
.copy-btn.small { padding: 3px 8px; font-size: 11px; }
.copyable { cursor: pointer; }
.copyable:hover { outline: 1px solid rgba(96, 165, 250, 0.5); }
.copyable.copied { outline: 1px solid var(--accent); background: rgba(74, 222, 128, 0.05); }
.ep-curl { margin-top: 8px; }
.ep-curl summary { cursor: pointer; padding: 4px 0; }
.ep-curl[open] summary { margin-bottom: 6px; }
.snippet {
background: #08080b;
border: 1px solid var(--border);
border-radius: 6px;
padding: 10px 12px;
margin: 0 0 8px;
font: 12px/1.55 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
color: #c7c7d1;
max-height: 200px;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
}
/* ===== Swap panel ===== */
.swap-panel {
background: var(--surface);
border: 1px solid var(--info);
border-radius: var(--radius);
padding: 16px 18px;
margin-bottom: 20px;
}
.swap-header { display: flex; align-items: center; gap: 12px; }
.swap-header #swap-title { font-weight: 600; color: var(--info); }
.timer {
font: 14px/1 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
background: var(--surface-2);
border: 1px solid var(--border);
padding: 5px 10px;
border-radius: 6px;
color: var(--text);
letter-spacing: 0.04em;
}
.spinner {
width: 14px; height: 14px;
border: 2px solid var(--info);
border-right-color: transparent;
border-radius: 50%;
animation: spin 0.8s linear infinite;
flex-shrink: 0;
}
@keyframes spin { to { transform: rotate(360deg); } }
.phase-row {
display: flex;
align-items: baseline;
gap: 10px;
margin-top: 14px;
}
.phase {
font-size: 16px;
font-weight: 500;
color: var(--text);
}
.phase-detail { font-size: 13px; }
.phase-track {
margin-top: 10px;
height: 6px;
background: var(--surface-2);
border-radius: 3px;
overflow: hidden;
}
.phase-fill {
height: 100%;
width: 2%;
background: linear-gradient(90deg, var(--info), var(--accent));
border-radius: 3px;
transition: width 0.5s ease-out;
}
#swap-log-details {
margin-top: 14px;
}
#swap-log-details summary {
cursor: pointer;
user-select: none;
padding: 2px 0;
}
#swap-log-details summary:hover { color: var(--text); }
#swap-log-details[open] summary { margin-bottom: 8px; }
.log {
background: #08080b;
border: 1px solid var(--border);
border-radius: 6px;
padding: 10px 12px;
margin: 0;
font: 12px/1.55 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
color: #c7c7d1;
max-height: 260px;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
}
/* ===== Modal dialogs (Advanced / Add to catalog) ===== */
.modal {
background: var(--surface);
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 0;
max-width: 520px;
width: 92vw;
}
.modal::backdrop {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(2px);
}
.modal-form { padding: 22px 24px; display: flex; flex-direction: column; gap: 12px; }
.modal-form h3 { margin: 0; font-size: 17px; }
.modal-row {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 13px;
color: var(--muted);
}
.modal-row.inline { flex-direction: row; align-items: center; gap: 8px; color: var(--text); font-size: 14px; }
.modal-row > span { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; }
.modal-row input[type='text'],
.modal-row input[type='number'],
.modal-row textarea,
.modal-row select {
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--text);
padding: 7px 10px;
border-radius: 6px;
font: 13px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
.modal-row textarea { font-family: inherit; resize: vertical; }
.modal-row .knob-hint {
color: var(--muted);
font-size: 11px;
line-height: 1.5;
margin-top: 2px;
padding-left: 2px;
}
.modal-row.inline .knob-hint { width: 100%; margin-left: 22px; margin-top: 0; }
.modal-row input:focus, .modal-row textarea:focus, .modal-row select:focus { outline: 1px solid var(--info); border-color: var(--info); }
.modal-row input[type='range'] { padding: 0; flex: 1; }
.modal-fieldset {
border: 1px solid var(--border);
border-radius: 6px;
padding: 12px 14px 4px;
display: flex;
flex-direction: column;
gap: 10px;
}
.modal-fieldset legend { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; padding: 0 6px; }
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 8px; align-items: center; }
/* ===== Update banner ===== */
.update-banner {
background: var(--surface);
border: 1px solid rgba(96, 165, 250, 0.4);
border-radius: var(--radius);
padding: 12px 14px;
margin-top: 18px;
font-size: 13px;
}
.ub-context { margin-bottom: 8px; line-height: 1.5; }
.ub-context a { color: var(--info); text-decoration: none; }
.ub-context a:hover { text-decoration: underline; }
.ub-context em { font-style: normal; color: var(--text); font-weight: 500; }
#ub-explain-section { margin-top: 8px; }
#ub-explain-section summary { cursor: pointer; padding: 4px 0; }
.explain-content {
background: #08080b;
border: 1px solid var(--border);
border-radius: 6px;
padding: 12px 14px;
margin-top: 8px;
font-size: 13px;
line-height: 1.6;
color: #c7c7d1;
white-space: pre-wrap;
word-break: break-word;
max-height: 320px;
overflow: auto;
}
.explain-content .reasoning {
color: var(--muted);
font-style: italic;
font-size: 11px;
border-left: 2px solid var(--border);
padding-left: 10px;
margin: 4px 0;
}
.update-banner.up-to-date {
border-color: var(--border);
color: var(--muted);
}
.update-banner.warn { border-color: var(--warn); }
.ub-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ub-row .spacer { flex: 1; }
#ub-list { margin-top: 8px; }
#ub-list summary { cursor: pointer; padding: 4px 0; }
#ub-progress { margin-top: 10px; }
/* ===== Hardware dashboard ===== */
.hardware-grid {
display: grid;
gap: 14px;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.hw-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.hw-card .head {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 4px;
}
.hw-card .head .name { font-weight: 600; font-size: 15px; }
.hw-card .head .meta { color: var(--muted); font-size: 12px; margin-left: auto; }
.hw-card.unreachable { border-color: rgba(239, 68, 68, 0.4); }
.hw-card.unreachable .name { color: var(--error); }
.hw-card.unreachable ol { color: var(--muted); }
.hw-card .wol-row {
margin-top: 8px;
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--muted);
}
.hw-card .wol-row .btn { padding: 5px 10px; font-size: 12px; }
.hw-card .mac-display { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.connectivity-content {
max-height: 360px;
overflow-y: auto;
border: 1px solid var(--border);
border-radius: 6px;
padding: 10px;
background: var(--surface-2);
}
.conn-spark { margin-bottom: 16px; }
.conn-spark h4 { font-size: 13px; margin: 0 0 8px; color: var(--text); }
.conn-event {
font-size: 12px;
display: flex;
gap: 10px;
padding: 4px 0;
border-bottom: 1px solid rgba(255,255,255,0.04);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.conn-event:last-child { border-bottom: 0; }
.conn-event .when { color: var(--muted); flex-shrink: 0; }
.conn-event .what { flex: 1; }
.conn-event.up .what { color: var(--accent); }
.conn-event.down .what { color: var(--error); }
.conn-event.report .what { font-style: italic; }
.conn-event .muted { color: var(--muted); font-style: normal; }
.conn-event .dur { color: var(--muted); }
.conn-summary { color: var(--muted); font-size: 11px; padding: 4px 0 10px; }
.hw-metric { display: flex; align-items: center; gap: 10px; font-size: 12px; }
.hw-metric .label { color: var(--muted); width: 56px; flex-shrink: 0; text-transform: uppercase; letter-spacing: 0.05em; font-size: 11px; }
.hw-metric .bar { flex: 1; height: 8px; background: var(--surface-2); border-radius: 4px; overflow: hidden; position: relative; }
.hw-metric .bar > span {
display: block;
height: 100%;
background: linear-gradient(90deg, var(--info), var(--accent));
border-radius: 4px;
transition: width 0.4s ease-out;
}
.hw-metric .bar.warn > span { background: linear-gradient(90deg, var(--warn), var(--error)); }
.hw-metric .val {
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
font-size: 12px;
color: var(--text);
min-width: 110px;
text-align: right;
}
/* ===== Section header (title + action button) ===== */
.section-header {
display: flex;
align-items: center;
gap: 12px;
margin: 24px 0 12px;
}
.section-header .section-title { margin: 0; }
.section-header .spacer { flex: 1; }
.section-header .small-btn,
.btn.small-btn {
margin-left: auto;
padding: 5px 12px;
font-size: 12px;
}
/* ===== Download panel ===== */
.download-panel {
background: var(--surface);
border: 1px solid var(--info);
border-radius: var(--radius);
padding: 14px 16px;
margin-bottom: 16px;
}
.download-form .dl-row {
display: flex;
align-items: center;
gap: 12px;
padding: 6px 0;
flex-wrap: wrap;
}
.dl-label {
color: var(--muted);
font-size: 12px;
min-width: 110px;
flex-shrink: 0;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.dl-row input[type='text'] {
flex: 1;
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--text);
padding: 7px 10px;
border-radius: 6px;
font: 13px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
min-width: 200px;
}
.dl-row input[type='text']:focus { outline: 1px solid var(--info); border-color: var(--info); }
.dl-hf-link {
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--info);
padding: 7px 10px;
border-radius: 6px;
text-decoration: none;
font-size: 14px;
flex-shrink: 0;
}
.dl-hf-link:hover { background: rgba(96, 165, 250, 0.08); border-color: var(--info); }
.dl-help { padding-left: 122px; line-height: 1.6; }
.dl-help a { color: var(--info); text-decoration: none; }
.dl-help a:hover { text-decoration: underline; }
.dl-help code { background: var(--surface-2); padding: 1px 5px; border-radius: 3px; font-size: 11px; }
.radio { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text); cursor: pointer; }
.radio input { accent-color: var(--accent); }
.dl-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.dl-stats {
margin-top: 8px;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
.dl-header { display: flex; align-items: center; gap: 12px; }
.dl-header #dl-title { font-weight: 600; color: var(--info); }
#dl-log-details { margin-top: 12px; }
#dl-log-details summary { cursor: pointer; padding: 4px 0; }
/* ===== NIM install dialog ===== */
.modal#nim-dialog,
.modal#nim-progress-dialog { max-width: 640px; }
.nim-grid {
display: grid;
gap: 8px;
grid-template-columns: 1fr;
max-height: 240px;
overflow-y: auto;
margin-bottom: 4px;
}
.nim-card {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 6px;
padding: 10px 12px;
display: flex;
gap: 10px;
align-items: flex-start;
}
.nim-card .info { flex: 1; }
.nim-card .name { font-weight: 600; font-size: 13px; }
.nim-card .desc { color: var(--muted); font-size: 12px; margin-top: 4px; }
.nim-card .img { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: #6b6b75; font-size: 11px; margin-top: 4px; word-break: break-all; }
.nim-card .btn { padding: 6px 12px; font-size: 12px; flex-shrink: 0; }
.nim-card .links { font-size: 11px; margin-top: 4px; }
.nim-card .links a { color: var(--info); text-decoration: none; }
.nim-card .links a:hover { text-decoration: underline; }
.nim-key-warn { color: var(--warn); }
/* ===== Section titles ===== */
.section-title {
font-size: 13px;
font-weight: 500;
color: var(--muted);
margin: 24px 0 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.section-title:first-child { margin-top: 0; }
/* ===== Services panel ===== */
.services-grid {
display: grid;
gap: 14px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.service-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.service-card.running { border-color: rgba(74, 222, 128, 0.45); }
.service-card.unhealthy { border-color: rgba(239, 68, 68, 0.55); }
.service-card.missing,
.service-card.unconfigured { border-color: rgba(245, 158, 11, 0.45); }
.service-card .head {
display: flex;
align-items: center;
gap: 8px;
}
.service-card .head .name { font-weight: 600; font-size: 15px; }
.service-card .head .kind { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.service-card .head .status {
margin-left: auto;
font-size: 12px;
padding: 2px 8px;
border-radius: 999px;
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--muted);
}
.service-card.running .status { color: var(--accent); border-color: rgba(74, 222, 128, 0.4); }
.service-card.unhealthy .status { color: var(--error); border-color: rgba(239, 68, 68, 0.4); }
.service-card.missing .status,
.service-card.unconfigured .status { color: var(--warn); border-color: rgba(245, 158, 11, 0.4); }
.service-card .row {
display: flex;
align-items: center;
font-size: 12px;
color: var(--muted);
gap: 6px;
}
.service-card .row .k { width: 60px; flex-shrink: 0; }
.service-card .row .v {
color: var(--text);
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
word-break: break-all;
flex: 1;
padding: 2px 4px;
border-radius: 4px;
}
.service-card .row .v.muted-v { color: var(--muted); font-family: inherit; }
.service-card .row .v.copyable:hover { outline: 1px solid rgba(96, 165, 250, 0.5); }
.service-card .row .v.copyable.copied { outline: 1px solid var(--accent); background: rgba(74, 222, 128, 0.05); }
.service-card .row .icon-btn { padding: 3px 6px; }
.service-card .row .icon-btn svg { width: 12px; height: 12px; }
.service-card .deep-row .deep-v { display: flex; align-items: center; gap: 6px; font-family: inherit; flex-wrap: wrap; }
.service-card .dh-ok { color: var(--accent); }
.service-card .dh-fail { color: var(--error); font-weight: 500; }
.service-card .dh-run-btn { font-family: inherit; }
.service-card .deep-error {
padding: 4px 8px;
background: rgba(239, 68, 68, 0.06);
border-left: 2px solid var(--error);
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 11px;
word-break: break-word;
}
.service-actions {
display: flex;
gap: 6px;
margin-top: 4px;
}
.service-actions .btn { padding: 6px 12px; font-size: 12px; flex: 1; }
.service-actions .btn.danger { color: var(--error); border-color: rgba(239, 68, 68, 0.3); }
.service-actions .btn.danger:hover:not(:disabled) { background: rgba(239, 68, 68, 0.08); border-color: var(--error); }
/* ===== Cards ===== */
.cards {
display: grid;
gap: 14px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
transition: border-color 0.15s, transform 0.15s;
}
.card.active {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent) inset, 0 0 24px rgba(74, 222, 128, 0.08);
}
.card .name { font-weight: 600; font-size: 15px; }
.card .meta { display: flex; flex-wrap: wrap; gap: 6px; font-size: 12px; color: var(--muted); }
.card .desc {
font-size: 13.5px;
line-height: 1.5;
color: #b9b9c4;
}
.card .repo {
word-break: break-all;
font-size: 11px;
color: #5c5c66;
}
.card .repo a { color: inherit; text-decoration: none; }
.card .repo a:hover { color: var(--info); text-decoration: underline; }
.card .repo .hf-icon { font-size: 13px; opacity: 0.7; }
.tag {
background: var(--surface-2);
border: 1px solid var(--border);
padding: 2px 8px;
border-radius: 999px;
font-size: 12px;
}
.tag.mode-cluster { color: var(--info); border-color: rgba(96, 165, 250, 0.4); }
.tag.mode-solo { color: var(--accent); border-color: rgba(74, 222, 128, 0.4); }
.tag.cap { color: var(--muted); }
/* Semantic status pills — reuse .tag sizing so every pill on the page
renders at the same 11px / 2px×8px footprint. */
.tag.ok { color: var(--accent); border-color: rgba(74, 222, 128, 0.4); }
.tag.warn { color: var(--warn); border-color: rgba(245, 158, 11, 0.4); }
.tag.bad { color: var(--error); border-color: rgba(239, 68, 68, 0.4); }
.btn {
appearance: none;
border: 1px solid var(--border);
background: var(--surface-2);
color: var(--text);
padding: 8px 14px;
border-radius: 8px;
cursor: pointer;
font: inherit;
font-weight: 500;
transition: background 0.15s, border-color 0.15s, opacity 0.15s;
}
.btn:hover:not(:disabled) { background: #24242c; border-color: #34343c; }
.btn.primary { background: var(--accent); color: #052e16; border-color: var(--accent); }
.btn.primary:hover:not(:disabled) { background: #6ee19a; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.danger { color: var(--error); border-color: rgba(239, 68, 68, 0.3); }
.btn.danger:hover:not(:disabled) { background: rgba(239, 68, 68, 0.08); border-color: var(--error); }
.btn.info { background: var(--info); color: #0a1e3d; border-color: var(--info); }
.btn.info:hover:not(:disabled) { background: #82baff; border-color: #82baff; }
.card.active .btn { background: rgba(74, 222, 128, 0.12); color: var(--accent); border-color: rgba(74, 222, 128, 0.4); }
.card-actions { display: flex; gap: 6px; }
.card-actions .btn.primary,
.card-actions .btn.info { flex: 1; }
.card .adv-btn,
.card .test-btn { padding: 8px 12px; font-size: 12px; }
.card .custom-pill { color: var(--info); border-color: rgba(96, 165, 250, 0.4); }
.tag.on-disk { color: var(--accent); border-color: rgba(74, 222, 128, 0.4); }
.tag.not-on-disk { color: var(--muted); border-color: var(--border); opacity: 0.7; }
.card-actions .icon-btn.danger { color: var(--error); border-color: rgba(239, 68, 68, 0.3); margin-left: auto; }
.card-actions .icon-btn.danger:hover:not(:disabled) { background: rgba(239, 68, 68, 0.08); border-color: var(--error); color: var(--error); }
.card-actions .icon-btn.danger:disabled { opacity: 0.35; cursor: not-allowed; }
.dd-hosts { padding-left: 18px; margin: 4px 0 8px; }
.dd-hosts code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
.dd-error { color: var(--error); }
.test-result {
font-size: 12px;
line-height: 1.45;
padding: 8px 10px;
border-radius: 5px;
margin-top: 4px;
border: 1px solid var(--border);
background: var(--surface-2);
}
.test-result.ok { border-color: rgba(74, 222, 128, 0.4); background: rgba(74, 222, 128, 0.04); }
.test-result.fail { border-color: rgba(239, 68, 68, 0.45); background: rgba(239, 68, 68, 0.06); word-break: break-word; }
.test-result .ok-mark { color: var(--accent); font-weight: 600; }
.test-result .fail-mark { color: var(--error); font-weight: 600; }
.footer {
margin-top: 28px;
padding-top: 16px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
gap: 14px;
flex-wrap: wrap;
}
.health { display: flex; gap: 14px; flex-wrap: wrap; }
.health-item { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); display: inline-block; }
.dot.ok { background: var(--accent); box-shadow: 0 0 8px rgba(74, 222, 128, 0.7); }
.dot.bad { background: var(--error); box-shadow: 0 0 8px rgba(239, 68, 68, 0.7); }
.dot.warn { background: var(--warn); }
@media (max-width: 640px) {
.topbar { padding: 10px 14px; }
main { padding: 16px 14px 80px; }
.cards { grid-template-columns: 1fr; }
}
/* ===== Speech model patches (v0.11) ===== */
.speech-models { margin-top: 28px; }
.sm-blurb { max-width: 880px; margin-bottom: 14px; }
.sm-blurb code {
background: var(--surface-2);
padding: 1px 6px;
border-radius: 4px;
font-size: 12px;
}
.speech-models-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 14px;
}
.sm-header {
display: flex;
align-items: center;
gap: 10px;
}
.sm-title {
font-weight: 600;
color: var(--text);
}
/* .sm-pill removed in v0.11.0:1 — speech-models pills now reuse the shared
.tag styling (+ .tag.ok / .tag.warn / .tag.bad color modifiers) so every
pill on the page renders identically. */
.sm-models { display: flex; flex-direction: column; gap: 6px; }
.sm-model-row {
display: grid;
grid-template-columns: 160px 1fr auto;
align-items: center;
gap: 12px;
padding: 6px 0;
border-top: 1px solid var(--border);
}
.sm-model-row:first-child { border-top: none; }
.sm-model-kind { color: var(--muted); font-size: 13px; }
.sm-model-name { font-family: ui-monospace, monospace; font-size: 12px; word-break: break-all; }
.sm-files { display: flex; flex-direction: column; gap: 4px; }
.sm-file-row {
display: grid;
grid-template-columns: 160px 100px 1fr;
gap: 12px;
font-size: 12px;
padding: 4px 0;
}
.sm-file-name code {
background: var(--surface-2);
padding: 1px 6px;
border-radius: 4px;
}
.sm-file-ok { color: var(--accent); }
.sm-file-warn { color: var(--warn); }
.sm-file-bad { color: var(--error); }
.sm-file-sha code {
background: var(--surface-2);
padding: 1px 4px;
border-radius: 3px;
font-size: 11px;
}
.sm-meta { margin-top: 4px; }
.sm-actions { display: flex; gap: 10px; }
.sm-prog-steps {
display: flex;
flex-direction: column;
gap: 6px;
margin: 12px 0;
font-size: 13px;
}
.sm-prog-step {
padding: 6px 10px;
background: var(--surface-2);
border-radius: 6px;
}
.sm-prog-done {
font-weight: 600;
margin-top: 8px;
}
/* ===== Collapsible endpoint card (v0.11.0:1) ===== */
.endpoint-panel .ep-header {
display: flex;
align-items: center;
gap: 10px;
}
.endpoint-panel .ep-title { flex: 1; margin: 0; }
.endpoint-panel .ep-collapse-btn {
flex-shrink: 0;
transition: transform 0.2s;
}
.endpoint-panel.collapsed .ep-body { display: none; }
.endpoint-panel.collapsed .ep-collapse-btn svg { transform: rotate(-90deg); }
.endpoint-panel:not(.collapsed) .ep-header { margin-bottom: 10px; }
/* ===== Dashboard tabs (LLM / Audio) (v0.11.0:1) ===== */
.dashboard-tabs {
display: flex;
gap: 4px;
margin-top: 8px;
margin-bottom: 16px;
border-bottom: 1px solid var(--border);
padding: 0 2px;
}
.dashboard-tab {
appearance: none;
background: transparent;
border: 1px solid transparent;
border-bottom: none;
color: var(--muted);
padding: 8px 16px;
border-radius: 6px 6px 0 0;
cursor: pointer;
font: inherit;
font-size: 14px;
font-weight: 500;
margin-bottom: -1px;
transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.dashboard-tab:hover { color: var(--text); }
.dashboard-tab.active {
color: var(--text);
background: var(--surface);
border-color: var(--border);
border-bottom: 1px solid var(--surface);
}
.tab-content { display: none; }
.tab-content.active { display: block; }