/* Author: Simon-Pierre Boucher Contact: contact@spboucher.ai Project: chat.spboucher.ai Design system — "Instrument Panel". Dark-first, one accent for "alive" (signal teal), one for "cost" (amber). Mobile-first: base styles target ~390px, enhanced upward. */ :root, :root[data-theme="dark"] { --ink-950: #0e1116; --ink-900: #151a22; --ink-850: #1a212b; --ink-700: #2a3240; --fog-300: #aab4c3; --fog-050: #eef2f7; --signal-500: #3fb6a8; --signal-600: #2f9a8e; --signal-alpha: rgba(63, 182, 168, 0.14); --amber-500: #e0a458; --amber-alpha: rgba(224, 164, 88, 0.15); --danger: #d97b7b; --surface: var(--ink-950); --surface-raised: var(--ink-900); --surface-raised-2: var(--ink-850); --border: var(--ink-700); --text: var(--fog-050); --text-dim: var(--fog-300); --user-bubble: #1d2634; --sheet-shadow: 0 -12px 48px rgba(0, 0, 0, 0.5); --card-shadow: 0 2px 16px rgba(0, 0, 0, 0.35); } :root[data-theme="light"] { --ink-950: #f6f8fa; --ink-900: #ffffff; --ink-850: #eef1f5; --ink-700: #d4dbe4; --fog-300: #5b6675; --fog-050: #171d26; --signal-500: #2b9a8e; --signal-600: #23857a; --signal-alpha: rgba(43, 154, 142, 0.12); --amber-500: #b97f35; --amber-alpha: rgba(185, 127, 53, 0.13); --danger: #b54545; --surface: var(--ink-950); --surface-raised: var(--ink-900); --surface-raised-2: var(--ink-850); --border: var(--ink-700); --text: var(--fog-050); --text-dim: var(--fog-300); --user-bubble: #e7edf4; --sheet-shadow: 0 -12px 48px rgba(23, 29, 38, 0.18); --card-shadow: 0 2px 16px rgba(23, 29, 38, 0.08); } @media (prefers-color-scheme: light) { :root:not([data-theme]) { --ink-950: #f6f8fa; --ink-900: #ffffff; --ink-850: #eef1f5; --ink-700: #d4dbe4; --fog-300: #5b6675; --fog-050: #171d26; --signal-500: #2b9a8e; --signal-600: #23857a; --signal-alpha: rgba(43, 154, 142, 0.12); --amber-500: #b97f35; --amber-alpha: rgba(185, 127, 53, 0.13); --danger: #b54545; --surface: var(--ink-950); --surface-raised: var(--ink-900); --surface-raised-2: var(--ink-850); --border: var(--ink-700); --text: var(--fog-050); --text-dim: var(--fog-300); --user-bubble: #e7edf4; --sheet-shadow: 0 -12px 48px rgba(23, 29, 38, 0.18); --card-shadow: 0 2px 16px rgba(23, 29, 38, 0.08); } } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; height: 100%; } body { background: var(--surface); color: var(--text); font-family: var(--font-ui), Inter, -apple-system, system-ui, sans-serif; font-size: 16px; line-height: 1.6; -webkit-font-smoothing: antialiased; overscroll-behavior-y: none; } code, kbd, pre, .mono { font-family: var(--font-mono), "Berkeley Mono", "JetBrains Mono", ui-monospace, monospace; } button { font-family: inherit; color: inherit; background: none; border: none; cursor: pointer; padding: 0; } button:focus-visible, a:focus-visible, input:focus-visible, textarea:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--signal-500); outline-offset: 2px; border-radius: 4px; } input, textarea { font-family: inherit; font-size: inherit; color: inherit; } a { color: var(--signal-500); } ::selection { background: var(--signal-alpha); } /* ---------- App shell ---------- */ .app { display: flex; height: 100dvh; overflow: hidden; } .main { flex: 1; display: flex; flex-direction: column; min-width: 0; position: relative; } /* ---------- Top bar ---------- */ .topbar { display: flex; align-items: center; gap: 10px; padding: 10px 14px; padding-top: calc(10px + env(safe-area-inset-top)); border-bottom: 1px solid var(--border); background: var(--surface); min-height: 54px; } .topbar-title { flex: 1; font-weight: 600; font-size: 15px; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 10px; color: var(--text-dim); flex: none; } .icon-btn:hover { background: var(--surface-raised); color: var(--text); } /* ---------- Sidebar / drawer ---------- */ .sidebar { width: 300px; flex: none; background: var(--surface-raised); border-right: 1px solid var(--border); display: flex; flex-direction: column; padding-top: env(safe-area-inset-top); } .sidebar-header { display: flex; align-items: center; gap: 8px; padding: 14px; } .wordmark { font-family: var(--font-mono), monospace; font-size: 13px; font-weight: 600; letter-spacing: 0.02em; color: var(--text); flex: 1; user-select: none; } .wordmark .tld { color: var(--signal-500); } .new-chat-btn { display: flex; align-items: center; gap: 8px; margin: 0 14px 10px; padding: 11px 14px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface); font-weight: 500; font-size: 14px; transition: border-color 0.15s; } .new-chat-btn:hover { border-color: var(--signal-500); } .conv-list { flex: 1; overflow-y: auto; padding: 0 8px 14px; } .conv-item { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 10px 10px; border-radius: 9px; font-size: 14px; color: var(--text-dim); margin-bottom: 1px; } .conv-item.active { background: var(--surface-raised-2); color: var(--text); } .conv-item:hover { background: var(--surface-raised-2); } .conv-item .conv-title { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .conv-item .conv-del { opacity: 0; color: var(--text-dim); width: 28px; height: 28px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; flex: none; } .conv-item:hover .conv-del, .conv-item.active .conv-del { opacity: 1; } .conv-item .conv-del:hover { color: var(--danger); background: var(--surface); } .sidebar-footer { border-top: 1px solid var(--border); padding: 10px 14px calc(10px + env(safe-area-inset-bottom)); display: flex; gap: 6px; } .sidebar-footer .foot-btn { flex: 1; display: flex; align-items: center; gap: 8px; padding: 9px 10px; border-radius: 8px; font-size: 13px; color: var(--text-dim); } .sidebar-footer .foot-btn:hover { background: var(--surface-raised-2); color: var(--text); } /* Mobile: sidebar becomes an off-canvas drawer */ @media (max-width: 1023px) { .sidebar { position: fixed; inset: 0 auto 0 0; z-index: 40; transform: translateX(-100%); transition: transform 0.25s cubic-bezier(0.32, 0.72, 0, 1); width: min(84vw, 320px); box-shadow: none; } .sidebar.open { transform: translateX(0); box-shadow: 24px 0 64px rgba(0, 0, 0, 0.4); } .drawer-scrim { position: fixed; inset: 0; z-index: 39; background: rgba(0, 0, 0, 0.45); opacity: 0; pointer-events: none; transition: opacity 0.25s; } .drawer-scrim.open { opacity: 1; pointer-events: auto; } } @media (min-width: 1024px) { .drawer-scrim { display: none; } .topbar .menu-btn { display: none; } } /* ---------- Messages ---------- */ .message-scroll { flex: 1; overflow-y: auto; overscroll-behavior: contain; scroll-behavior: smooth; } @media (prefers-reduced-motion: reduce) { .message-scroll { scroll-behavior: auto; } * { animation-duration: 0.001s !important; transition-duration: 0.001s !important; } } .message-column { max-width: 780px; margin: 0 auto; padding: 20px 16px 24px; display: flex; flex-direction: column; gap: 22px; } .empty-state { margin: auto; text-align: center; padding: 40px 24px; color: var(--text-dim); } .empty-state .glyph { font-family: var(--font-mono), monospace; font-size: 28px; color: var(--signal-500); margin-bottom: 14px; } .empty-state h2 { color: var(--text); font-size: 17px; font-weight: 600; margin: 0 0 6px; } .empty-state p { font-size: 14px; margin: 0; } /* User message: compact right-aligned card */ .msg-user { align-self: flex-end; max-width: 85%; background: var(--user-bubble); border-radius: 14px 14px 4px 14px; padding: 10px 14px; white-space: pre-wrap; word-break: break-word; font-size: 16px; } .msg-user.pending { opacity: 0.6; } /* Assistant message: full-width block with slim attribution header */ .msg-assistant { display: flex; flex-direction: column; gap: 6px; min-width: 0; } .msg-attribution { display: flex; align-items: center; gap: 8px; font-family: var(--font-mono), monospace; font-size: 11.5px; color: var(--text-dim); flex-wrap: wrap; } .msg-attribution .model-name { color: var(--text); font-weight: 500; } .msg-attribution .live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--signal-500); animation: pulse 1.4s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } } .cost-chip { color: var(--amber-500); background: var(--amber-alpha); padding: 1px 7px; border-radius: 6px; font-size: 11px; } .msg-body { font-size: 16.5px; line-height: 1.62; word-break: break-word; min-width: 0; } .msg-body > *:first-child { margin-top: 0; } .msg-body > *:last-child { margin-bottom: 0; } .msg-error { color: var(--danger); font-size: 14px; border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); border-radius: 10px; padding: 10px 14px; background: color-mix(in srgb, var(--danger) 7%, transparent); } .streaming-caret::after { content: ""; display: inline-block; width: 8px; height: 17px; margin-left: 3px; vertical-align: text-bottom; background: var(--signal-500); border-radius: 2px; animation: pulse 1.1s ease-in-out infinite; } .reasoning-block { border-left: 2px solid var(--border); padding: 2px 0 2px 12px; color: var(--text-dim); font-size: 13.5px; margin-bottom: 8px; } .reasoning-block summary { cursor: pointer; font-family: var(--font-mono), monospace; font-size: 11.5px; user-select: none; list-style: none; } .reasoning-block summary::-webkit-details-marker { display: none; } /* Message actions: tap-friendly row, never hover-only */ .msg-actions { display: flex; align-items: center; gap: 4px; margin-top: 2px; } .msg-action-btn { min-width: 40px; min-height: 36px; padding: 4px 10px; border-radius: 8px; color: var(--text-dim); font-size: 12px; display: inline-flex; align-items: center; gap: 5px; } .msg-action-btn:hover { background: var(--surface-raised); color: var(--text); } .branch-nav { display: inline-flex; align-items: center; gap: 2px; font-family: var(--font-mono), monospace; font-size: 12px; color: var(--text-dim); } .branch-nav button { min-width: 34px; min-height: 36px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; } .branch-nav button:disabled { opacity: 0.3; cursor: default; } .branch-nav button:not(:disabled):hover { background: var(--surface-raised); color: var(--text); } /* Markdown internals */ .msg-body pre { background: var(--ink-900); border: 1px solid var(--border); border-radius: 12px; padding: 0; overflow: hidden; margin: 14px 0; } :root[data-theme="light"] .msg-body pre { background: #14181f; } .code-block-header { display: flex; align-items: center; justify-content: space-between; padding: 6px 12px; border-bottom: 1px solid var(--ink-700); font-family: var(--font-mono), monospace; font-size: 11px; color: #8b96a5; } .code-block-header button { color: #8b96a5; font-family: inherit; font-size: 11px; padding: 4px 8px; border-radius: 6px; min-height: 28px; } .code-block-header button:hover { color: #eef2f7; background: rgba(255, 255, 255, 0.06); } .msg-body pre code { display: block; padding: 12px 14px; overflow-x: auto; font-size: 13.5px; line-height: 1.55; background: transparent; } .msg-body code:not(pre code) { background: var(--surface-raised-2); border: 1px solid var(--border); padding: 1px 5px; border-radius: 5px; font-size: 0.86em; } .msg-body table { border-collapse: collapse; display: block; overflow-x: auto; max-width: 100%; margin: 14px 0; font-size: 14.5px; } .msg-body th, .msg-body td { border: 1px solid var(--border); padding: 6px 12px; text-align: left; } .msg-body th { background: var(--surface-raised); } .msg-body blockquote { border-left: 3px solid var(--signal-500); margin: 14px 0; padding: 2px 0 2px 14px; color: var(--text-dim); } .msg-body img { max-width: 100%; border-radius: 10px; } /* ---------- Jump-to-latest pill ---------- */ .jump-pill { position: absolute; bottom: 150px; left: 50%; transform: translateX(-50%); z-index: 10; background: var(--surface-raised-2); border: 1px solid var(--border); color: var(--text); border-radius: 999px; padding: 8px 16px; font-size: 13px; display: flex; align-items: center; gap: 6px; box-shadow: var(--card-shadow); } /* ---------- Composer + Model Rail ---------- */ .composer-wrap { border-top: 1px solid var(--border); background: var(--surface); padding: 0 12px calc(10px + env(safe-area-inset-bottom)); } .composer { max-width: 780px; margin: 0 auto; } /* The Model Rail: machined cartridge attached to the composer */ .model-rail { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 12px; margin-top: 10px; border: 1px solid var(--border); border-radius: 12px 12px 0 0; border-bottom: none; background: var(--surface-raised); text-align: left; position: relative; overflow: hidden; transition: border-color 0.2s; } .model-rail:hover { border-color: color-mix(in srgb, var(--signal-500) 55%, var(--border)); } .model-rail::before { /* signal edge: pulses teal while streaming */ content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--border); transition: background 0.3s; } .model-rail.live::before { background: var(--signal-500); animation: pulse 1.2s ease-in-out infinite; } .rail-glyph { font-family: var(--font-mono), monospace; font-size: 13px; font-weight: 600; color: var(--signal-500); border: 1px solid var(--border); border-radius: 7px; width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; flex: none; background: var(--surface); } .rail-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; } .rail-model-id { font-family: var(--font-mono), monospace; font-size: 12.5px; font-weight: 500; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .rail-meta { display: flex; align-items: center; gap: 8px; font-family: var(--font-mono), monospace; font-size: 10.5px; color: var(--text-dim); } .ctx-meter { flex: 1; max-width: 120px; height: 3px; background: var(--border); border-radius: 2px; overflow: hidden; } .ctx-meter .fill { height: 100%; background: var(--amber-500); border-radius: 2px; transition: width 0.4s; } .price-chip { color: var(--amber-500); flex: none; } .rail-chevron { color: var(--text-dim); flex: none; } .composer-box { display: flex; align-items: flex-end; gap: 8px; border: 1px solid var(--border); border-radius: 0 0 14px 14px; background: var(--surface-raised); padding: 8px 8px 8px 14px; transition: border-color 0.2s; } .composer-box:focus-within { border-color: var(--signal-500); } .composer-box textarea { flex: 1; background: transparent; border: none; resize: none; outline: none; font-size: 16px; /* prevents iOS zoom */ line-height: 1.5; max-height: 40dvh; padding: 6px 0; color: var(--text); } .composer-box textarea::placeholder { color: var(--text-dim); opacity: 0.7; } .send-btn { width: 44px; height: 44px; border-radius: 11px; background: var(--signal-500); color: #07110f; display: inline-flex; align-items: center; justify-content: center; flex: none; transition: background 0.15s, transform 0.1s; } .send-btn:hover { background: var(--signal-600); } .send-btn:active { transform: scale(0.94); } .send-btn:disabled { background: var(--border); color: var(--text-dim); cursor: default; } .send-btn.stop { background: var(--surface-raised-2); color: var(--danger); border: 1px solid var(--border); } /* ---------- Bottom sheet (model picker) ---------- */ .sheet-scrim { position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, 0.5); animation: fadeIn 0.2s; } @keyframes fadeIn { from { opacity: 0; } } .sheet { position: fixed; z-index: 61; left: 0; right: 0; bottom: 0; top: max(24px, env(safe-area-inset-top)); background: var(--surface-raised); border-radius: 18px 18px 0 0; box-shadow: var(--sheet-shadow); display: flex; flex-direction: column; animation: sheetUp 0.28s cubic-bezier(0.32, 0.72, 0.18, 1.02); } @keyframes sheetUp { from { transform: translateY(40px); opacity: 0.5; } } @media (min-width: 1024px) { .sheet { left: 50%; right: auto; top: 50%; bottom: auto; transform: translate(-50%, -50%); width: 660px; height: min(78vh, 740px); border-radius: 18px; animation: fadeIn 0.18s; } } .sheet-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--border); margin: 10px auto 2px; flex: none; } @media (min-width: 1024px) { .sheet-handle { display: none; } } .sheet-search { position: sticky; top: 0; padding: 10px 14px; display: flex; gap: 8px; align-items: center; } .sheet-search input { flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: 11px; padding: 11px 14px; font-size: 16px; outline: none; } .sheet-search input:focus { border-color: var(--signal-500); } .filter-row { display: flex; gap: 6px; padding: 2px 14px 10px; overflow-x: auto; flex: none; scrollbar-width: none; } .filter-row::-webkit-scrollbar { display: none; } .filter-chip { flex: none; padding: 6px 12px; border-radius: 999px; border: 1px solid var(--border); font-size: 12.5px; color: var(--text-dim); background: var(--surface); min-height: 32px; } .filter-chip.on { border-color: var(--signal-500); color: var(--signal-500); background: var(--signal-alpha); } .model-list { flex: 1; overflow-y: auto; padding: 0 8px 20px; } .model-section-label { font-family: var(--font-mono), monospace; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); padding: 14px 10px 6px; } .model-row { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 10px; border-radius: 10px; min-height: 56px; } .model-row:hover, .model-row.highlight { background: var(--surface-raised-2); } .model-row.selected { background: var(--signal-alpha); } .model-row .prov-glyph { font-family: var(--font-mono), monospace; font-size: 11px; font-weight: 600; color: var(--text-dim); border: 1px solid var(--border); border-radius: 7px; width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; flex: none; background: var(--surface); } .model-row .m-main { flex: 1; min-width: 0; } .model-row .m-name { font-size: 14px; font-weight: 500; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .model-row .m-sub { font-family: var(--font-mono), monospace; font-size: 11px; color: var(--text-dim); display: flex; gap: 8px; white-space: nowrap; overflow: hidden; } .model-row .fav-btn { width: 40px; height: 40px; border-radius: 9px; color: var(--text-dim); display: inline-flex; align-items: center; justify-content: center; flex: none; } .model-row .fav-btn.on { color: var(--amber-500); } .model-row .fav-btn:hover { background: var(--surface); } .cap-badges { display: flex; gap: 4px; flex: none; } .cap-badge { font-family: var(--font-mono), monospace; font-size: 9.5px; color: var(--text-dim); border: 1px solid var(--border); border-radius: 4px; padding: 1px 4px; text-transform: uppercase; } /* ---------- Login ---------- */ .login-page { min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 24px; background: radial-gradient(1200px 500px at 50% -10%, var(--signal-alpha), transparent 60%), var(--surface); } .login-card { width: 100%; max-width: 380px; background: var(--surface-raised); border: 1px solid var(--border); border-radius: 18px; padding: 28px; box-shadow: var(--card-shadow); } .login-card .wordmark { font-size: 15px; display: block; margin-bottom: 4px; } .login-card .sub { color: var(--text-dim); font-size: 13px; margin: 0 0 22px; } .login-card label { display: block; font-size: 12.5px; font-weight: 500; color: var(--text-dim); margin: 14px 0 6px; } .login-card input { width: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; font-size: 16px; outline: none; } .login-card input:focus { border-color: var(--signal-500); } .login-card .login-btn { width: 100%; margin-top: 22px; background: var(--signal-500); color: #07110f; font-weight: 600; font-size: 15px; border-radius: 11px; padding: 13px; transition: background 0.15s; } .login-card .login-btn:hover { background: var(--signal-600); } .login-card .login-btn:disabled { opacity: 0.6; } .login-error { margin-top: 14px; color: var(--danger); font-size: 13.5px; } /* ---------- Settings / usage ---------- */ .settings-page { max-width: 780px; margin: 0 auto; padding: 20px 16px calc(40px + env(safe-area-inset-bottom)); } .settings-page h1 { font-size: 20px; margin: 8px 0 20px; } .settings-page h2 { font-size: 14px; font-family: var(--font-mono), monospace; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-dim); margin: 28px 0 12px; font-weight: 500; } .stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } @media (min-width: 640px) { .stat-grid { grid-template-columns: repeat(4, 1fr); } } .stat-tile { background: var(--surface-raised); border: 1px solid var(--border); border-radius: 12px; padding: 14px; } .stat-tile .v { font-family: var(--font-mono), monospace; font-size: 20px; font-weight: 600; } .stat-tile .v.cost { color: var(--amber-500); } .stat-tile .k { font-size: 12px; color: var(--text-dim); margin-top: 2px; } .period-tabs { display: flex; gap: 6px; margin-bottom: 14px; } .usage-table { width: 100%; border-collapse: collapse; font-size: 13.5px; } .usage-table th { text-align: left; font-family: var(--font-mono), monospace; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-dim); font-weight: 500; padding: 8px 10px; border-bottom: 1px solid var(--border); } .usage-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); } .usage-table td.num { font-family: var(--font-mono), monospace; text-align: right; } .usage-table th.num { text-align: right; } .settings-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: var(--surface-raised); border: 1px solid var(--border); border-radius: 12px; padding: 14px; margin-bottom: 10px; } .settings-row .r-label { font-size: 14px; font-weight: 500; } .settings-row .r-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; } .btn { padding: 9px 16px; border-radius: 9px; border: 1px solid var(--border); background: var(--surface); font-size: 13.5px; font-weight: 500; min-height: 40px; } .btn:hover { border-color: var(--signal-500); } .btn.primary { background: var(--signal-500); border-color: var(--signal-500); color: #07110f; } .btn.danger:hover { border-color: var(--danger); color: var(--danger); } /* thin scrollbars */ *::-webkit-scrollbar { width: 8px; height: 8px; } *::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } *::-webkit-scrollbar-track { background: transparent; }