5117168454
A real shell on the chat's own connection, opened and closed like the inspector and never beside it. The modes govern the model; what a person types is theirs, since they hold the credential and could open the same shell with an ssh client. The model cannot see the panel -- a button copies the output you choose into the composer. The session outlives the socket: closing the panel leaves a build running, and coming back reattaches with the scrollback. Two tabs share one shell and the smaller window decides the size. It ends on an idle timeout, on deleting the chat, on disabling, moving or deleting the connection, and on a restart -- which says why rather than quietly opening a fresh shell that has lost the working directory. The nginx template's `Connection ""` is right for SSE and fails every WebSocket handshake, so `location /` now uses a `map $http_upgrade`; update.sh grows a drift check for it, because the only symptom on a stale vhost is a panel that cannot connect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
219 lines
6.2 KiB
CSS
219 lines
6.2 KiB
CSS
/*
|
|
Design tokens.
|
|
|
|
Every colour, space and radius in the application resolves through a variable
|
|
declared here. Component CSS must never hard-code a hex value -- that is what
|
|
makes adding a theme a matter of writing one new block rather than auditing
|
|
every stylesheet.
|
|
|
|
Themes are selected with data-theme on <html>. `moria` is the default and is
|
|
declared on :root so the page is styled even before the theme script runs.
|
|
*/
|
|
|
|
:root {
|
|
/* --- Type ------------------------------------------------------------- */
|
|
--font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Palladio,
|
|
"URW Palladio L", "Book Antiqua", Baskerville, Georgia, serif;
|
|
--font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
|
|
Arial, sans-serif;
|
|
--font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code",
|
|
"Cascadia Code", Menlo, Consolas, monospace;
|
|
|
|
--text-xs: 0.75rem;
|
|
--text-sm: 0.8125rem;
|
|
--text-base: 0.9375rem;
|
|
--text-md: 1rem;
|
|
--text-lg: 1.125rem;
|
|
--text-xl: 1.375rem;
|
|
--text-2xl: 1.75rem;
|
|
--text-3xl: 2.25rem;
|
|
|
|
--leading-tight: 1.25;
|
|
--leading-normal: 1.6;
|
|
--leading-relaxed: 1.75;
|
|
|
|
/* --- Space (4px scale) ------------------------------------------------ */
|
|
--sp-1: 0.25rem;
|
|
--sp-2: 0.5rem;
|
|
--sp-3: 0.75rem;
|
|
--sp-4: 1rem;
|
|
--sp-5: 1.25rem;
|
|
--sp-6: 1.5rem;
|
|
--sp-8: 2rem;
|
|
--sp-10: 2.5rem;
|
|
--sp-12: 3rem;
|
|
--sp-16: 4rem;
|
|
|
|
/* --- Radius & shadow -------------------------------------------------- */
|
|
--radius-sm: 4px;
|
|
--radius: 8px;
|
|
--radius-lg: 12px;
|
|
--radius-xl: 18px;
|
|
--radius-full: 999px;
|
|
|
|
/*
|
|
--- Controls ----------------------------------------------------------
|
|
Every button, input and select resolves its height from these. That is the
|
|
whole reason things line up: a row of mixed controls has one height, not
|
|
whatever each element's padding and font happened to add up to.
|
|
*/
|
|
--control-h: 2.25rem;
|
|
--control-h-sm: 1.75rem;
|
|
--control-h-lg: 2.75rem;
|
|
--control-px: 0.75rem;
|
|
--control-px-sm: 0.5rem;
|
|
|
|
/* --- Layout ----------------------------------------------------------- */
|
|
--sidebar-width: 17.5rem;
|
|
--inspector-width: 24rem;
|
|
/* Wider than the inspector because the content is not prose: eighty columns
|
|
of --font-mono do not fit in 24rem, and a terminal narrower than eighty
|
|
re-wraps everything a program prints. */
|
|
--terminal-width: 34rem;
|
|
--thread-max-width: 48rem;
|
|
--header-height: 3.5rem;
|
|
|
|
--transition-fast: 120ms ease;
|
|
--transition: 200ms ease;
|
|
}
|
|
|
|
/*
|
|
---------------------------------------------------------------------------
|
|
MORIA (default, dark)
|
|
|
|
Deep stone and lamplight: the halls under the mountain. Surfaces are cool and
|
|
near-neutral so the mallorn and mithril accents carry all the colour.
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
:root,
|
|
:root[data-theme="moria"] {
|
|
color-scheme: dark;
|
|
|
|
--bg: #101317;
|
|
--bg-sunken: #0B0E11;
|
|
--surface: #171B21;
|
|
--surface-raised: #1E242B;
|
|
--surface-hover: #232A32;
|
|
--surface-active: #2A323B;
|
|
|
|
--border: #2A313A;
|
|
--border-strong: #3A434E;
|
|
|
|
--ink: #E4E8EC;
|
|
--ink-muted: #A2ADB8;
|
|
--ink-faint: #6E7883;
|
|
--ink-inverse: #0B0E11;
|
|
|
|
/* Mithril: the cool primary, used for focus and interactive accents. */
|
|
--accent: #8FB3CC;
|
|
--accent-hover: #A9C6DA;
|
|
--accent-ink: #0B0E11;
|
|
--accent-soft: rgba(143, 179, 204, 0.14);
|
|
|
|
/*
|
|
Mallorn: the brand accent, and the assistant's mark. A yellow-leaning leaf
|
|
green, so it stays warm against the mithril blue rather than turning the
|
|
palette into two cool accents that compete.
|
|
*/
|
|
--leaf: #9BCC5A;
|
|
--leaf-hover: #B1DD74;
|
|
--leaf-soft: rgba(155, 204, 90, 0.14);
|
|
|
|
/* Ember: destructive actions and errors. */
|
|
--danger: #E2795A;
|
|
--danger-hover: #EC8E72;
|
|
--danger-soft: rgba(226, 121, 90, 0.14);
|
|
|
|
/*
|
|
Success leans teal rather than leaf. Two greens a hue apart read as one
|
|
colour rendered inconsistently -- an unread dot beside a brand badge has to
|
|
be tellable from it at a glance.
|
|
*/
|
|
--success: #5FBFA0;
|
|
--success-soft: rgba(95, 191, 160, 0.14);
|
|
--warning: #DFAE58;
|
|
--warning-soft: rgba(223, 174, 88, 0.14);
|
|
|
|
--bubble-user: #232B34;
|
|
--bubble-assistant: transparent;
|
|
--code-bg: #0C0F13;
|
|
--code-border: #262D36;
|
|
|
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
--shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
|
|
--shadow-lg: 0 12px 34px rgba(0, 0, 0, 0.55);
|
|
|
|
--scrim: rgba(6, 8, 10, 0.66);
|
|
}
|
|
|
|
/*
|
|
---------------------------------------------------------------------------
|
|
SHIRE (light)
|
|
|
|
Parchment, ink and moss: warm, low-contrast, easy to read for a long time.
|
|
Backgrounds are deliberately off-white -- pure #FFF next to the leaf accent
|
|
reads as clinical rather than as paper.
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
:root[data-theme="shire"] {
|
|
color-scheme: light;
|
|
|
|
--bg: #F6F1E4;
|
|
--bg-sunken: #EDE6D4;
|
|
--surface: #FDFBF5;
|
|
--surface-raised: #FFFFFF;
|
|
--surface-hover: #F1EADA;
|
|
--surface-active: #E7DEC9;
|
|
|
|
--border: #DED3BB;
|
|
--border-strong: #C6B896;
|
|
|
|
--ink: #2C2419;
|
|
--ink-muted: #6A5C48;
|
|
--ink-faint: #94856D;
|
|
--ink-inverse: #FDFBF5;
|
|
|
|
/* Hobbit-door blue-green: the cool primary. */
|
|
--accent: #3E6B7A;
|
|
--accent-hover: #325867;
|
|
--accent-ink: #FDFBF5;
|
|
--accent-soft: rgba(62, 107, 122, 0.12);
|
|
|
|
/* The same mallorn, darkened until it holds its own as text on parchment. */
|
|
--leaf: #4C7A22;
|
|
--leaf-hover: #3C6318;
|
|
--leaf-soft: rgba(76, 122, 34, 0.13);
|
|
|
|
--danger: #A6432B;
|
|
--danger-hover: #8C3722;
|
|
--danger-soft: rgba(166, 67, 43, 0.11);
|
|
|
|
--success: #2C7360;
|
|
--success-soft: rgba(44, 115, 96, 0.12);
|
|
--warning: #98701A;
|
|
--warning-soft: rgba(152, 112, 26, 0.13);
|
|
|
|
--bubble-user: #EDE4CF;
|
|
--bubble-assistant: transparent;
|
|
--code-bg: #F2EBD9;
|
|
--code-border: #DED3BB;
|
|
|
|
--shadow-sm: 0 1px 2px rgba(72, 58, 34, 0.09);
|
|
--shadow: 0 4px 14px rgba(72, 58, 34, 0.11);
|
|
--shadow-lg: 0 12px 34px rgba(72, 58, 34, 0.16);
|
|
|
|
--scrim: rgba(44, 36, 25, 0.4);
|
|
}
|
|
|
|
/* Respect a stated preference for reduced motion everywhere, at once. */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
scroll-behavior: auto !important;
|
|
}
|
|
}
|