.app { display: flex; width: 100%; height: 100%; position: relative; background: var(--bg-primary); --keyboard-offset: 0px; } /* ── Sidebar ── */ .sidebar { width: 260px; min-width: 260px; background: var(--bg-secondary); border-right: 1px solid var(--border-color); display: flex; flex-direction: column; overflow: hidden; contain: layout style paint; } .sidebar-header { padding: 16px; } .sidebar-title-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } .sidebar-header h1 { font-family: var(--font-serif); font-size: 18px; font-weight: 600; color: var(--accent); letter-spacing: 0.12em; text-transform: uppercase; } .settings-btn { background: transparent; color: var(--text-faint); font-size: 16px; padding: 4px 6px; border-radius: var(--radius-sm); transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease; } .settings-btn:hover { background: var(--bg-tertiary); color: var(--text-secondary); transform: rotate(20deg); } .new-session-btn { width: 100%; background: var(--bg-tertiary); color: var(--text-secondary); padding: 9px 12px; font-weight: 500; font-size: 13px; border-radius: var(--radius-sm); border: 1px solid var(--border-color); cursor: pointer; transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease; } .new-session-btn:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); border-color: var(--accent-border); } .new-session-btn:disabled { opacity: 0.3; } /* ── Settings Panel ── */ .settings-panel { border-bottom: 1px solid var(--border-color); max-height: 400px; overflow-y: auto; animation: fadeIn 0.25s ease; } .settings-provider-select { padding: 10px 14px; border-bottom: 1px solid var(--border-color); } .provider-dropdown { width: 100%; } .provider-dropdown .dropdown-trigger { width: 100%; font-size: 12px; font-weight: 500; } .provider-dropdown .dropdown-trigger:hover { border-color: var(--accent-border); } .provider-dropdown .dropdown-list { font-size: 12px; } .anthropic-setup, .custom-providers { padding: 14px 16px; } .anthropic-setup { display: flex; flex-direction: column; gap: 8px; } .setup-hint { font-size: 12px; color: var(--text-tertiary); margin-bottom: 4px; } .api-key-form { display: flex; flex-direction: column; gap: 8px; } .api-key-form input { font-size: 12px; padding: 8px 10px; } .settings-error { font-size: 11px; color: #e5534b; } .save-key-btn { background: var(--accent); color: var(--bg-primary); font-size: 12px; font-weight: 600; padding: 8px 12px; border-radius: var(--radius-sm); transition: background 0.2s ease, box-shadow 0.2s ease; } .save-key-btn:hover { background: var(--accent-hover); box-shadow: var(--glow); } .api-key-saved { display: flex; flex-direction: column; gap: 8px; align-items: center; padding: 10px; background: var(--accent-subtle); border-radius: var(--radius-sm); border: 1px solid var(--accent-border); } .key-status { font-size: 12px; color: var(--text-primary); margin: 0; } .disconnect-btn { background: transparent; color: var(--text-faint); font-size: 11px; padding: 4px 8px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); transition: color 0.2s ease, border-color 0.2s ease; } .disconnect-btn:hover { color: #e5534b; border-color: #e5534b; } /* ── Auth Mode Toggle ── */ .auth-mode-toggle { display: flex; gap: 0; border: 1px solid var(--border-color); border-radius: var(--radius-sm); overflow: hidden; } .auth-mode-btn { flex: 1; padding: 6px 10px; background: transparent; color: var(--text-faint); font-size: 11px; font-weight: 600; border: none; cursor: pointer; letter-spacing: 0.03em; transition: color 0.2s ease, background 0.2s ease; } .auth-mode-btn:first-child { border-right: 1px solid var(--border-color); } .auth-mode-btn:hover { color: var(--text-secondary); background: var(--bg-tertiary); } .auth-mode-btn.active { background: var(--bg-tertiary); color: var(--accent); } /* ── OAuth Flow ── */ .oauth-flow { display: flex; flex-direction: column; gap: 8px; } .oauth-btn { width: 100%; } .oauth-btn:disabled { opacity: 0.5; } .oauth-code-form { display: flex; flex-direction: column; gap: 8px; } .oauth-code-form input { font-size: 12px; padding: 8px 10px; } /* ── Vertex AI ADC Status ── */ .vertex-adc-status { display: flex; align-items: center; gap: 6px; padding: 4px 0; } .adc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .adc-dot.found { background: #3fb950; } .adc-dot.missing { background: #e5534b; } .adc-dot.unknown { background: var(--text-faint); } .save-key-btn:disabled { opacity: 0.4; cursor: not-allowed; } /* ── Custom Providers ── */ .custom-providers { display: flex; flex-direction: column; gap: 12px; } .provider-list { display: flex; flex-direction: column; gap: 4px; } .provider-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; background: var(--bg-tertiary); border-radius: var(--radius-sm); transition: background 0.2s ease; } .provider-item:hover { background: var(--bg-hover); } .provider-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; } .provider-name { font-size: 13px; font-weight: 500; color: var(--text-primary); } .provider-url { font-size: 11px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .remove-btn { background: transparent; color: var(--text-faint); font-size: 16px; padding: 2px 6px; flex-shrink: 0; cursor: pointer; transition: color 0.2s ease; } .remove-btn:hover { color: #e5534b; } .add-provider-form { display: flex; flex-direction: column; gap: 6px; padding-top: 8px; border-top: 1px solid var(--border-subtle); } .add-provider-form input { font-size: 12px; padding: 7px 10px; } .add-provider-btn { background: var(--bg-hover); color: var(--text-primary); font-size: 12px; font-weight: 500; padding: 7px 12px; transition: background 0.2s ease, color 0.2s ease; } .add-provider-btn:hover { background: var(--bg-active); } /* ── Model Selector ── */ .model-selector { padding: 12px 16px; border-top: 1px solid var(--border-color); } .model-selector label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); margin-bottom: 6px; font-weight: 500; } .model-selector select { width: 100%; padding: 7px 10px; font-size: 13px; } .model-connect-hint { font-size: 11px; color: var(--text-faint); padding: 10px; background: var(--bg-tertiary); border-radius: var(--radius-sm); text-align: center; } .model-connect-hint p { margin: 0; } .custom-model-input { margin-top: 6px; font-size: 12px; padding: 7px 10px; width: 100%; } .link-btn { background: none; color: var(--accent); padding: 0; font-size: 11px; text-decoration: underline; transition: color 0.2s ease; } .link-btn:hover { color: var(--accent-hover); } /* ── Session List ── */ .sessions-list { flex: 1; overflow-y: auto; padding: 6px 8px; } .session-item { width: 100%; padding: 10px 12px; margin-bottom: 1px; background: transparent; border: none; border-radius: var(--radius-sm); text-align: left; display: flex; flex-direction: column; gap: 2px; cursor: pointer; border-left: 2px solid transparent; transition: background 0.2s ease, border-color 0.25s ease; } .session-item:hover { background: var(--bg-tertiary); border-left-color: var(--accent-border); } .session-item.active { background: var(--bg-tertiary); border-left-color: var(--accent); } .session-title { font-size: 13px; font-weight: 400; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .session-item.active .session-title { color: var(--accent); font-weight: 500; } .session-meta { display: flex; align-items: center; justify-content: space-between; } .session-item .date { font-size: 11px; color: var(--text-faint); } .delete-session-btn { background: transparent; color: transparent; font-size: 14px; padding: 0 4px; border: none; cursor: pointer; line-height: 1; transition: color 0.2s ease; } .session-item:hover .delete-session-btn { color: var(--text-faint); } .delete-session-btn:hover { color: #e5534b !important; } .session-item.streaming { border-left: 2px solid var(--accent); } .streaming-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); margin-right: 6px; animation: pulse 1.5s ease-in-out infinite; vertical-align: middle; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } /* ── Buffer Tabs ── */ .buffer-tabs { display: flex; border-bottom: 1px solid var(--border-color); background: var(--bg-secondary); flex-shrink: 0; } .buffer-tab { padding: 8px 20px; background: transparent; color: var(--text-faint); font-size: 12px; font-weight: 500; border: none; cursor: pointer; letter-spacing: 0.03em; position: relative; transition: color 0.2s ease, background 0.2s ease; } .buffer-tab:hover { color: var(--text-secondary); background: var(--bg-tertiary); } .buffer-tab.active { color: var(--accent); } .buffer-tab.active::after { content: ''; position: absolute; bottom: 0; left: 15%; right: 15%; height: 2px; background: var(--accent); border-radius: 1px; animation: tabUnderline 0.3s ease forwards; } .buffer-content { flex: 1; overflow: hidden; display: flex; flex-direction: column; contain: layout style; background: var(--bg-primary); } /* ── Main Area ── */ .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: var(--bg-primary); contain: layout style; } .mobile-sidebar-scrim, .mobile-bottom-overlay { display: none; } @media (max-width: 980px) { .app.mobile-layout { padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } .app.mobile-layout .sidebar { position: fixed; inset: env(safe-area-inset-top) auto env(safe-area-inset-bottom) 0; width: min(85vw, 320px); min-width: min(85vw, 320px); z-index: 30; transform: translateX(-102%); transition: transform 0.24s ease; border-right: 1px solid var(--border-color); box-shadow: 0 12px 24px rgba(0, 0, 0, 0.35); } .app.mobile-layout.sidebar-dragging .sidebar { transition: none; } .app.mobile-layout.mobile-sidebar-open .sidebar { transform: translateX(0); } .app.mobile-layout .main { width: 100%; padding-bottom: calc(58px + env(safe-area-inset-bottom) + var(--keyboard-offset, 0px)); } .desktop-only-tabs { display: none; } .mobile-sidebar-scrim { display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.48); transition: background-color 0.24s ease; z-index: 20; border: none; border-radius: 0; padding: 0; margin: 0; } .app.mobile-layout.sidebar-dragging .mobile-sidebar-scrim { transition: none; } .mobile-bottom-overlay { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; align-items: center; position: fixed; left: 8px; right: 8px; bottom: calc(6px + env(safe-area-inset-bottom) + var(--keyboard-offset, 0px)); z-index: 40; padding: 6px; border-radius: 12px; background: rgba(25, 25, 24, 0.92); border: 1px solid var(--border-color); backdrop-filter: blur(8px); } .mobile-action-btn { min-height: 36px; border: 1px solid var(--border-color); background: var(--bg-primary); color: var(--text-secondary); font-size: 16px; line-height: 1; letter-spacing: 0.02em; padding: 0; } .mobile-action-btn.active { color: var(--accent); border-color: var(--accent-border); background: var(--bg-tertiary); } } /* ── Buffer panes: active vs hidden ── */ .buffer-pane { contain: strict; will-change: transform; background: var(--bg-primary); } .buffer-pane.hidden { content-visibility: hidden; /* content-visibility: hidden skips rendering entirely while keeping the element in the DOM. Unlike display: none this doesn't destroy layout state, and unlike visibility: hidden it avoids all rendering work including layout, paint, and compositing — eliminating resize cost for inactive buffers. */ } .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; gap: 8px; animation: fadeIn 0.4s ease; position: relative; } /* Warm glow behind empty state */ .empty-state::before { content: ''; position: absolute; width: 280px; height: 180px; background: radial-gradient(ellipse, rgba(196, 168, 130, 0.06) 0%, transparent 70%); border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -60%); pointer-events: none; animation: warmPulse 4s ease-in-out infinite; } .empty-state h2 { font-family: var(--font-serif); color: var(--text-secondary); font-size: 20px; font-weight: 500; letter-spacing: -0.01em; } .empty-state p { margin: 0; } .empty-state button { background: var(--bg-tertiary); color: var(--text-primary); padding: 10px 20px; font-weight: 500; border-radius: var(--radius-sm); border: 1px solid var(--border-color); margin-top: 4px; transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; } .empty-state button:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--accent-border); box-shadow: var(--glow); }