Files
oh-my-pi/python/robomp/web/src/styles/index.css
T
can1357 2c773a12a4 Add 'python/robomp/' from commit '553fd1cfcf59e4c501c54fc81bc083ffd2ca007b'
git-subtree-dir: python/robomp
git-subtree-mainline: 4f6e70f779
git-subtree-split: 553fd1cfcf
2026-05-16 21:00:42 +02:00

552 lines
17 KiB
CSS

@import "tailwindcss";
/* ──────────────────────────────────────────────────────────────────────────
Design tokens. Exposed both as plain CSS variables (for raw `var()` use)
and as Tailwind theme keys so utilities like `bg-surface-1`, `text-ink-100`,
`border-stroke` work without a separate config file.
────────────────────────────────────────────────────────────────────────── */
@theme {
--font-sans:
-apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
"Inter", system-ui, sans-serif;
--font-mono:
ui-monospace, "SF Mono", Menlo, Consolas, monospace;
--color-ink-50: #f8fafc;
--color-ink-100: #e8eaef;
--color-ink-200: #c6cad3;
--color-ink-300: #8b94a1;
--color-ink-400: #5e6772;
--color-ink-500: #3a4049;
--color-ink-700: #1c2026;
--color-ink-800: #14171d;
--color-ink-900: #0a0c11;
--color-ink-950: #07090c;
--color-surface-1: rgba(255, 255, 255, 0.045);
--color-surface-2: rgba(255, 255, 255, 0.075);
--color-surface-3: rgba(255, 255, 255, 0.11);
--color-stroke: rgba(255, 255, 255, 0.10);
--color-stroke-soft: rgba(255, 255, 255, 0.06);
--color-accent: #0a84ff;
--color-accent-2: #5aa9ff;
--color-ok: #30d158;
--color-warn: #ffd60a;
--color-err: #ff453a;
--color-info: #64d2ff;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 22px;
--radius-2xl: 28px;
--shadow-glass:
0 24px 60px -20px rgba(0, 0, 0, 0.55),
0 8px 24px -12px rgba(0, 0, 0, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.04);
--shadow-soft: 0 8px 24px -12px rgba(0, 0, 0, 0.45);
--blur-glass: blur(32px) saturate(180%);
}
/* ──────────────────────────────────────────────────────────────────────────
Root + page chrome. The body gradient sits behind every glass card.
────────────────────────────────────────────────────────────────────────── */
:root {
color-scheme: dark;
}
html,
body,
#app {
min-height: 100%;
margin: 0;
background-color: var(--color-ink-950);
color: var(--color-ink-100);
font-family: var(--font-sans);
font-feature-settings: "ss01", "ss03", "cv11";
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
body {
background:
radial-gradient(
120vw 70vh at 88% -12%,
rgba(10, 132, 255, 0.18),
transparent 60%
),
radial-gradient(
90vw 60vh at -10% 110%,
rgba(100, 210, 255, 0.10),
transparent 60%
),
radial-gradient(60vw 40vh at 50% 50%, rgba(20, 24, 36, 0.45), transparent 70%),
linear-gradient(180deg, #05070a 0%, #090c12 55%, #050608 100%);
background-attachment: fixed;
}
#app {
display: flex;
flex-direction: column;
}
::selection {
background: rgba(10, 132, 255, 0.45);
color: #fff;
}
a {
color: var(--color-accent-2);
text-decoration: none;
transition: color 150ms ease-out;
}
a:hover {
color: #9ec9ff;
}
/* ──────────────────────────────────────────────────────────────────────────
Reusable utility classes layered on top of Tailwind.
────────────────────────────────────────────────────────────────────────── */
.glass {
background: var(--color-surface-1);
backdrop-filter: var(--blur-glass);
-webkit-backdrop-filter: var(--blur-glass);
border: 1px solid var(--color-stroke);
box-shadow: var(--shadow-glass);
}
.glass-flat {
background: var(--color-surface-1);
border: 1px solid var(--color-stroke);
}
.hairline {
border-color: var(--color-stroke-soft);
}
.tabular {
font-variant-numeric: tabular-nums;
}
.eyebrow {
font-size: 10.5px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--color-ink-300);
}
/* ──────────────────────────────────────────────────────────────────────────
Pills — capsule status tags, tabular, hairline outline. Tints are flat
(no glow); the only colour is the text + a hairline border.
────────────────────────────────────────────────────────────────────────── */
.pill {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 500;
letter-spacing: 0.02em;
border: 1px solid var(--color-stroke);
background: rgba(255, 255, 255, 0.04);
color: var(--color-ink-200);
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.pill.queued {
color: #9ec9ff;
border-color: rgba(100, 175, 255, 0.32);
background: rgba(10, 132, 255, 0.10);
}
.pill.running {
color: #ffe26b;
border-color: rgba(255, 214, 10, 0.32);
background: rgba(255, 214, 10, 0.08);
}
.pill.done {
color: #7fe5a3;
border-color: rgba(48, 209, 88, 0.32);
background: rgba(48, 209, 88, 0.08);
}
.pill.failed {
color: #ff8e85;
border-color: rgba(255, 69, 58, 0.36);
background: rgba(255, 69, 58, 0.08);
}
.pill.skipped {
color: var(--color-ink-300);
border-color: rgba(255, 255, 255, 0.10);
background: rgba(255, 255, 255, 0.03);
}
.pill.open {
color: #9ec9ff;
border-color: rgba(100, 175, 255, 0.32);
background: rgba(10, 132, 255, 0.08);
}
.pill.closed {
color: #d8b4ff;
border-color: rgba(186, 130, 255, 0.32);
background: rgba(186, 130, 255, 0.08);
}
.pill.dot::before {
content: "";
width: 6px;
height: 6px;
border-radius: 999px;
background: currentColor;
display: inline-block;
}
/* Pulsing dot for running pills. */
.pill.running.dot::before {
animation: pulse-dot 1.8s ease-in-out infinite;
}
@keyframes pulse-dot {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.55; transform: scale(0.75); }
}
/* ──────────────────────────────────────────────────────────────────────────
Buttons.
────────────────────────────────────────────────────────────────────────── */
button,
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
font: inherit;
font-weight: 500;
padding: 7px 14px;
border-radius: 10px;
border: 1px solid var(--color-stroke);
background: var(--color-surface-1);
color: var(--color-ink-100);
cursor: pointer;
transition:
background 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out,
transform 80ms ease-out;
user-select: none;
}
button:hover:not(:disabled),
.btn:hover:not(:disabled) {
background: var(--color-surface-2);
border-color: rgba(255, 255, 255, 0.18);
}
button:active:not(:disabled),
.btn:active:not(:disabled) {
transform: translateY(1px);
}
button:disabled,
.btn:disabled {
opacity: 0.45;
cursor: not-allowed;
}
button.primary,
.btn.primary {
background: linear-gradient(180deg, #1f95ff 0%, #0a84ff 100%);
border-color: rgba(10, 132, 255, 0.7);
color: #fff;
box-shadow:
0 6px 16px -6px rgba(10, 132, 255, 0.55),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
button.primary:hover:not(:disabled),
.btn.primary:hover:not(:disabled) {
background: linear-gradient(180deg, #34a0ff 0%, #1d8eff 100%);
}
button.ghost,
.btn.ghost {
background: transparent;
border-color: transparent;
color: var(--color-ink-300);
}
button.ghost:hover:not(:disabled),
.btn.ghost:hover:not(:disabled) {
background: var(--color-surface-1);
color: var(--color-ink-100);
border-color: var(--color-stroke);
}
button.danger,
.btn.danger {
color: #ff8e85;
border-color: rgba(255, 69, 58, 0.32);
background: rgba(255, 69, 58, 0.08);
}
button.danger:hover:not(:disabled),
.btn.danger:hover:not(:disabled) {
background: rgba(255, 69, 58, 0.16);
border-color: rgba(255, 69, 58, 0.6);
color: #ffb1a8;
}
button.tiny,
.btn.tiny {
padding: 3px 9px;
font-size: 11.5px;
border-radius: 8px;
}
/* ──────────────────────────────────────────────────────────────────────────
Form controls.
────────────────────────────────────────────────────────────────────────── */
input[type="text"],
input[type="search"],
input[type="password"],
select {
font: inherit;
background: rgba(0, 0, 0, 0.28);
color: var(--color-ink-100);
border: 1px solid var(--color-stroke);
border-radius: 10px;
padding: 7px 11px;
outline: none;
transition:
border-color 150ms ease-out,
background 150ms ease-out,
box-shadow 150ms ease-out;
}
input[type="text"]::placeholder,
input[type="search"]::placeholder {
color: var(--color-ink-400);
}
input[type="text"]:focus,
input[type="search"]:focus,
input[type="password"]:focus,
select:focus {
border-color: rgba(10, 132, 255, 0.55);
box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.16);
}
select {
appearance: none;
background-image:
linear-gradient(45deg, transparent 50%, var(--color-ink-300) 50%),
linear-gradient(135deg, var(--color-ink-300) 50%, transparent 50%);
background-position:
calc(100% - 18px) calc(50% - 2px),
calc(100% - 13px) calc(50% - 2px);
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
padding-right: 30px;
}
input[type="checkbox"] {
accent-color: var(--color-accent);
}
/* ──────────────────────────────────────────────────────────────────────────
Tables.
────────────────────────────────────────────────────────────────────────── */
table.t {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-variant-numeric: tabular-nums;
font-size: 13px;
}
table.t thead th {
text-align: left;
font-size: 10.5px;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--color-ink-400);
padding: 9px 14px;
border-bottom: 1px solid var(--color-stroke);
background: rgba(255, 255, 255, 0.015);
white-space: nowrap;
}
table.t tbody td {
padding: 9px 14px;
border-bottom: 1px solid var(--color-stroke-soft);
vertical-align: top;
color: var(--color-ink-100);
}
table.t tbody tr {
transition: background 120ms ease-out;
}
table.t tbody tr:hover td {
background: rgba(255, 255, 255, 0.025);
}
table.t tbody tr:last-child td {
border-bottom: none;
}
table.t td .meta-line {
display: block;
margin-top: 2px;
color: var(--color-ink-400);
font-size: 11px;
}
.err-cell {
color: #ffa39c;
white-space: pre-wrap;
word-break: break-word;
max-width: 460px;
font-size: 12px;
}
/* ──────────────────────────────────────────────────────────────────────────
Code chips inline.
────────────────────────────────────────────────────────────────────────── */
code,
.code {
font-family: var(--font-mono);
font-size: 11.5px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--color-stroke-soft);
padding: 1px 6px;
border-radius: 6px;
color: var(--color-ink-200);
}
/* ──────────────────────────────────────────────────────────────────────────
Scrollbar styling on opt-in containers.
────────────────────────────────────────────────────────────────────────── */
.scrollable {
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.12) transparent;
}
.scrollable::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.scrollable::-webkit-scrollbar-track {
background: transparent;
}
.scrollable::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.08);
border-radius: 999px;
}
.scrollable::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.18);
}
/* ──────────────────────────────────────────────────────────────────────────
Log viewer.
────────────────────────────────────────────────────────────────────────── */
.logs {
font-family: var(--font-mono);
font-size: 11.5px;
line-height: 1.55;
max-height: 60vh;
overflow: auto;
}
.log-row {
display: grid;
grid-template-columns: 80px 60px 160px 1fr;
gap: 12px;
padding: 4px 16px;
border-bottom: 1px solid var(--color-stroke-soft);
align-items: baseline;
}
.log-row:hover {
background: rgba(255, 255, 255, 0.025);
}
.log-row .ts {
color: var(--color-ink-400);
white-space: nowrap;
}
.log-row .lvl {
font-weight: 600;
letter-spacing: 0.04em;
}
.log-row .logger {
color: var(--color-ink-400);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.log-row .msg {
white-space: pre-wrap;
word-break: break-word;
color: var(--color-ink-100);
}
.log-row .extras {
color: var(--color-ink-300);
margin-left: 6px;
}
.log-row .extras b {
color: var(--color-ink-200);
font-weight: 500;
}
.log-row .exc {
color: #ffa39c;
white-space: pre-wrap;
display: block;
margin-top: 4px;
}
.lvl.INFO { color: #6fb0ff; }
.lvl.DEBUG { color: var(--color-ink-400); }
.lvl.WARNING { color: #ffd66b; }
.lvl.ERROR { color: #ff8e85; }
.lvl.RAW { color: var(--color-ink-400); }
/* ──────────────────────────────────────────────────────────────────────────
Reveal animation for the dashboard's first paint. Honour reduced motion.
────────────────────────────────────────────────────────────────────────── */
@keyframes glass-rise {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.glass-rise {
animation: glass-rise 360ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}
/* Tighter form rows. */
.form-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
/* Card section heading. */
.section-heading {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
padding: 14px 18px 10px 18px;
}
.section-heading h2 {
font-size: 11px;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-ink-300);
margin: 0;
}
.section-heading .accessory {
font-size: 11px;
color: var(--color-ink-400);
display: flex;
align-items: center;
gap: 10px;
}
.empty {
padding: 24px;
color: var(--color-ink-400);
font-style: italic;
text-align: center;
}