/* Codeman - Terminal-First UI */ /* Self-hosted UI + mono fonts (Carbon Aurora · Daylight) — served from /fonts, no external CDN, CSP-safe (font-src 'self'). Variable woff2 cover all weights. */ @font-face { font-family: 'Manrope'; font-style: normal; font-display: swap; font-weight: 400 800; src: url('fonts/manrope-variable.woff2') format('woff2'); } @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 400 700; src: url('fonts/jetbrains-mono-variable.woff2') format('woff2'); } :root { /* Dark is the safe fallback. Light skins override this so native selects, date/time pickers, form controls, and scrollbars match the chosen skin. */ color-scheme: dark; /* Carbon Aurora · Daylight — deep-but-not-black slate, surfaces step UP into the light */ --bg-dark: #11151c; --bg-card: #1b222c; --bg-input: #202833; --bg-hover: #2a323d; --border: #2b333f; --border-light: #3a4350; --text: #f3f6fa; --text-dim: #98a2b1; --text-muted: #717b8c; /* SINGLE cohesive accent — optimistic emerald → teal (replaces the old blue) */ --accent: #38b6f0; --accent-hover: #3ec8ee; /* calmer secondary green for non-primary pills/dots so Run + ring stay focal */ --green: #44b993; /* warm, quiet "working" amber (no second saturated hue) */ --yellow: #f0c25a; --red: #e06363; /* Daylight accent extras — referenced by the v1.0 override block at end of file */ --accent-d: #2487c9; --emerald: #3ec8ee; --teal: #2b8fd9; --accent-soft: #44b993; --accent-ink: #04223a; --warm: #e8c79a; --ring-glow: 0 0 12px -2px rgba(56, 182, 240, 0.55); --header-height: 36px; --toolbar-height: 42px; --glass-bg: rgba(31, 38, 48, 0.85); --glass-border: rgba(255, 255, 255, 0.08); --control-bg: rgba(255, 255, 255, 0.045); --control-bg-hover: rgba(255, 255, 255, 0.08); --control-border: rgba(255, 255, 255, 0.09); --control-border-hover: rgba(255, 255, 255, 0.14); --floating-bg: rgba(31, 38, 48, 0.96); --banner-bg-a: rgba(31, 38, 48, 0.92); --banner-bg-b: rgba(22, 27, 35, 0.92); --modal-backdrop: rgba(0, 0, 0, 0.6); --elevated-shadow: 0 16px 64px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.3); --subtle-shadow: 0 -1px 3px rgba(0, 0, 0, 0.3), 0 -4px 16px rgba(0, 0, 0, 0.15); --btn-radius: 6px; --transition-smooth: 0.2s cubic-bezier(0.4, 0, 0.2, 1); /* Session color palette — retoned toward the Daylight system */ --session-red: #e06363; --session-orange: #e8a45c; --session-yellow: #f0c25a; --session-green: #44b993; --session-blue: #2b8fd9; --session-purple: #a98fe0; --session-pink: #e07db0; /* Safe area insets for notched devices (iPhone X+, Dynamic Island) */ --safe-area-top: env(safe-area-inset-top, 0px); --safe-area-bottom: env(safe-area-inset-bottom, 0px); --safe-area-left: env(safe-area-inset-left, 0px); --safe-area-right: env(safe-area-inset-right, 0px); /* Touch target minimum (iOS Human Interface Guidelines) */ --touch-target-min: 44px; /* UI font + accent/gradient/hover tokens referenced by the v1.0 override block. These :root values equal the daylight-blue palette so the no-attribute fallback matches current behavior. */ --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --accent-rgb: 56, 182, 240; --accent-grad-a: #3ec8ee; --accent-grad-b: #2b8fd9; --run-hover-a: #5cc4f5; --run-hover-b: #3aa3e2; --gear-hover: #2a93d0; /* Compatibility aliases used by newer panels and overlays. Keep these references dynamic so every skin, including light skins, inherits the same semantic surface and text colors. */ --bg-primary: var(--bg-dark); --bg-secondary: var(--bg-card); --bg-tertiary: var(--bg-input); --text-primary: var(--text); --text-secondary: var(--text-dim); --border-color: var(--border); --accent-color: var(--accent); --success: var(--green); --error: var(--red); --danger: var(--red); --font-mono: 'Fira Code', 'JetBrains Mono', 'SF Mono', Menlo, Monaco, monospace; --shadow-lg: var(--elevated-shadow); } /* ===== Skin: Daylight Blue (current default) ===== */ html[data-skin="daylight-blue"] { --bg-dark: #11151c; --bg-card: #1b222c; --bg-input: #202833; --bg-hover: #2a323d; --border: #2b333f; --border-light: #3a4350; --text: #f3f6fa; --text-dim: #98a2b1; --text-muted: #717b8c; --accent: #38b6f0; --accent-hover: #3ec8ee; --term-bg: #161b23; --green: #44b993; --yellow: #f0c25a; --red: #e06363; --glass-bg: rgba(31, 38, 48, 0.85); --glass-border: rgba(255, 255, 255, 0.08); --accent-d: #2487c9; --emerald: #3ec8ee; --teal: #2b8fd9; --accent-soft: #44b993; --accent-ink: #04223a; --accent-rgb: 56, 182, 240; --accent-grad-a: #3ec8ee; --accent-grad-b: #2b8fd9; --run-hover-a: #5cc4f5; --run-hover-b: #3aa3e2; --gear-hover: #2a93d0; --ring-glow: 0 0 12px -2px rgba(56, 182, 240, 0.55); --session-red: #e06363; --session-orange: #e8a45c; --session-yellow: #f0c25a; --session-green: #44b993; --session-blue: #2b8fd9; --session-purple: #a98fe0; --session-pink: #e07db0; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } /* ===== Skin: Daylight Green ===== */ html[data-skin="daylight-green"] { --bg-dark: #11151c; --bg-card: #1b222c; --bg-input: #202833; --bg-hover: #2a323d; --border: #2b333f; --border-light: #3a4350; --text: #f3f6fa; --text-dim: #98a2b1; --text-muted: #717b8c; --accent: #2fd3aa; --accent-hover: #34d8a0; --term-bg: #161b23; --green: #44b993; --yellow: #f0c25a; --red: #e06363; --glass-bg: rgba(31, 38, 48, 0.85); --glass-border: rgba(255, 255, 255, 0.08); --accent-d: #19a987; --emerald: #34d8a0; --teal: #2bcbbb; --accent-soft: #44b993; --accent-ink: #062019; --accent-rgb: 47, 211, 170; --accent-grad-a: #34d8a0; --accent-grad-b: #2bcbbb; --run-hover-a: #3ee0aa; --run-hover-b: #34d4c4; --gear-hover: #1cbd97; --ring-glow: 0 0 12px -2px rgba(47, 211, 170, 0.55); --session-red: #e06363; --session-orange: #e8a45c; --session-yellow: #f0c25a; --session-green: #44b993; --session-blue: #2bcbbb; --session-purple: #a98fe0; --session-pink: #e07db0; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } /* ===== Skin: OG Codeman (original look — no Daylight polish, system font) ===== */ html[data-skin="og"] { --bg-dark: #09090b; --bg-card: #131316; --bg-input: #1a1a1f; --bg-hover: #1f1f26; --border: #232329; --border-light: #2e2e38; --text: #ececf0; --text-dim: #8b8b97; --text-muted: #52525e; --accent: #3b82f6; --accent-hover: #60a5fa; --term-bg: #0d0d0d; --green: #22c55e; --yellow: #eab308; --red: #ef4444; --glass-bg: rgba(19, 19, 22, 0.85); --glass-border: rgba(255, 255, 255, 0.06); /* OG is a neutral near-black palette with no blue in it. Without this the :root slate default would repaint every modal/palette/floating window rgba(31,38,48,.96) and quietly break the skin's identity. */ --floating-bg: rgba(19, 19, 22, 0.96); /* daylight-only extras left at sane neutral defaults (unused — override block does not apply to og) */ --accent-d: #3b82f6; --emerald: #3b82f6; --teal: #2563eb; --accent-soft: #22c55e; --accent-ink: #0b1220; --accent-rgb: 59, 130, 246; --accent-grad-a: #3b82f6; --accent-grad-b: #2563eb; --run-hover-a: #60a5fa; --run-hover-b: #3b82f6; --gear-hover: #2563eb; --ring-glow: 0 0 12px -2px rgba(59, 130, 246, 0.55); --session-red: #ef4444; --session-orange: #f97316; --session-yellow: #eab308; --session-green: #22c55e; --session-blue: #3b82f6; --session-purple: #a855f7; --session-pink: #ec4899; --ui-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } /* ===== Light skins ===== Each palette covers both the application chrome and the xterm palette in terminal-ui.js. The names reference their source palettes; Paper Gray is a Codeman-specific neutral theme informed by GitHub Primer Light. */ html[data-skin="paper-gray"] { color-scheme: light; --bg-dark: #f3f4f6; --bg-card: #ffffff; --bg-input: #eef1f4; --bg-hover: #e4e9ef; --border: #d0d7de; --border-light: #afb8c1; --text: #1f2328; --text-dim: #59636e; --text-muted: #6e7781; --accent: #0969da; --accent-hover: #0550ae; --term-bg: #f6f8fa; --green: #1a7f37; --yellow: #9a6700; --red: #cf222e; --glass-bg: rgba(255, 255, 255, 0.9); --glass-border: rgba(31, 35, 40, 0.15); --control-bg: rgba(31, 35, 40, 0.045); --control-bg-hover: rgba(31, 35, 40, 0.08); --control-border: rgba(31, 35, 40, 0.12); --control-border-hover: rgba(31, 35, 40, 0.2); --floating-bg: rgba(255, 255, 255, 0.97); --banner-bg-a: rgba(255, 255, 255, 0.96); --banner-bg-b: rgba(238, 241, 244, 0.96); --modal-backdrop: rgba(31, 35, 40, 0.32); --elevated-shadow: 0 16px 48px rgba(31, 35, 40, 0.18), 0 3px 12px rgba(31, 35, 40, 0.1); --accent-d: #0550ae; --emerald: #0969da; --teal: #218bff; --accent-soft: #1a7f37; --accent-ink: #ffffff; --accent-rgb: 9, 105, 218; --accent-grad-a: #218bff; --accent-grad-b: #0969da; --run-hover-a: #0969da; --run-hover-b: #0550ae; --gear-hover: #033d8b; --ring-glow: 0 0 10px -2px rgba(9, 105, 218, 0.35); --session-red: #cf222e; --session-orange: #bc4c00; --session-yellow: #9a6700; --session-green: #1a7f37; --session-blue: #0969da; --session-purple: #8250df; --session-pink: #bf3989; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } html[data-skin="solarized-light"] { color-scheme: light; --bg-dark: #fdf6e3; --bg-card: #fffaf0; --bg-input: #eee8d5; --bg-hover: #e5deca; --border: #d7cfb9; --border-light: #b8ad91; --text: #073642; --text-dim: #586e75; --text-muted: #6f8185; --accent: #147ba3; --accent-hover: #07658b; --term-bg: #fdf6e3; --green: #6f8100; --yellow: #8f7000; --red: #c43c39; --glass-bg: rgba(255, 250, 240, 0.9); --glass-border: rgba(88, 110, 117, 0.2); --control-bg: rgba(88, 110, 117, 0.07); --control-bg-hover: rgba(88, 110, 117, 0.12); --control-border: rgba(88, 110, 117, 0.18); --control-border-hover: rgba(88, 110, 117, 0.3); --floating-bg: rgba(255, 250, 240, 0.97); --banner-bg-a: rgba(255, 250, 240, 0.96); --banner-bg-b: rgba(238, 232, 213, 0.96); --modal-backdrop: rgba(7, 54, 66, 0.28); --elevated-shadow: 0 16px 48px rgba(7, 54, 66, 0.16), 0 3px 12px rgba(7, 54, 66, 0.09); --accent-d: #07658b; --emerald: #2aa198; --teal: #147ba3; --accent-soft: #6f8100; --accent-ink: #ffffff; --accent-rgb: 20, 123, 163; --accent-grad-a: #2aa198; --accent-grad-b: #147ba3; --run-hover-a: #168f86; --run-hover-b: #07658b; --gear-hover: #075676; --ring-glow: 0 0 10px -2px rgba(20, 123, 163, 0.32); --session-red: #dc322f; --session-orange: #cb4b16; --session-yellow: #9b7800; --session-green: #758600; --session-blue: #147ba3; --session-purple: #6c71c4; --session-pink: #d33682; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } html[data-skin="catppuccin-latte"] { color-scheme: light; --bg-dark: #eff1f5; --bg-card: #f8f9fb; --bg-input: #e6e9ef; --bg-hover: #dce0e8; --border: #ccd0da; --border-light: #acb0be; --text: #4c4f69; --text-dim: #5c5f77; --text-muted: #6c6f85; --accent: #1e66f5; --accent-hover: #174fbf; --term-bg: #eff1f5; --green: #3b8f2b; --yellow: #a86605; --red: #d20f39; --glass-bg: rgba(248, 249, 251, 0.9); --glass-border: rgba(76, 79, 105, 0.16); --control-bg: rgba(76, 79, 105, 0.055); --control-bg-hover: rgba(76, 79, 105, 0.1); --control-border: rgba(76, 79, 105, 0.14); --control-border-hover: rgba(76, 79, 105, 0.24); --floating-bg: rgba(248, 249, 251, 0.97); --banner-bg-a: rgba(248, 249, 251, 0.96); --banner-bg-b: rgba(230, 233, 239, 0.96); --modal-backdrop: rgba(76, 79, 105, 0.28); --elevated-shadow: 0 16px 48px rgba(76, 79, 105, 0.17), 0 3px 12px rgba(76, 79, 105, 0.09); --accent-d: #174fbf; --emerald: #179299; --teal: #1e66f5; --accent-soft: #3b8f2b; --accent-ink: #ffffff; --accent-rgb: 30, 102, 245; --accent-grad-a: #209fb5; --accent-grad-b: #1e66f5; --run-hover-a: #17889c; --run-hover-b: #174fbf; --gear-hover: #153f99; --ring-glow: 0 0 10px -2px rgba(30, 102, 245, 0.32); --session-red: #d20f39; --session-orange: #d65d0e; --session-yellow: #a86605; --session-green: #3b8f2b; --session-blue: #1e66f5; --session-purple: #8839ef; --session-pink: #c63c91; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } html[data-skin="rose-pine-dawn"] { color-scheme: light; --bg-dark: #faf4ed; --bg-card: #fffaf3; --bg-input: #f2e9e1; --bg-hover: #ebe1da; --border: #dfdad9; --border-light: #c8c1c0; --text: #575279; --text-dim: #6e6a86; --text-muted: #797593; --accent: #286983; --accent-hover: #1f5266; --term-bg: #faf4ed; --green: #286983; --yellow: #96681f; --red: #b4637a; --glass-bg: rgba(255, 250, 243, 0.9); --glass-border: rgba(87, 82, 121, 0.16); --control-bg: rgba(87, 82, 121, 0.055); --control-bg-hover: rgba(87, 82, 121, 0.1); --control-border: rgba(87, 82, 121, 0.14); --control-border-hover: rgba(87, 82, 121, 0.24); --floating-bg: rgba(255, 250, 243, 0.97); --banner-bg-a: rgba(255, 250, 243, 0.96); --banner-bg-b: rgba(242, 233, 225, 0.96); --modal-backdrop: rgba(87, 82, 121, 0.28); --elevated-shadow: 0 16px 48px rgba(87, 82, 121, 0.17), 0 3px 12px rgba(87, 82, 121, 0.09); --accent-d: #1f5266; --emerald: #56949f; --teal: #286983; --accent-soft: #907aa9; --accent-ink: #ffffff; --accent-rgb: 40, 105, 131; --accent-grad-a: #56949f; --accent-grad-b: #286983; --run-hover-a: #3f7f8b; --run-hover-b: #1f5266; --gear-hover: #193f4f; --ring-glow: 0 0 10px -2px rgba(40, 105, 131, 0.32); --session-red: #b4637a; --session-orange: #c06f45; --session-yellow: #96681f; --session-green: #286983; --session-blue: #477f91; --session-purple: #907aa9; --session-pink: #b4637a; --ui-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } /* Components that predate skin tokens used literal dark glass fills. Keep their structure, but make those elevated surfaces coherent in light mode. */ html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) { scrollbar-color: var(--border-light) var(--bg-input); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .modal-content, .ralph-dropdown, .ralph-panel.detached, .mobile-case-picker-sheet, .command-palette, .case-combobox-list ) { background: var(--floating-bg); border-color: var(--control-border); color: var(--text); box-shadow: var(--elevated-shadow); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .settings-item, .cron-job-row, #cronModal .form-row-switch.cron-switch-row, .cron-weekdays label ) { background: var(--control-bg); border-color: var(--control-border); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .settings-item:hover, .cron-job-row:hover, .cron-weekdays label:hover ) { background: var(--control-bg-hover); border-color: var(--control-border-hover); } /* Status badges and accent-tinted pills bake in pale light-on-dark ink (#cdddff, #9dc0ff, #ffc107, #fff, …) over a low-alpha tint. That reads at 1.0–1.9:1 once the tint sits on a light surface — the search filter chips literally vanish. Re-point the ink at each skin's own dark tokens and keep the tint as the category signal. */ html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .search-filter-chip.active, .search-badge-session, .history-view-all-btn, .session-tab .tab-mode.gemini, .session-tab .tab-mode.antigravity ) { color: var(--accent-d); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .search-badge-file, .tunnel-panel-btn.btn-start, .voice-provider-status.active ) { color: var(--green); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .ralph-task-priority.priority-p1, .ralph-circuit-breaker.half-open ) { color: var(--yellow); } html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is( .search-badge-event, .respawn-state, .history-detail-path, .mobile-case-item, .mobile-case-picker-header h3, .btn-toolbar.btn-case-mobile:hover ) { color: var(--text); } * { box-sizing: border-box; margin: 0; padding: 0; } /* ========== Accessibility: Focus Styles ========== */ /* Skip link for keyboard users */ .skip-link { position: absolute; top: -50px; left: 8px; padding: 8px 16px; background: var(--accent); color: white; text-decoration: none; border-radius: 4px; z-index: 10000; font-size: 0.875rem; transition: top 0.2s; } .skip-link:focus { top: 8px; } /* Global focus-visible styles for keyboard navigation */ :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* Remove default outline for mouse users */ :focus:not(:focus-visible) { outline: none; } /* Button focus styles */ button:focus-visible, .btn-toolbar:focus-visible, .btn-icon:focus-visible, .btn-icon-header:focus-visible, .btn-icon-sm:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* Input focus styles */ input:focus-visible, select:focus-visible, textarea:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); outline: none; } /* xterm.js hidden textarea — must never show focus ring or caret. * On mobile (touch devices), override xterm.css defaults that position the * textarea at left:-9999em with width/height:0. iOS Safari ignores keyboard * input to off-screen zero-size textareas, so we move it on-screen with a * minimal size while keeping it visually invisible. */ .xterm-helper-textarea { border: none !important; box-shadow: none !important; outline: none !important; opacity: 0 !important; caret-color: transparent !important; } .touch-device .xterm .xterm-helper-textarea { left: var(--xterm-helper-left, 0px) !important; top: var(--xterm-helper-top, 0px) !important; width: 1px !important; height: 1px !important; z-index: 0 !important; font-size: 16px !important; /* prevent iOS auto-zoom on focus */ } /* Session tab focus */ .session-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 1; } /* Modal close button focus */ .modal-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } body { font-family: var(--ui-font); background: var(--bg-dark); color: var(--text); height: 100vh; height: 100dvh; height: var(--app-height, 100dvh); overflow: hidden; } /* App Layout - Terminal First */ .app { display: flex; flex-direction: column; height: 100vh; height: 100dvh; height: var(--app-height, 100dvh); } /* Compact Header */ .header { display: flex; align-items: flex-start; min-height: var(--header-height); padding: 0.35rem 0.75rem; background: var(--glass-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-bottom: 1px solid var(--glass-border); flex-shrink: 0; position: relative; z-index: 100; /* Above main content so dropdowns work */ /* Performance: isolate header from terminal reflow — tab badge updates and token counter changes shouldn't trigger terminal layout recalculation */ contain: layout style paint; } .header-brand { display: flex; align-items: center; padding-right: 0.75rem; border-right: 1px solid var(--glass-border); margin-right: 0.5rem; height: var(--header-height); flex-shrink: 0; } .logo { font-size: 0.85rem; font-weight: 700; color: var(--accent-hover); letter-spacing: -0.02em; cursor: pointer; transition: color var(--transition-smooth), text-shadow var(--transition-smooth), filter var(--transition-smooth); } /* Single-letter brand shown only on phones (see mobile.css phone breakpoint) */ .logo .logo-compact { display: none; } .logo:hover { color: #93c5fd; text-shadow: 0 0 12px rgba(96, 165, 250, 0.5), 0 0 24px rgba(96, 165, 250, 0.2); filter: brightness(1.1); } /* Session Tabs */ .session-tabs { display: flex; align-items: flex-start; flex-wrap: nowrap; gap: 4px 2px; flex: 1; overflow-x: auto; overflow-y: hidden; padding: 0.15rem 0.25rem; /* Performance: isolate layout recalculations */ contain: layout; } .session-tabs.tabs-two-rows { flex-wrap: wrap; overflow-x: hidden; overflow-y: auto; max-height: 120px; } .session-tabs.tabs-auto-wrap { flex-wrap: wrap; overflow-x: hidden; overflow-y: auto; max-height: 96px; } .session-tabs::-webkit-scrollbar { width: 4px; height: 0; } .session-tabs::-webkit-scrollbar-track { background: transparent; } .session-tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } .session-tabs::-webkit-scrollbar-thumb:hover { background: var(--border-light); } .session-tab { display: flex; align-items: center; gap: 0.35rem; position: relative; padding: 0.35rem 0.6rem; background: transparent; border: 1px solid transparent; border-radius: var(--btn-radius); color: var(--text-dim); font-size: 0.75rem; cursor: pointer; white-space: nowrap; transition: background var(--transition-smooth), border-color var(--transition-smooth), color var(--transition-smooth), box-shadow var(--transition-smooth); } .session-tab:hover { background: rgba(34, 197, 94, 0.06); color: var(--text); box-shadow: 0 0 8px 2px rgba(34, 197, 94, 0.18), inset 0 0 6px 1px rgba(34, 197, 94, 0.06); border-color: rgba(34, 197, 94, 0.18); } .session-tab:active { background: rgba(34, 197, 94, 0.12); box-shadow: 0 0 12px 4px rgba(34, 197, 94, 0.35), inset 0 0 8px 2px rgba(34, 197, 94, 0.15); border-color: rgba(34, 197, 94, 0.3); } .session-tab.active { background: rgba(34, 197, 94, 0.15) !important; border: 2px solid #00FF66 !important; color: #fff !important; box-shadow: none !important; outline: none !important; } .session-tab.tab-loading::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: -2px; height: 2px; border-radius: 999px; background: linear-gradient(90deg, transparent, rgba(96, 165, 250, 0.95), transparent); animation: tab-load-sweep 0.9s linear infinite; pointer-events: none; } .tab-load-spinner { width: 10px; height: 10px; border: 2px solid rgba(96, 165, 250, 0.3); border-top-color: rgba(96, 165, 250, 0.95); border-radius: 50%; flex: 0 0 10px; animation: tab-load-spin 0.7s linear infinite; } @keyframes tab-load-spin { to { transform: rotate(360deg); } } @keyframes tab-load-sweep { 0% { transform: translateX(-45%); opacity: 0.35; } 50% { opacity: 1; } 100% { transform: translateX(45%); opacity: 0.35; } } /* Tab switch feedback: bright green glow on the newly-active tab */ .session-tab.tab-glow { animation: tab-glow 0.35s ease-out; } @keyframes tab-glow { 0% { box-shadow: 0 0 0px 0px rgba(34, 197, 94, 0); background: transparent; } 10% { box-shadow: 0 0 18px 6px rgba(34, 197, 94, 0.7), 0 0 40px 12px rgba(34, 197, 94, 0.3), inset 0 0 12px 3px rgba(34, 197, 94, 0.25); background: rgba(34, 197, 94, 0.12); } 30% { box-shadow: 0 0 14px 5px rgba(34, 197, 94, 0.5), 0 0 30px 10px rgba(34, 197, 94, 0.2), inset 0 0 10px 2px rgba(34, 197, 94, 0.15); background: rgba(34, 197, 94, 0.08); } 100% { box-shadow: 0 0 0px 0px rgba(34, 197, 94, 0); background: transparent; } } /* ── Tab entrance animations (tab-entrance.js) ───────────────────────────── Style is picked by html[data-tab-anim]; the stagger arrives as an inline --tab-enter-delay per tab (negative when an entrance is resuming after a re-render). Duration is scaled by --anim-enter-scale so one slider retimes every style. Colour/glow effects live on ::before, never on the tab itself: .session-tab.active sets background/border/box-shadow with !important (and a newly created session is normally the active one), and !important beats an animation. Transform and opacity are unaffected, so the tab keeps those. */ .session-tab.tab-enter { animation-delay: var(--tab-enter-delay, 0ms); animation-fill-mode: both; will-change: transform, opacity; } .session-tab.tab-enter::before { content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none; opacity: 0; animation-delay: var(--tab-enter-delay, 0ms); animation-fill-mode: both; } /* Slide, drifts in from the right and settles. */ html[data-tab-anim="slide"] .session-tab.tab-enter { animation-name: tab-enter-slide; animation-duration: calc(380ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } @keyframes tab-enter-slide { from { opacity: 0; transform: translate3d(24px, 3px, 0) scale(0.96); } to { opacity: 1; transform: none; } } /* Pop, springs past full size, then settles back. */ html[data-tab-anim="pop"] .session-tab.tab-enter { animation-name: tab-enter-pop; animation-duration: calc(460ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes tab-enter-pop { 0% { opacity: 0; transform: scale(0.4); } 55% { opacity: 1; transform: scale(1.13); } 76% { opacity: 1; transform: scale(0.965); } 100% { opacity: 1; transform: scale(1); } } /* CRT, snaps open as a hot line, then unfolds vertically. */ html[data-tab-anim="crt"] .session-tab.tab-enter { animation-name: tab-enter-crt; animation-duration: calc(520ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1); } html[data-tab-anim="crt"] .session-tab.tab-enter::before { animation-name: tab-enter-crt-flash; animation-duration: calc(520ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes tab-enter-crt { 0% { opacity: 0; transform: scale3d(0.04, 0.09, 1); } 20% { opacity: 1; transform: scale3d(1, 0.09, 1); } 56% { opacity: 1; transform: scale3d(1, 1.14, 1); } 78% { opacity: 1; transform: scale3d(1, 0.95, 1); } 100% { opacity: 1; transform: none; } } @keyframes tab-enter-crt-flash { 0% { opacity: 1; background: rgba(205, 255, 225, 0.95); box-shadow: 0 0 26px 8px rgba(0, 255, 102, 0.6); } 20% { opacity: 0.9; background: rgba(150, 255, 195, 0.7); box-shadow: 0 0 20px 6px rgba(0, 255, 102, 0.45); } 60% { opacity: 0.32; background: rgba(0, 255, 102, 0.14); box-shadow: 0 0 12px 2px rgba(0, 255, 102, 0.22); } 100% { opacity: 0; background: transparent; box-shadow: none; } } /* Unroll, the strip makes room and the tab widens into it. */ html[data-tab-anim="unroll"] .session-tab.tab-enter { animation-name: tab-enter-unroll; animation-duration: calc(480ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); overflow: hidden; } @keyframes tab-enter-unroll { 0% { max-width: 0; opacity: 0; padding-left: 0; padding-right: 0; transform: translateY(3px); } 30% { opacity: 1; } 100% { max-width: 900px; opacity: 1; padding-left: 0.6rem; padding-right: 0.6rem; transform: none; } } /* Boot, flickers on under a green scan sweep, like a display warming up. */ html[data-tab-anim="boot"] .session-tab.tab-enter { animation-name: tab-enter-boot; animation-duration: calc(720ms * var(--anim-enter-scale, 1)); animation-timing-function: linear; } html[data-tab-anim="boot"] .session-tab.tab-enter::before { background: linear-gradient( 100deg, transparent 0%, rgba(0, 255, 102, 0.06) 34%, rgba(200, 255, 220, 0.5) 50%, rgba(0, 255, 102, 0.06) 66%, transparent 100% ); background-size: 280% 100%; animation-name: tab-enter-boot-scan; animation-duration: calc(720ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-in-out; } @keyframes tab-enter-boot { 0% { opacity: 0; transform: translate3d(0, 5px, 0); } 8% { opacity: 0.85; } 15% { opacity: 0.12; } 23% { opacity: 1; } 31% { opacity: 0.35; } 42% { opacity: 1; transform: none; } 55% { opacity: 0.72; } 66% { opacity: 1; } 100% { opacity: 1; transform: none; } } @keyframes tab-enter-boot-scan { 0% { opacity: 0; background-position: 150% 0; } 12% { opacity: 1; } 86% { opacity: 1; } 100% { opacity: 0; background-position: -50% 0; } } /* Flip, drops in as a card hinged on its top edge. */ html[data-tab-anim="flip"] .session-tab.tab-enter { animation-name: tab-enter-flip; animation-duration: calc(520ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1); transform-origin: 50% 0%; } @keyframes tab-enter-flip { 0% { opacity: 0; transform: perspective(700px) rotateX(-92deg); } 55% { opacity: 1; transform: perspective(700px) rotateX(13deg); } 78% { opacity: 1; transform: perspective(700px) rotateX(-5deg); } 100% { opacity: 1; transform: perspective(700px) rotateX(0deg); } } /* ── Entrance lab (?animlab=1) ───────────────────────────────────────────── */ .anim-lab { position: fixed; right: 14px; bottom: 14px; z-index: 3100; width: 300px; max-height: 88vh; display: flex; flex-direction: column; padding: 10px 12px 12px; border: 1px solid var(--border-light); border-radius: 10px; background: rgba(12, 16, 14, 0.96); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55); color: var(--text); font-size: 0.72rem; backdrop-filter: blur(6px); } .anim-lab-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; font-weight: 600; letter-spacing: 0.02em; } .anim-lab-close { background: none; border: none; color: var(--text-dim); font-size: 1.1rem; line-height: 1; cursor: pointer; } .anim-lab-close:hover { color: var(--text); } .anim-lab-themes { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 10px; } .anim-lab-themes button { padding: 3px 8px; border: 1px solid var(--border-light); border-radius: 999px; background: rgba(255, 255, 255, 0.04); color: var(--text-dim); font-size: 0.66rem; cursor: pointer; } .anim-lab-themes button:hover { background: rgba(34, 197, 94, 0.16); color: var(--text); } .anim-lab-themes button.selected { border-color: rgba(0, 255, 102, 0.7); background: rgba(34, 197, 94, 0.2); color: #fff; } .anim-lab-scroll { flex: 1; min-height: 0; overflow-y: auto; margin-bottom: 8px; } .anim-lab-scroll::-webkit-scrollbar { width: 5px; } .anim-lab-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } .anim-lab-group { margin-bottom: 10px; } .anim-lab-group-title { margin-bottom: 4px; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); } .anim-lab-style { display: flex; flex-direction: column; gap: 1px; width: 100%; margin-bottom: 3px; padding: 5px 8px; border: 1px solid transparent; border-radius: 6px; background: rgba(255, 255, 255, 0.03); color: var(--text-dim); text-align: left; cursor: pointer; } .anim-lab-style:hover { background: rgba(34, 197, 94, 0.09); color: var(--text); } .anim-lab-style.selected { border-color: rgba(0, 255, 102, 0.6); background: rgba(34, 197, 94, 0.14); color: #fff; } .anim-lab-style strong { font-size: 0.73rem; font-weight: 600; } .anim-lab-style em { font-style: normal; font-size: 0.64rem; opacity: 0.7; } .anim-lab-range { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4px 8px; margin-bottom: 6px; color: var(--text-dim); } .anim-lab-range output { justify-self: end; color: var(--text); font-variant-numeric: tabular-nums; } .anim-lab-range input { grid-column: 1 / -1; width: 100%; accent-color: #00ff66; } .anim-lab-demo { display: flex; align-items: center; gap: 6px; margin-top: 8px; color: var(--text-dim); } .anim-lab-demo button { flex: 1; padding: 4px 0; border: 1px solid var(--border-light); border-radius: 6px; background: rgba(255, 255, 255, 0.04); color: var(--text); cursor: pointer; } .anim-lab-demo button:hover { background: rgba(34, 197, 94, 0.16); border-color: rgba(0, 255, 102, 0.5); } .anim-lab-hint { margin: 8px 0 0; font-size: 0.64rem; opacity: 0.55; } /* ── Window entrance animations ──────────────────────────────────────────── Applied to a window already sitting at its resting position. The `fly` style is NOT here: it is the pre-existing JS transition in subagent-windows.js that flies the window out of its parent tab, and it skips this class entirely. */ .subagent-window.win-enter, .ultracode-window.win-enter { animation-delay: var(--win-enter-delay, 0ms); animation-fill-mode: both; will-change: transform, opacity, filter; } .subagent-window.win-enter::before, .ultracode-window.win-enter::before { content: ""; position: absolute; inset: 0; z-index: 5; border-radius: inherit; pointer-events: none; opacity: 0; animation-delay: var(--win-enter-delay, 0ms); animation-fill-mode: both; } /* CRT, bursts open as a hot line, then unfolds vertically. */ html[data-win-anim="crt"] .subagent-window.win-enter, html[data-win-anim="crt"] .ultracode-window.win-enter { animation-name: win-enter-crt; animation-duration: calc(560ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1); } html[data-win-anim="crt"] .subagent-window.win-enter::before, html[data-win-anim="crt"] .ultracode-window.win-enter::before { animation-name: win-enter-crt-flash; animation-duration: calc(560ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes win-enter-crt { 0% { opacity: 0; transform: scale3d(0.55, 0.008, 1); } 22% { opacity: 1; transform: scale3d(1, 0.01, 1); } 58% { opacity: 1; transform: scale3d(1, 1.05, 1); } 80% { opacity: 1; transform: scale3d(1, 0.98, 1); } 100% { opacity: 1; transform: none; } } @keyframes win-enter-crt-flash { 0% { opacity: 1; background: rgba(205, 255, 225, 0.9); box-shadow: 0 0 40px 14px rgba(0, 255, 102, 0.55); } 22% { opacity: 0.8; background: rgba(120, 255, 180, 0.5); box-shadow: 0 0 30px 10px rgba(0, 255, 102, 0.4); } 60% { opacity: 0.25; background: rgba(0, 255, 102, 0.1); box-shadow: 0 0 14px 3px rgba(0, 255, 102, 0.18); } 100% { opacity: 0; background: transparent; box-shadow: none; } } /* Materialize, resolves out of a blur with a short glitch. */ html[data-win-anim="materialize"] .subagent-window.win-enter, html[data-win-anim="materialize"] .ultracode-window.win-enter { animation-name: win-enter-materialize; animation-duration: calc(620ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } @keyframes win-enter-materialize { 0% { opacity: 0; transform: scale(0.94); filter: blur(16px) brightness(1.7); } 35% { opacity: 0.85; filter: blur(6px) brightness(1.3); } 45% { opacity: 0.4; } 55% { opacity: 0.95; filter: blur(3px) brightness(1.15); } 70% { opacity: 0.75; } 100% { opacity: 1; transform: none; filter: none; } } /* Unfold, hinges down from the top edge. */ html[data-win-anim="unfold"] .subagent-window.win-enter, html[data-win-anim="unfold"] .ultracode-window.win-enter { animation-name: win-enter-unfold; animation-duration: calc(560ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1); transform-origin: 50% 0%; } @keyframes win-enter-unfold { 0% { opacity: 0; transform: perspective(1600px) rotateX(-88deg); } 55% { opacity: 1; transform: perspective(1600px) rotateX(9deg); } 80% { opacity: 1; transform: perspective(1600px) rotateX(-3deg); } 100% { opacity: 1; transform: perspective(1600px) rotateX(0deg); } } /* Beam down, holds still (so its connection line can draw toward a stable rect), then materializes out of a green wash. NO transform: a transformed window reports a transformed rect and the line would aim at the wrong place. */ html[data-win-anim="beam"] .subagent-window.win-enter, html[data-win-anim="beam"] .ultracode-window.win-enter { animation-name: win-enter-beam; animation-duration: calc(620ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } html[data-win-anim="beam"] .subagent-window.win-enter::before, html[data-win-anim="beam"] .ultracode-window.win-enter::before { animation-name: win-enter-beam-wash; animation-duration: calc(620ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes win-enter-beam { 0% { opacity: 0; filter: brightness(2.6) saturate(0.4); } 20% { opacity: 0.55; } 32% { opacity: 0.2; } 48% { opacity: 0.9; filter: brightness(1.5) saturate(0.8); } 100% { opacity: 1; filter: none; } } @keyframes win-enter-beam-wash { 0% { opacity: 0.9; background: linear-gradient(180deg, rgba(190, 255, 215, 0.85), rgba(0, 255, 102, 0)); } 45% { opacity: 0.5; background: linear-gradient(180deg, rgba(0, 255, 102, 0.35), rgba(0, 255, 102, 0)); } 100% { opacity: 0; background: transparent; } } /* Pop, springs open from the centre. */ html[data-win-anim="pop"] .subagent-window.win-enter, html[data-win-anim="pop"] .ultracode-window.win-enter { animation-name: win-enter-pop; animation-duration: calc(460ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes win-enter-pop { 0% { opacity: 0; transform: scale(0.55); } 58% { opacity: 1; transform: scale(1.045); } 80% { opacity: 1; transform: scale(0.99); } 100% { opacity: 1; transform: scale(1); } } /* ── Main terminal pane entrance animations ──────────────────────────────── ⚠ transform / opacity / clip-path ONLY. xterm's FitAddon derives rows+cols from getComputedStyle(parent).width/height, the untransformed layout box - so these are invisible to it, but animating width/height/padding here would resize the PTY mid-animation. Colour washes go on ::before, never as a `filter` on the container: that would blur a full-screen WebGL canvas every frame. `will-change` is deliberately not set, the base rule needs its `will-change: contents` for terminal compositing. */ .terminal-container.term-enter { animation-fill-mode: both; } .terminal-container.term-enter::before { content: ""; position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0; animation-fill-mode: both; } /* CRT, power-on: a hot line that expands to full height. */ html[data-term-anim="crt"] .terminal-container.term-enter { animation-name: term-enter-crt; animation-duration: calc(560ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.3, 0.9, 0.3, 1); } html[data-term-anim="crt"] .terminal-container.term-enter::before { animation-name: term-enter-crt-flash; animation-duration: calc(560ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes term-enter-crt { 0% { opacity: 0; transform: scale3d(0.6, 0.004, 1); } 20% { opacity: 1; transform: scale3d(1, 0.006, 1); } 58% { opacity: 1; transform: scale3d(1, 1.03, 1); } 80% { opacity: 1; transform: scale3d(1, 0.99, 1); } 100% { opacity: 1; transform: none; } } @keyframes term-enter-crt-flash { 0% { opacity: 1; background: rgba(210, 255, 230, 0.85); } 20% { opacity: 0.7; background: rgba(120, 255, 180, 0.4); } 60% { opacity: 0.2; background: rgba(0, 255, 102, 0.08); } 100% { opacity: 0; background: transparent; } } /* Boot, flickers on under a green scan sweep. */ html[data-term-anim="boot"] .terminal-container.term-enter { animation-name: term-enter-boot; animation-duration: calc(760ms * var(--anim-enter-scale, 1)); animation-timing-function: linear; } html[data-term-anim="boot"] .terminal-container.term-enter::before { background: linear-gradient( 180deg, transparent 0%, rgba(0, 255, 102, 0.05) 40%, rgba(200, 255, 220, 0.28) 50%, rgba(0, 255, 102, 0.05) 60%, transparent 100% ); background-size: 100% 300%; animation-name: term-enter-boot-scan; animation-duration: calc(760ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-in-out; } @keyframes term-enter-boot { 0% { opacity: 0; transform: scale(0.995); } 8% { opacity: 0.85; } 15% { opacity: 0.1; } 24% { opacity: 1; } 33% { opacity: 0.35; } 45% { opacity: 1; transform: none; } 58% { opacity: 0.7; } 70% { opacity: 1; } 100% { opacity: 1; transform: none; } } @keyframes term-enter-boot-scan { 0% { opacity: 0; background-position: 0 -150%; } 12% { opacity: 1; } 86% { opacity: 1; } 100% { opacity: 0; background-position: 0 150%; } } /* Wipe, reveals top-to-bottom behind a bright edge. */ html[data-term-anim="wipe"] .terminal-container.term-enter { animation-name: term-enter-wipe; animation-duration: calc(520ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.35, 0.85, 0.3, 1); } html[data-term-anim="wipe"] .terminal-container.term-enter::before { background: linear-gradient(180deg, rgba(0, 255, 102, 0.16) 0%, rgba(190, 255, 215, 0.5) 82%, transparent 100%); animation-name: term-enter-wipe-edge; animation-duration: calc(520ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.35, 0.85, 0.3, 1); } @keyframes term-enter-wipe { 0% { opacity: 1; clip-path: inset(0 0 100% 0); } 100% { opacity: 1; clip-path: inset(0 0 0 0); } } @keyframes term-enter-wipe-edge { 0% { opacity: 0.9; clip-path: inset(0 0 100% 0); } 80% { opacity: 0.45; } 100% { opacity: 0; clip-path: inset(0 0 0 0); } } /* Slide up, rises into place from below. */ html[data-term-anim="slide"] .terminal-container.term-enter { animation-name: term-enter-slide; animation-duration: calc(420ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } @keyframes term-enter-slide { 0% { opacity: 0; transform: translate3d(0, 34px, 0); } 100% { opacity: 1; transform: none; } } /* Fade, quiet, with a touch of scale. */ html[data-term-anim="fade"] .terminal-container.term-enter { animation-name: term-enter-fade; animation-duration: calc(340ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes term-enter-fade { 0% { opacity: 0; transform: scale(0.985); } 100% { opacity: 1; transform: none; } } /* ── Connection-line entrance animations ─────────────────────────────────── `--line-len` is the measured path length, stamped inline by _applyLineEntrances(); `--line-enter-delay` is negative when an entrance is resuming after the SVG was rebuilt underneath it. */ .connection-line.line-enter { animation-delay: var(--line-enter-delay, 0ms); animation-fill-mode: both; } /* Draw, the line paints itself from the tab down to the window. Overrides the resting 5 3 dash to a single full-length dash for the duration. */ html[data-line-anim="draw"] .connection-line.line-enter { stroke-dasharray: var(--line-len); animation-name: line-enter-draw; animation-duration: calc(420ms * var(--anim-enter-scale, 1)); animation-timing-function: cubic-bezier(0.32, 0.8, 0.3, 1); } @keyframes line-enter-draw { from { stroke-dashoffset: var(--line-len); opacity: 1; } to { stroke-dashoffset: 0; opacity: 0.9; } } /* Fade, plain opacity ramp, dashes intact. */ html[data-line-anim="fade"] .connection-line.line-enter { animation-name: line-enter-fade; animation-duration: calc(300ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } @keyframes line-enter-fade { from { opacity: 0; } to { opacity: 0.9; } } /* Packet, the base line fades in and a separate bright dash rides down it. The packet is its own cloned path so the base line keeps its dashed look. */ html[data-line-anim="packet"] .connection-line.line-enter { animation-name: line-enter-fade; animation-duration: calc(300ms * var(--anim-enter-scale, 1)); animation-timing-function: ease-out; } .connection-line-packet { fill: none; stroke: #cdfbe3; stroke-width: 4; stroke-linecap: round; pointer-events: none; stroke-dasharray: 20px 100000px; filter: drop-shadow(0 0 4px rgba(0, 255, 102, 0.95)) drop-shadow(0 0 10px rgba(59, 130, 246, 0.7)); animation-name: line-enter-packet; animation-duration: calc(700ms * var(--anim-enter-scale, 1)); animation-delay: var(--line-enter-delay, 0ms); animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1); animation-fill-mode: both; } @keyframes line-enter-packet { 0% { stroke-dashoffset: 20px; opacity: 0; } 12% { opacity: 1; } 85% { opacity: 1; } 100% { stroke-dashoffset: calc(-1 * var(--line-len)); opacity: 0; } } .anim-lab-check { display: flex; align-items: center; gap: 6px; margin: -4px 0 12px; padding: 0 2px; color: var(--text-dim); font-size: 0.66rem; cursor: pointer; } .anim-lab-check input { accent-color: #00ff66; } @media (prefers-reduced-motion: reduce) { .session-tab.tab-enter, .session-tab.tab-enter::before, .subagent-window.win-enter, .subagent-window.win-enter::before, .ultracode-window.win-enter, .ultracode-window.win-enter::before, .terminal-container.term-enter, .terminal-container.term-enter::before, .connection-line.line-enter, .connection-line-packet { animation: none !important; } } .session-tab .tab-status { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; } .session-tab .tab-status.idle { background: var(--green); } .session-tab .tab-status.busy { background: var(--green); animation: pulse 1.5s infinite; /* Performance: GPU acceleration for animation */ will-change: opacity; } .session-tab .tab-status.error { background: var(--red); } .session-tab .tab-status.ended { background: var(--text-muted); opacity: 0.5; } /* Session color coding - left border indicator */ .session-tab[data-color="red"] { border-left: 3px solid var(--session-red); } .session-tab[data-color="orange"] { border-left: 3px solid var(--session-orange); } .session-tab[data-color="yellow"] { border-left: 3px solid var(--session-yellow); } .session-tab[data-color="green"] { border-left: 3px solid var(--session-green); } .session-tab[data-color="blue"] { border-left: 3px solid var(--session-blue); } .session-tab[data-color="purple"] { border-left: 3px solid var(--session-purple); } .session-tab[data-color="pink"] { border-left: 3px solid var(--session-pink); } /* Active tabs with color get subtle background tint */ .session-tab.active[data-color="red"] { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.5); box-shadow: 0 0 10px rgba(239, 68, 68, 0.3); } .session-tab.active[data-color="orange"] { background: rgba(249, 115, 22, 0.15); border-color: rgba(249, 115, 22, 0.5); box-shadow: 0 0 10px rgba(249, 115, 22, 0.3); } .session-tab.active[data-color="yellow"] { background: rgba(234, 179, 8, 0.15); border-color: rgba(234, 179, 8, 0.5); box-shadow: 0 0 10px rgba(234, 179, 8, 0.3); } .session-tab.active[data-color="green"] { background: rgba(34, 197, 94, 0.15); border-color: rgba(34, 197, 94, 0.5); box-shadow: 0 0 10px rgba(34, 197, 94, 0.3); } .session-tab.active[data-color="blue"] { background: rgba(59, 130, 246, 0.15); border-color: rgba(59, 130, 246, 0.5); box-shadow: 0 0 10px rgba(59, 130, 246, 0.3); } .session-tab.active[data-color="purple"] { background: rgba(168, 85, 247, 0.15); border-color: rgba(168, 85, 247, 0.5); box-shadow: 0 0 10px rgba(168, 85, 247, 0.3); } .session-tab.active[data-color="pink"] { background: rgba(236, 72, 153, 0.15); border-color: rgba(236, 72, 153, 0.5); box-shadow: 0 0 10px rgba(236, 72, 153, 0.3); } /* Tab number indicator (Alt+N shortcut hint) */ .session-tab .tab-number { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 3px; background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.35); color: rgba(255, 255, 255, 0.75); font-size: 0.6rem; font-weight: 700; flex-shrink: 0; font-family: monospace; } .session-tab.active .tab-number { background: rgba(0, 255, 102, 0.2) !important; border-color: rgba(0, 255, 102, 0.5) !important; color: #00FF66 !important; } .session-tab .tab-info { display: flex; flex-direction: column; overflow: hidden; min-width: 0; } .session-tab .tab-name-row { display: flex; align-items: center; gap: 0.25rem; } .session-tab .tab-name { overflow: hidden; text-overflow: ellipsis; } .session-tab .tab-prefix { color: var(--text-muted); } .session-tab .tab-suffix { color: var(--text); font-weight: 500; } /* Tab folder path — hidden by default, shown via .tabs-show-folder on container */ .session-tab .tab-folder { font-size: 0.6rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.2; display: none; } .tabs-show-folder .session-tab .tab-folder { display: block; } .session-tab .tab-close { opacity: 0; width: 0; padding: 0; font-size: 0.9rem; line-height: 1; color: var(--text-muted); overflow: hidden; cursor: default; border-radius: 3px; /* Performance: use transform for GPU acceleration */ transition: opacity 0.05s ease-out, width 0.05s ease-out, padding 0.05s ease-out; } .session-tab:hover .tab-close { opacity: 1; width: auto; padding: 0.15rem 0.35rem; } .session-tab .tab-close:hover { color: var(--red); background: rgba(255, 255, 255, 0.1); } .session-tab.new-tab { padding: 0.35rem 0.5rem; color: var(--text-muted); font-size: 1rem; font-weight: 300; } .session-tab.new-tab:hover { color: var(--green); } /* Tab alert animations */ .session-tab.tab-alert-action { animation: tab-blink-red 2.5s ease-in-out infinite; } .session-tab.tab-alert-idle { animation: tab-blink-yellow 3.5s ease-in-out infinite; } @keyframes tab-blink-red { 0%, 100% { background: transparent; border-color: transparent; } 50% { background: rgba(239, 68, 68, 0.12); border-color: var(--red); } } @keyframes tab-blink-yellow { 0%, 100% { background: transparent; border-color: transparent; } 50% { background: rgba(234, 179, 8, 0.1); border-color: var(--yellow); } } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } /* Tab drag-and-drop reordering */ .session-tab[draggable="true"] { cursor: grab; } .session-tab.dragging { opacity: 0.5; cursor: grabbing; } .session-tab.drag-over-left { box-shadow: -2px 0 0 0 var(--accent); } .session-tab.drag-over-right { box-shadow: 2px 0 0 0 var(--accent); } /* Header Right */ .header-right { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; padding-left: 0.75rem; border-left: 1px solid var(--glass-border); } /* Connection Indicator */ .connection-indicator { display: flex; align-items: center; gap: 0.35rem; font-size: 0.7rem; color: var(--text-dim); font-family: 'SF Mono', Monaco, monospace; white-space: nowrap; } .connection-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .connection-dot.connected { background: var(--green); } .connection-dot.fallback { background: var(--yellow); box-shadow: 0 0 6px var(--yellow); } .connection-dot.offline { background: var(--red); box-shadow: 0 0 6px var(--red); } .connection-dot.reconnecting { background: var(--yellow); animation: connection-pulse 1.5s ease-in-out infinite; } .connection-dot.draining { background: var(--green); animation: connection-pulse 0.8s ease-in-out infinite; } @keyframes connection-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } /* Tunnel Indicator */ .tunnel-indicator { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; background: transparent; border: none; cursor: pointer; border-radius: var(--btn-radius); padding: 0; position: relative; transition: background var(--transition-smooth); } .tunnel-indicator:hover { background: rgba(255, 255, 255, 0.06); } .tunnel-dot { width: 9px; height: 9px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 6px #22c55e, 0 0 12px rgba(34, 197, 94, 0.4); animation: tunnel-glow 2s ease-in-out infinite; } .tunnel-indicator.connecting .tunnel-dot { background: #f59e0b; box-shadow: 0 0 6px #f59e0b, 0 0 12px rgba(245, 158, 11, 0.4); animation: tunnel-glow-amber 1s ease-in-out infinite; } @keyframes tunnel-glow { 0%, 100% { box-shadow: 0 0 6px #22c55e, 0 0 12px rgba(34, 197, 94, 0.4); } 50% { box-shadow: 0 0 8px #22c55e, 0 0 18px rgba(34, 197, 94, 0.6); } } @keyframes tunnel-glow-amber { 0%, 100% { box-shadow: 0 0 6px #f59e0b, 0 0 12px rgba(245, 158, 11, 0.4); opacity: 1; } 50% { box-shadow: 0 0 4px #f59e0b; opacity: 0.4; } } /* Tunnel Panel Dropdown */ .tunnel-panel { position: fixed; top: 36px; right: 12px; width: 320px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); z-index: 1000; overflow: hidden; } .tunnel-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--border); } .tunnel-panel-header h3 { margin: 0; font-size: 13px; font-weight: 600; color: var(--text); display: flex; align-items: center; gap: 8px; } .tunnel-panel-status { font-size: 11px; font-weight: 400; color: #22c55e; } .tunnel-panel-status.offline { color: var(--text-muted); } .tunnel-panel-body { padding: 10px 14px; } .tunnel-panel-section { margin-bottom: 12px; } .tunnel-panel-section:last-child { margin-bottom: 0; } .tunnel-panel-label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 6px; } .tunnel-panel-url { font-family: 'SF Mono', Monaco, monospace; font-size: 11px; color: var(--accent-hover); word-break: break-all; cursor: pointer; padding: 6px 8px; background: var(--bg-input); border-radius: 4px; transition: background 0.15s; } .tunnel-panel-url:hover { background: var(--bg-hover); } .tunnel-panel-stat { display: flex; align-items: center; justify-content: space-between; padding: 4px 0; font-size: 12px; color: var(--text-dim); } .tunnel-panel-stat-value { color: var(--text); font-family: 'SF Mono', Monaco, monospace; font-size: 11px; } .tunnel-panel-session { display: flex; align-items: center; gap: 8px; padding: 6px 8px; background: var(--bg-input); border-radius: 4px; margin-bottom: 4px; font-size: 11px; color: var(--text-dim); } .tunnel-panel-session-dot { width: 6px; height: 6px; border-radius: 50%; background: #22c55e; flex-shrink: 0; } .tunnel-panel-session-info { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tunnel-panel-session-method { font-size: 10px; padding: 1px 5px; border-radius: 3px; background: var(--bg-hover); color: var(--text-muted); text-transform: uppercase; flex-shrink: 0; } .tunnel-panel-actions { display: flex; gap: 6px; padding-top: 8px; border-top: 1px solid var(--border); } .tunnel-panel-btn { flex: 1; padding: 6px 0; font-size: 12px; font-weight: 500; border: 1px solid var(--border); border-radius: 5px; cursor: pointer; text-align: center; transition: all 0.15s; } .tunnel-panel-btn.btn-start { background: rgba(34, 197, 94, 0.1); border-color: rgba(34, 197, 94, 0.3); color: #22c55e; } .tunnel-panel-btn.btn-start:hover { background: rgba(34, 197, 94, 0.2); } .tunnel-panel-btn.btn-stop { background: rgba(239, 68, 68, 0.1); border-color: rgba(239, 68, 68, 0.3); color: #ef4444; } .tunnel-panel-btn.btn-stop:hover { background: rgba(239, 68, 68, 0.2); } .tunnel-panel-btn.btn-qr { background: var(--bg-input); color: var(--text-dim); } .tunnel-panel-btn.btn-qr:hover { background: var(--bg-hover); color: var(--text); } .tunnel-panel-btn.btn-revoke { background: rgba(239, 68, 68, 0.1); border-color: rgba(239, 68, 68, 0.3); color: #ef4444; font-size: 11px; } .tunnel-panel-btn.btn-revoke:hover { background: rgba(239, 68, 68, 0.2); } .tunnel-panel-empty { font-size: 11px; color: var(--text-muted); font-style: italic; padding: 4px 0; } .header-tokens { font-size: 0.75rem; font-weight: 500; color: var(--accent-hover); font-family: 'SF Mono', Monaco, monospace; } .header-system-stats { display: flex; gap: 0.75rem; font-size: 0.65rem; font-family: 'SF Mono', Monaco, monospace; color: var(--text-dim); padding: 0 0.5rem; } .stat-item { display: flex; align-items: center; gap: 0.35rem; } .stat-label { color: var(--text-muted); font-size: 0.6rem; text-transform: uppercase; min-width: 24px; } .stat-bar { width: 40px; height: 5px; background: rgba(255, 255, 255, 0.06); border-radius: 3px; overflow: hidden; } .stat-bar-fill { height: 100%; border-radius: 3px; transition: width 0.3s ease, background 0.3s ease; } .stat-bar-cpu { background: linear-gradient(90deg, var(--green) 0%, var(--green) 100%); } .stat-bar-cpu.medium { background: linear-gradient(90deg, var(--green) 0%, var(--yellow) 100%); } .stat-bar-cpu.high { background: linear-gradient(90deg, var(--yellow) 0%, var(--red) 100%); } .stat-bar-mem { background: linear-gradient(90deg, var(--accent) 0%, var(--accent-hover) 100%); } .stat-bar-mem.medium { background: linear-gradient(90deg, var(--accent) 0%, var(--yellow) 100%); } .stat-bar-mem.high { background: linear-gradient(90deg, var(--yellow) 0%, var(--red) 100%); } .stat-value { min-width: 32px; text-align: right; color: var(--text-dim); } .stat-value.high { color: var(--red); font-weight: 500; } .btn-icon-header { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; background: transparent; border: none; color: var(--text-muted); font-size: 1rem; cursor: pointer; border-radius: var(--btn-radius); transition: all var(--transition-smooth); } .btn-icon-header:hover { background: rgba(255, 255, 255, 0.07); color: var(--text); transform: rotate(45deg); } /* Admin Panel header button: only shown to admins in multi-user mode (marker class removed by admin-ui.js after identity boot). Deliberately BIG and prominent: it is the entry point to user/permission management. */ .btn-admin-panel { display: inline-flex; align-items: center; gap: 6px; padding: 5px 14px; background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%); color: var(--accent-ink); border: none; border-radius: var(--btn-radius); font-size: 0.85rem; font-weight: 700; letter-spacing: 0.02em; cursor: pointer; box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 45%, transparent); transition: all var(--transition-smooth); } .btn-admin-panel:hover { filter: brightness(1.1); box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 65%, transparent); } .btn-admin-panel--hidden { display: none !important; } /* Admin user tables (Admin Panel modal + the App Settings Users tab). */ .admin-users th, .admin-users td { padding: 5px 12px 5px 0; vertical-align: top; border-bottom: 1px solid color-mix(in srgb, var(--text-muted) 20%, transparent); } /* Multi-monitor header button: hidden by default (opt-in via App Settings → Display → "Header Displays"). The server strips this class at render when the setting is on; the client toggles it live on save. */ .btn-multimonitor--hidden { display: none !important; } /* Redraw terminal header button: hidden by default (opt-in via App Settings → Display → "Header Displays"). Pure client-side toggle. */ .btn-redraw-terminal--hidden { display: none !important; } .btn-icon-header.btn-settings { width: 30px; height: 30px; margin-left: 0; } .btn-icon-header.btn-sm { width: 20px; height: 20px; font-size: 0.7rem; font-weight: 600; } .btn-icon-header.btn-sm:hover { transform: none; } .header-font-controls { display: flex; align-items: center; gap: 0.25rem; padding: 0.15rem 0.4rem; background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.04); border-radius: var(--btn-radius); } .header-font-controls .font-size-display { font-size: 0.7rem; color: var(--text-muted); min-width: 18px; text-align: center; font-family: 'SF Mono', Monaco, monospace; } /* Session tab gear icon */ .session-tab .tab-gear { opacity: 0; width: 0; padding: 0; font-size: 1rem; line-height: 1; color: var(--text-muted); cursor: pointer; overflow: hidden; transition: opacity 0.15s, width 0.15s, padding 0.15s, transform 0.2s; } .session-tab:hover .tab-gear { opacity: 1; width: auto; padding: 0 0.3rem; } .session-tab .tab-gear:hover { color: var(--accent-hover); transform: rotate(45deg); } /* ===== Session detach / undock (beta/session-detach) ===================== */ /* Pop-out (detach) icon on each tab — mirrors .tab-gear reveal-on-hover. */ .session-tab .tab-detach { opacity: 0; width: 0; padding: 0; font-size: 0.95rem; line-height: 1; color: var(--text-muted); cursor: pointer; overflow: hidden; transition: opacity 0.15s, width 0.15s, padding 0.15s; } .session-tab:hover .tab-detach { opacity: 1; width: auto; padding: 0 0.3rem; } .session-tab .tab-detach:hover { color: var(--accent-hover); background: rgba(255, 255, 255, 0.1); border-radius: 3px; } /* A tab whose session is popped out into its own window. */ .session-tab.detached { opacity: 0.72; } .session-tab.detached .tab-detach { /* Keep the pop-out icon visible while detached as a re-focus affordance. */ opacity: 1; width: auto; padding: 0 0.3rem; color: var(--accent-hover); } .session-tab .tab-detached-badge { display: none; align-items: center; font-size: 0.55rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; padding: 1px 4px; margin-left: 4px; border-radius: 3px; background: rgba(96, 165, 250, 0.18); color: var(--accent-hover); } .session-tab.detached .tab-detached-badge { display: inline-flex; } /* ===== Solo (detached single-session) window chrome ===================== */ body.solo-mode .session-tabs, body.solo-mode .header-system-stats, body.solo-mode .header-tokens, body.solo-mode .btn-notifications, body.solo-mode .btn-multimonitor, body.solo-mode .header-plan-usage, body.solo-mode .btn-lifecycle-log { display: none !important; } .solo-session-title { flex: 1; min-width: 0; font-weight: 600; font-size: 13px; color: var(--text); padding: 0 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* "Session unavailable" overlay for a solo window whose session has ended. */ .solo-gone-overlay { position: fixed; inset: 0; z-index: 5000; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; background: rgba(9, 9, 11, 0.92); color: var(--text); text-align: center; padding: 24px; } .solo-gone-overlay h2 { margin: 0; font-size: 18px; } .solo-gone-overlay p { margin: 0; color: var(--text-muted); font-size: 13px; } /* Mode indicator on session tab */ .session-tab .tab-mode { font-size: 0.6rem; padding: 1px 4px; border-radius: 3px; background: var(--bg-hover); color: var(--text-muted); text-transform: uppercase; } .session-tab .tab-mode.shell { background: rgba(234, 179, 8, 0.2); color: var(--yellow); } .session-tab .tab-mode.opencode { background: rgba(16, 185, 129, 0.2); color: #10b981; } .session-tab .tab-mode.codex { background: rgba(168, 85, 247, 0.2); color: #a855f7; } .session-tab .tab-mode.gemini { background: rgba(138, 180, 248, 0.2); color: #8ab4f8; } .session-tab .tab-mode.antigravity { background: rgba(34, 211, 238, 0.2); color: #22d3ee; } /* Timer Banner - Compact */ .timer-banner { display: flex; align-items: center; gap: 1rem; padding: 0.4rem 1rem; background: linear-gradient(90deg, rgba(30, 58, 95, 0.8), rgba(21, 34, 56, 0.8)); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-bottom: 1px solid rgba(59, 130, 246, 0.2); flex-shrink: 0; } .timer-content { display: flex; align-items: center; gap: 1rem; flex: 1; } .timer-value { font-size: 1rem; font-weight: 600; font-family: 'SF Mono', Monaco, monospace; color: var(--accent-hover); } .timer-progress { flex: 1; height: 4px; background: rgba(0, 0, 0, 0.3); border-radius: 2px; max-width: 200px; } .timer-progress-fill { height: 100%; background: linear-gradient(90deg, #3b82f6, #60a5fa); border-radius: 2px; transition: width 1s linear; } .timer-meta { font-size: 0.7rem; color: var(--text-dim); } /* Respawn Banner - Compact 2-column layout */ .respawn-banner { display: flex; padding: 0.25rem 0.75rem; background: linear-gradient(90deg, rgba(30, 58, 30, 0.8), rgba(19, 37, 19, 0.8)); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-bottom: 1px solid rgba(34, 197, 94, 0.2); font-size: 0.7rem; flex-shrink: 0; } .respawn-compact-layout { display: flex; width: 100%; gap: 1rem; } .respawn-status-col { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; flex-shrink: 0; } .respawn-status-row1 { display: flex; align-items: center; gap: 0.5rem; } .respawn-status-row2 { display: flex; align-items: center; gap: 0.5rem; min-height: 1.2em; font-size: 0.65rem; color: var(--text-dim); } .respawn-status-row2:empty { display: none; } .respawn-countdown-timers { display: flex; gap: 0.3rem; flex-wrap: wrap; } .respawn-countdown-timer { display: flex; align-items: center; gap: 0.25rem; background: rgba(0, 0, 0, 0.35); padding: 0.1rem 0.35rem; border-radius: 3px; font-family: 'SF Mono', Monaco, monospace; font-size: 0.6rem; } .respawn-countdown-timer .timer-name { color: var(--text-dim); } .respawn-countdown-timer .timer-value { color: var(--green); font-weight: 500; min-width: 2em; text-align: right; } .respawn-timer-bar { width: 30px; height: 2px; background: rgba(255, 255, 255, 0.15); border-radius: 1px; overflow: hidden; } .respawn-timer-progress { height: 100%; background: var(--green); transition: width 0.1s linear; } .respawn-action-log { flex: 1; max-height: 3.2em; overflow-y: auto; font-size: 0.65rem; font-family: 'SF Mono', Monaco, monospace; color: var(--text-dim); border-left: 1px solid rgba(34, 197, 94, 0.2); padding-left: 0.5rem; } .respawn-action-log::-webkit-scrollbar { width: 3px; } .respawn-action-log::-webkit-scrollbar-thumb { background: rgba(34, 197, 94, 0.3); border-radius: 2px; } .respawn-action-entry { padding: 0.05rem 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .respawn-action-entry .action-time { color: var(--text-muted); margin-right: 0.3rem; } .respawn-action-entry .action-type { color: var(--green); margin-right: 0.3rem; } .respawn-action-entry .action-detail { color: var(--text-dim); } /* Command entries are highlighted */ .respawn-action-entry.action-command { color: var(--accent); } .respawn-action-entry.action-command .action-type { color: var(--accent); font-weight: 600; } .respawn-action-entry.action-command .action-detail { color: var(--text); font-weight: 500; } .respawn-indicator { color: var(--green); animation: spin 2s linear infinite; font-size: 0.8rem; } .respawn-state { color: #fff; font-weight: 600; background: rgba(34, 197, 94, 0.3); padding: 0.1rem 0.4rem; border-radius: 3px; font-size: 0.7rem; } .respawn-state.respawn-blocked { background: rgba(244, 67, 54, 0.3); color: #f44336; animation: respawn-blocked-pulse 1.5s ease-in-out infinite; } @keyframes respawn-blocked-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* Respawn spacer removed - using flex layout */ .respawn-cycles { color: var(--text-muted); font-family: 'SF Mono', Monaco, monospace; font-size: 0.65rem; } .respawn-timer { color: var(--accent-hover); font-family: 'SF Mono', Monaco, monospace; font-weight: 500; font-size: 0.65rem; padding: 0 0.4rem; border-left: 1px solid rgba(34, 197, 94, 0.3); } .respawn-tokens { color: var(--text-dim); font-family: 'SF Mono', Monaco, monospace; font-size: 0.65rem; } .detection-status { color: var(--text-dim); font-size: 0.65rem; } .detection-ai-check { font-size: 0.65rem; padding: 0.05rem 0.3rem; border-radius: 2px; background: rgba(255, 255, 255, 0.1); } .detection-ai-check.ai-checking { color: var(--accent); background: rgba(59, 130, 246, 0.15); } .detection-ai-check.ai-idle { color: var(--green); background: rgba(34, 197, 94, 0.15); } .detection-ai-check.ai-working { color: var(--yellow); background: rgba(234, 179, 8, 0.15); } .detection-ai-check.ai-disabled { color: var(--text-muted); background: rgba(255, 255, 255, 0.05); } .detection-confidence { color: var(--text-dim); font-family: 'SF Mono', Monaco, monospace; font-size: 0.6rem; padding: 0.05rem 0.25rem; background: rgba(34, 197, 94, 0.15); border-radius: 2px; } .detection-confidence.high { background: rgba(34, 197, 94, 0.3); color: var(--green); } .detection-confidence.medium { background: rgba(234, 179, 8, 0.2); color: var(--yellow); } .detection-confidence.hook-confirmed { background: rgba(139, 92, 246, 0.3); color: var(--purple, #a78bfa); } .detection-hook { font-size: 0.65rem; padding: 0.05rem 0.3rem; border-radius: 2px; background: rgba(139, 92, 246, 0.15); color: var(--purple, #a78bfa); } .detection-hook.hook-active { background: rgba(139, 92, 246, 0.25); color: var(--purple, #a78bfa); font-weight: 500; } @keyframes pulse-hook { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } @keyframes spin { to { transform: rotate(360deg); } } /* ===== Enhanced Ralph Wiggum Loop Panel ===== */ .ralph-panel { background: var(--glass-bg); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-bottom: 1px solid var(--glass-border); font-size: 0.75rem; flex-shrink: 0; overflow: hidden; position: relative; overflow-anchor: none; /* Prevent scroll anchoring when expanding/collapsing */ /* Performance: isolate paint and layout operations */ contain: layout style paint; } /* Mini Progress Ring (in summary) */ .ralph-ring-mini { position: relative; width: 32px; height: 32px; flex-shrink: 0; } .ralph-ring-svg { width: 100%; height: 100%; transform: rotate(-90deg); } .ralph-ring-bg { fill: none; stroke: var(--bg-input); stroke-width: 3; } .ralph-ring-progress { fill: none; stroke: url(#ralphGradient); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 0.5s ease-out; } .ralph-ring-progress-mini { fill: none; stroke: url(#ralphGradientMini); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 0.5s ease-out; } .ralph-ring-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 0.4rem; font-weight: 700; background: linear-gradient(135deg, #3b82f6, #22c55e); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; line-height: 1; text-align: center; } /* Summary Info */ .ralph-summary-info { flex: 1; display: flex; align-items: center; gap: 0.75rem; min-width: 0; } .ralph-title { font-weight: 600; color: var(--text); font-size: 0.8rem; white-space: nowrap; } .ralph-status-badge { display: flex; align-items: center; gap: 0.35rem; padding: 0.2rem 0.5rem; border-radius: 4px; background: var(--bg-input); font-size: 0.7rem; font-weight: 500; } .ralph-status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); transition: background 0.2s; } .ralph-status-badge.active .ralph-status-dot { background: var(--accent); animation: ralph-pulse 1.5s ease-in-out infinite; } .ralph-status-badge.completed .ralph-status-dot { background: var(--green); } .ralph-status-badge.tracking .ralph-status-dot { background: var(--yellow); } @keyframes ralph-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.6; transform: scale(1.2); } } /* Circuit Breaker Badge */ .ralph-circuit-breaker { display: flex; align-items: center; gap: 0.25rem; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.7rem; font-weight: 600; cursor: pointer; transition: all 0.2s; margin-left: 0.5rem; } .ralph-circuit-breaker.half-open { background: rgba(255, 193, 7, 0.2); color: #ffc107; border: 1px solid rgba(255, 193, 7, 0.4); } .ralph-circuit-breaker.half-open:hover { background: rgba(255, 193, 7, 0.3); } .ralph-circuit-breaker.open { background: rgba(244, 67, 54, 0.2); color: #f44336; border: 1px solid rgba(244, 67, 54, 0.4); animation: circuit-breaker-pulse 1s ease-in-out infinite; } .ralph-circuit-breaker.open:hover { background: rgba(244, 67, 54, 0.3); } .ralph-circuit-breaker .cb-icon { font-size: 0.8rem; } .ralph-circuit-breaker .cb-text { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.5px; } @keyframes circuit-breaker-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } /* RALPH_STATUS Block Display */ .ralph-status-block { background: var(--bg-input); border-radius: 4px; padding: 0.5rem 0.75rem; margin-top: 0.5rem; font-size: 0.75rem; } .ralph-status-block-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.4rem; font-weight: 600; color: var(--text-bright); } .ralph-status-block-status { padding: 0.1rem 0.4rem; border-radius: 3px; font-size: 0.65rem; font-weight: 600; text-transform: uppercase; } .ralph-status-block-status.in-progress { background: rgba(33, 150, 243, 0.2); color: #2196f3; } .ralph-status-block-status.complete { background: rgba(76, 175, 80, 0.2); color: #4caf50; } .ralph-status-block-status.blocked { background: rgba(244, 67, 54, 0.2); color: #f44336; } .ralph-status-block-stats { display: flex; gap: 1rem; color: var(--text-dim); } .ralph-status-block-stats span { display: flex; align-items: center; gap: 0.25rem; } .ralph-status-block-recommendation { margin-top: 0.4rem; padding-top: 0.4rem; border-top: 1px solid var(--border); color: var(--text-muted); font-style: italic; } /* Summary Stats */ .ralph-summary-stats { display: flex; align-items: center; gap: 0.75rem; } .ralph-stat { display: flex; align-items: center; gap: 0.25rem; color: var(--text-dim); font-size: 0.7rem; } .ralph-stat-icon { font-size: 0.75rem; opacity: 0.7; } .ralph-toggle { color: var(--text-dim); font-size: 0.6rem; flex-shrink: 0; } /* Hide detail when collapsed */ .ralph-panel.collapsed .ralph-detail { display: none; } /* Expanded Detail View - Compact horizontal layout */ .ralph-detail { padding: 0.5rem 0.75rem; border-top: 1px solid var(--border); background: var(--bg-dark); } .ralph-detail-row { display: flex; align-items: center; gap: 1rem; } /* Compact Progress Ring */ .ralph-ring-compact { position: relative; width: 75px; height: 75px; flex-shrink: 0; } .ralph-ring-compact .ralph-ring-percent { font-size: 0.95rem; font-weight: 600; } .ralph-ring-compact .ralph-ring-label { font-size: 0.55rem; } /* Unified Info + Tasks Section */ .ralph-info-unified { flex: 1; display: flex; align-items: flex-start; gap: 0.75rem; overflow: hidden; min-width: 0; background: var(--bg-input); padding: 0.4rem 0.6rem; border-radius: 4px; } .ralph-info-labels { display: grid; grid-template-columns: auto auto; gap: 0.15rem 0.5rem; flex-shrink: 0; align-items: center; } .ralph-info-row { display: contents; } .ralph-info-label { font-size: 0.5rem; white-space: nowrap; text-transform: uppercase; letter-spacing: 0.3px; color: var(--text-muted); text-align: right; } .ralph-info-unified code { font-size: 0.7rem; font-weight: 500; padding: 0; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background: transparent; color: var(--text); } .ralph-info-unified span:not(.ralph-info-label) { font-size: 0.7rem; font-weight: 500; color: var(--text); } .ralph-info-unified .ralph-tasks-count { font-size: 0.7rem; font-weight: 500; color: var(--text); } .ralph-info-unified .ralph-tasks-grid { flex: 1; display: flex; flex-wrap: wrap; gap: 0.2rem; padding: 0; max-height: 60px; overflow-y: auto; align-content: flex-start; } .ralph-tasks-compact .ralph-task-card { padding: 0.2rem 0.4rem; font-size: 0.65rem; border-left-width: 2px; } .ralph-tasks-compact .ralph-task-icon { font-size: 0.7rem; } .ralph-tasks-compact .ralph-task-content { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Large Progress Ring */ .ralph-ring-svg-large { width: 100%; height: 100%; transform: rotate(-90deg); } .ralph-ring-track { fill: none; stroke: var(--bg-input); stroke-width: 6; } .ralph-ring-fill { fill: none; stroke: url(#ralphGradient); stroke-width: 6; stroke-linecap: round; stroke-dasharray: 264; stroke-dashoffset: 264; transition: stroke-dashoffset 0.5s ease-out; } .ralph-ring-center { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; } .ralph-ring-percent { font-size: 1.25rem; font-weight: 700; color: var(--text); line-height: 1; } .ralph-ring-label { font-size: 0.6rem; color: var(--text-dim); margin-top: 0.15rem; } .ralph-tasks-count { color: var(--text-dim); font-weight: 400; } .ralph-tasks-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 0.5rem; padding: 0.5rem; max-height: 200px; overflow-y: auto; } /* Task Cards */ .ralph-task-card { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.5rem; background: var(--bg-dark); border-radius: 4px; border-left: 2px solid var(--text-muted); transition: border-color 0.2s, background 0.2s; position: relative; } .ralph-task-card.task-pending { border-left-color: var(--text-muted); } .ralph-task-card.task-in-progress { border-left-color: var(--accent); background: rgba(59, 130, 246, 0.05); } .ralph-task-card.task-completed { border-left-color: var(--green); opacity: 0.75; } .ralph-task-icon { flex-shrink: 0; width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; border-radius: 50%; } .ralph-task-card.task-pending .ralph-task-icon { color: var(--text-muted); } .ralph-task-card.task-in-progress .ralph-task-icon { color: var(--accent); animation: ralph-spin 2s linear infinite; } .ralph-task-card.task-completed .ralph-task-icon { color: var(--green); } @keyframes ralph-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .ralph-task-content { flex: 1; font-size: 0.7rem; color: var(--text-dim); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .ralph-task-card.task-completed .ralph-task-content { color: var(--text-dim); } /* Priority badges */ .ralph-task-priority { font-size: 0.55rem; font-weight: 700; padding: 0.1rem 0.25rem; border-radius: 2px; flex-shrink: 0; text-transform: uppercase; } .ralph-task-priority.priority-p0 { background: rgba(244, 67, 54, 0.3); color: #f44336; } .ralph-task-priority.priority-p1 { background: rgba(255, 193, 7, 0.3); color: #ffc107; } .ralph-task-priority.priority-p2 { background: rgba(33, 150, 243, 0.2); color: #2196f3; } /* Priority-based card highlighting */ .ralph-task-card.task-priority-p0 { border-left-color: #f44336; } .ralph-task-card.task-priority-p1:not(.task-completed) { border-left-color: #ffc107; } /* Empty state */ .ralph-state-empty { color: var(--text-muted); font-style: italic; padding: 0.5rem; } /* Ralph panel summary layout adjustments */ .ralph-summary { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; user-select: none; transition: background 0.15s; } .ralph-summary-content { display: flex; align-items: center; gap: 0.75rem; flex: 1; cursor: pointer; } .ralph-summary-content:hover { background: var(--bg-hover); } .ralph-controls { display: flex; gap: 0.25rem; flex-shrink: 0; } /* Ralph Menu Dropdown */ .ralph-menu-container { position: relative; } .ralph-dropdown { display: none; position: absolute; top: 100%; right: 0; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 10px; min-width: 170px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2); z-index: 1000; padding: 4px; } .ralph-dropdown.show { display: block; } .ralph-dropdown button { display: block; width: 100%; padding: 0.5rem 0.75rem; border: none; background: transparent; color: var(--text); text-align: left; font-size: 0.75rem; cursor: pointer; border-radius: var(--btn-radius); transition: background var(--transition-smooth); } .ralph-dropdown button:hover { background: rgba(255, 255, 255, 0.07); } .ralph-dropdown hr { margin: 0.25rem 4px; border: none; border-top: 1px solid rgba(255, 255, 255, 0.06); } /* Detached Ralph Panel */ .ralph-panel.detached { position: fixed; top: 80px; left: 50px; width: 600px; height: 400px; min-width: 350px; min-height: 200px; max-width: 90vw; max-height: 80vh; z-index: 1000; border: 1px solid var(--control-border); border-radius: 12px; box-shadow: var(--elevated-shadow); background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); overflow: hidden; resize: both; display: flex; flex-direction: column; } .ralph-panel.detached .ralph-summary { cursor: move; background: linear-gradient(180deg, var(--bg-hover) 0%, var(--bg-card) 100%); border-bottom: 1px solid var(--border); border-radius: 8px 8px 0 0; flex-shrink: 0; } .ralph-panel.detached .ralph-summary-content { cursor: move; } .ralph-panel.detached .ralph-summary-content:hover { background: transparent; } .ralph-panel.detached .ralph-detail { flex: 1; max-height: none; overflow: auto; display: flex; flex-direction: column; } .ralph-panel.detached .ralph-detail-row { flex: 1; overflow: auto; } .ralph-panel.detached .ralph-info-unified { flex-direction: column; flex: 1; overflow: auto; } .ralph-panel.detached .ralph-info-unified .ralph-tasks-grid { max-height: none; flex: 1; } .ralph-panel.detached.collapsed { min-height: auto; height: auto; } /* Main - Terminal Area */ .main { flex: 1; display: flex; overflow: hidden; background: var(--bg-dark); position: relative; } .terminal-wrap { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .terminal-container { flex: 1; background: var(--term-bg, #161b23); overflow: hidden; position: relative; /* Performance: isolate layout and paint operations. Do NOT use contain:strict — size containment breaks xterm.js FitAddon dimension calculations. */ contain: layout paint; /* Performance: promote to own compositor layer for isolation from header/toolbar/panel repaints. Eliminates compositing stalls when surrounding UI elements update during typing. */ will-change: contents; } .terminal-container .xterm { width: 100%; min-width: 0; height: 100%; padding: 0; } .terminal-container .xterm-viewport { background: transparent !important; } /* Touch devices: prevent browser from claiming the touch gesture before our JS touchmove handler fires. Without this, the browser starts native scrolling during the first few px of finger travel and ignores our subsequent preventDefault() — breaking custom terminal scroll. */ .touch-device .terminal-container, .touch-device .terminal-container .xterm, .touch-device .terminal-container .xterm-viewport, .touch-device .terminal-container .xterm-screen { touch-action: none; } /* Mobile terminal taps are cursor-positioning gestures, not text-selection gestures. xterm re-enables selectable DOM text in its accessibility tree, so force the whole terminal subtree back to non-selectable on touch devices. Synthetic mouse events for tap-to-position still dispatch normally through JavaScript. */ body.touch-device .terminal-container .xterm, body.touch-device .terminal-container .xterm .xterm-viewport, body.touch-device .terminal-container .xterm .xterm-screen, body.touch-device .terminal-container .xterm .xterm-rows, body.touch-device .terminal-container .xterm .xterm-accessibility-tree, body.touch-device .terminal-container .xterm .xterm-accessibility-tree *, body.touch-device .terminal-container .xterm .xterm-selection, body.touch-device .terminal-container .xterm .xterm-helper-textarea { user-select: none !important; -webkit-user-select: none !important; -webkit-touch-callout: none !important; } /* Welcome Overlay */ .welcome-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: var(--bg-dark); z-index: 10; opacity: 0; pointer-events: none; transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .welcome-overlay.visible { opacity: 1; pointer-events: auto; } .welcome-content { text-align: center; max-width: 520px; padding: 2rem; } .welcome-title { font-size: 3.5rem; font-weight: 800; background: linear-gradient(135deg, #60a5fa 0%, #93c5fd 50%, #60a5fa 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 1rem; letter-spacing: -0.04em; } .welcome-desc { color: var(--text-dim); font-size: 0.9rem; line-height: 1.6; margin-bottom: 0.5rem; } .welcome-actions { display: flex; gap: 0.75rem; justify-content: center; flex-wrap: wrap; margin-top: 2rem; margin-bottom: 1.5rem; } .welcome-btn { display: flex; align-items: center; gap: 0.5rem; padding: 0.7rem 1.3rem; font-size: 0.85rem; font-weight: 600; border-radius: 10px; border: 1px solid transparent; cursor: pointer; transition: all var(--transition-smooth); letter-spacing: 0.01em; } .welcome-btn-claude { background: linear-gradient(135deg, #1a3358 0%, #1e4fb8 50%, #2563eb 100%); border-color: rgba(59, 130, 246, 0.4); color: #e0e7ff; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); } .welcome-btn-claude:hover { background: linear-gradient(135deg, #2454a8 0%, #2d6cf0 50%, #4b8af7 100%); box-shadow: 0 4px 20px rgba(59, 130, 246, 0.35), 0 0 40px rgba(59, 130, 246, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1); border-color: rgba(96, 165, 250, 0.5); color: #fff; transform: translateY(-1px); } .welcome-btn-opencode { background: linear-gradient(135deg, #0a2e2a 0%, #0b3d35 50%, #0d4a40 100%); border-color: rgba(16, 185, 129, 0.4); color: #6ee7b7; box-shadow: 0 2px 8px rgba(16, 185, 129, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .welcome-btn-opencode:hover { background: linear-gradient(135deg, #0d4a40 0%, #116a58 50%, #15856e 100%); box-shadow: 0 4px 20px rgba(16, 185, 129, 0.3), 0 0 40px rgba(16, 185, 129, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(52, 211, 153, 0.5); color: #a7f3d0; transform: translateY(-1px); } .welcome-btn-gemini { background: linear-gradient(135deg, #10243f 0%, #174ea6 55%, #4f46e5 100%); border-color: rgba(96, 165, 250, 0.4); color: #dbeafe; box-shadow: 0 2px 8px rgba(96, 165, 250, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .welcome-btn-gemini:hover { background: linear-gradient(135deg, #17345f 0%, #2563eb 55%, #6366f1 100%); box-shadow: 0 4px 20px rgba(96, 165, 250, 0.3), 0 0 40px rgba(99, 102, 241, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(147, 197, 253, 0.5); color: #eff6ff; transform: translateY(-1px); } .welcome-btn-tunnel { background: linear-gradient(135deg, #221538 0%, #3b1a7a 50%, #6d28d9 100%); border-color: rgba(124, 58, 237, 0.4); color: #ddd6fe; box-shadow: 0 2px 8px rgba(109, 40, 217, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .welcome-btn-tunnel:hover { background: linear-gradient(135deg, #4c1d95 0%, #6d28d9 50%, #7c3aed 100%); box-shadow: 0 4px 20px rgba(124, 58, 237, 0.35), 0 0 40px rgba(124, 58, 237, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1); border-color: rgba(139, 92, 246, 0.5); color: #fff; transform: translateY(-1px); } .welcome-btn-tunnel.active { background: linear-gradient(135deg, #047857 0%, #059669 50%, #10b981 100%); border-color: rgba(52, 211, 153, 0.5); color: #ecfdf5; box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); } .welcome-btn-tunnel.active:hover { background: linear-gradient(135deg, #059669 0%, #10b981 50%, #34d399 100%); box-shadow: 0 4px 20px rgba(52, 211, 153, 0.35), 0 0 40px rgba(52, 211, 153, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1); color: #fff; transform: translateY(-1px); } .welcome-btn-tunnel.connecting { background: linear-gradient(135deg, #1e1e3a 0%, #312e81 50%, #4338ca 100%); border-color: rgba(99, 102, 241, 0.4); color: #c7d2fe; cursor: wait; } .tunnel-spinner { display: inline-block; width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.25); border-top-color: currentColor; border-radius: 50%; animation: tunnel-spin 0.8s linear infinite; flex-shrink: 0; } @keyframes tunnel-spin { to { transform: rotate(360deg); } } .welcome-qr { display: none; flex-direction: column; align-items: center; margin-top: 1.5rem; margin-bottom: 0.5rem; cursor: pointer; transition: transform 0.2s ease; } .welcome-qr.visible { display: flex; } .welcome-qr-inner { background: #fff; border-radius: 10px; padding: 12px; width: 140px; height: 140px; transition: width 0.25s ease, height 0.25s ease, padding 0.25s ease; } .welcome-qr-inner svg { width: 100%; height: 100%; } .welcome-qr.expanded .welcome-qr-inner { width: 280px; height: 280px; padding: 16px; } .welcome-qr-url { margin-top: 8px; font-family: monospace; font-size: 11px; color: var(--text-muted); word-break: break-all; max-width: 320px; text-align: center; } /* History sessions panel (welcome overlay) */ .history-sessions { margin-top: 1.5rem; width: 100%; max-width: 560px; } /* ── COD-9 cross-session search (folded into the welcome history panel) ── */ .search-panel { width: 100%; margin-bottom: 0.9rem; text-align: left; } .search-input-row { position: relative; display: flex; align-items: center; } .search-input { flex: 1; width: 100%; box-sizing: border-box; padding: 0.55rem 2rem 0.55rem 0.8rem; font-size: 0.85rem; color: var(--text); background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px; outline: none; transition: border-color var(--transition-smooth), background var(--transition-smooth); } .search-input:focus { border-color: rgba(59, 130, 246, 0.5); background: rgba(255, 255, 255, 0.06); } .search-input::placeholder { color: var(--text-dim); } .search-clear-btn { position: absolute; right: 0.4rem; top: 50%; transform: translateY(-50%); appearance: none; border: none; background: transparent; color: var(--text-dim); font-size: 1.2rem; line-height: 1; padding: 0.1rem 0.35rem; cursor: pointer; border-radius: 6px; } .search-clear-btn:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); } .search-filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; align-items: center; } .search-filter-group { display: flex; gap: 0.3rem; flex-wrap: wrap; } .search-filter-secondary { margin-left: auto; } .search-filter-chip { appearance: none; border: 1px solid rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.03); color: var(--text-muted); font-size: 0.68rem; padding: 0.28rem 0.6rem; border-radius: 999px; cursor: pointer; transition: all var(--transition-smooth); } .search-filter-chip:hover { border-color: rgba(59, 130, 246, 0.3); color: var(--text); } .search-filter-chip.active { background: rgba(59, 130, 246, 0.18); border-color: rgba(59, 130, 246, 0.5); color: #cdddff; } .search-select { appearance: none; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.1); color: var(--text-muted); font-size: 0.68rem; padding: 0.28rem 0.5rem; border-radius: 6px; cursor: pointer; max-width: 9rem; } .search-select:focus { outline: none; border-color: rgba(59, 130, 246, 0.5); } .search-results { display: flex; flex-direction: column; gap: 0.3rem; margin-top: 0.7rem; max-height: 320px; overflow-y: auto; } .search-results[hidden] { display: none; } .search-group-header { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.4rem; padding: 0 0.2rem; } .search-group-header:first-child { margin-top: 0; } .search-group-label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); font-weight: 600; } .search-group-count { font-size: 0.6rem; color: var(--text-muted); background: rgba(255, 255, 255, 0.06); border-radius: 999px; padding: 0.05rem 0.4rem; } .search-result-card { display: flex; flex-direction: column; gap: 0.25rem; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; padding: 0.5rem 0.7rem; cursor: pointer; transition: all var(--transition-smooth); } .search-result-card:hover, .search-result-card:focus-visible { border-color: rgba(59, 130, 246, 0.35); background: rgba(255, 255, 255, 0.06); outline: none; } .search-result-top { display: flex; align-items: center; gap: 0.5rem; min-width: 0; } .search-result-badge { font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.1rem 0.4rem; border-radius: 4px; flex-shrink: 0; font-weight: 600; } .search-badge-session { background: rgba(59, 130, 246, 0.18); color: #9dc0ff; } .search-badge-event { background: rgba(168, 85, 247, 0.18); color: #d4b3ff; } .search-badge-file { background: rgba(34, 197, 94, 0.16); color: #95e6b3; } .search-result-name { flex: 1; min-width: 0; font-size: 0.74rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .search-result-time { font-size: 0.65rem; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; } .search-result-snippet { font-size: 0.7rem; color: var(--text-muted); line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; } .search-empty, .search-truncated { font-size: 0.72rem; color: var(--text-dim); padding: 0.6rem 0.2rem; text-align: left; } .search-truncated { border-top: 1px dashed rgba(255, 255, 255, 0.08); margin-top: 0.3rem; color: var(--text-muted); } @media (max-width: 640px) { .search-filter-secondary { margin-left: 0; } .search-select { max-width: 7rem; } } .history-title { font-size: 0.85rem; color: var(--text-dim); margin-bottom: 0.5rem; font-weight: 500; text-align: left; } .history-list { display: flex; flex-direction: column; gap: 0.35rem; max-height: 240px; overflow-y: auto; } .history-item { display: flex; flex-direction: column; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 8px; transition: all var(--transition-smooth); text-align: left; } .history-item:hover { border-color: rgba(59, 130, 246, 0.3); background: rgba(255, 255, 255, 0.06); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); } .history-item.expanded { border-color: rgba(59, 130, 246, 0.35); background: rgba(255, 255, 255, 0.05); } /* COD-139: pinned sessions float to the top with a subtle accent highlight. */ .history-item.is-pinned { border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); box-shadow: inset 3px 0 0 rgba(245, 158, 11, 0.7); } .history-item.is-pinned:hover { border-color: rgba(245, 158, 11, 0.5); background: rgba(245, 158, 11, 0.12); } .history-item-pin { margin-right: 0.35rem; font-size: 0.75rem; line-height: 1; vertical-align: baseline; } .history-item-main { display: flex; align-items: center; gap: 0.6rem; padding: 0.55rem 0.8rem; cursor: pointer; border-radius: 8px; } .history-item-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; } .history-item-title { font-size: 0.8rem; color: var(--text); line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; } .history-item-subtitle { font-size: 0.65rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .history-item-subtitle.is-case { color: #7aa7ff; font-weight: 500; } /* Badge row (mode + LIVE pills) sits between the title and subtitle (COD-121). */ .history-item-badges { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; align-items: center; } .history-item-badge { font-size: 0.55rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; line-height: 1; padding: 0.12rem 0.35rem; border-radius: 0.35rem; background: var(--bg-hover); color: var(--text-muted); white-space: nowrap; } .history-item-badge-live { background: color-mix(in srgb, var(--green) 22%, transparent); color: var(--green); } .history-item-meta { font-size: 0.7rem; color: var(--text-muted); white-space: nowrap; align-self: center; } .history-item-expand { appearance: none; border: none; background: transparent; color: var(--text-dim); font-size: 1.1rem; line-height: 1; padding: 0.25rem 0.4rem; cursor: pointer; border-radius: 6px; transition: background var(--transition-smooth), color var(--transition-smooth); flex-shrink: 0; } .history-item-expand:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); } .history-item.expanded .history-item-expand { color: #7aa7ff; transform: rotate(90deg); } .history-item-detail { padding: 0.5rem 0.8rem 0.7rem; border-top: 1px dashed rgba(255, 255, 255, 0.08); display: flex; flex-direction: column; gap: 0.4rem; font-size: 0.72rem; color: var(--text-muted); } .history-item-detail[hidden] { display: none; } .history-detail-row { display: flex; gap: 0.5rem; align-items: flex-start; word-break: break-word; } .history-detail-label { color: var(--text-dim); min-width: 46px; flex-shrink: 0; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.04em; padding-top: 0.1rem; } .history-detail-value { color: var(--text); flex: 1; min-width: 0; white-space: pre-wrap; } .history-detail-path { font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.68rem; color: #a8b5c9; } .history-detail-meta { color: var(--text-dim); font-size: 0.68rem; } @media (max-width: 640px) { .history-item-meta { font-size: 0.65rem; } .history-item-main { gap: 0.45rem; padding: 0.6rem 0.7rem; } } .history-show-more { width: 100%; padding: 0.5rem; margin-top: 0.25rem; background: rgba(255, 255, 255, 0.04); border: 1px dashed rgba(255, 255, 255, 0.1); border-radius: 8px; color: var(--text-muted); font-size: 0.75rem; cursor: pointer; transition: background var(--transition-smooth), color var(--transition-smooth); } .history-show-more:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); } .history-detail-actions { margin-top: 0.5rem; } .history-view-all-btn { width: 100%; padding: 0.45rem 0.75rem; background: rgba(99, 179, 237, 0.08); border: 1px solid rgba(99, 179, 237, 0.25); border-radius: 6px; color: rgba(99, 179, 237, 0.95); font-size: 0.78rem; font-weight: 500; cursor: pointer; transition: background var(--transition-smooth), border-color var(--transition-smooth); } .history-view-all-btn:hover { background: rgba(99, 179, 237, 0.15); border-color: rgba(99, 179, 237, 0.5); } /* Folder history modal */ .folder-history-modal .modal-body { padding: 0.75rem 1rem 1rem; } .folder-history-subtitle { color: var(--text-muted); font-size: 0.78rem; font-family: 'SF Mono', Menlo, Consolas, monospace; word-break: break-all; margin-bottom: 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid rgba(255, 255, 255, 0.06); } .folder-history-list { display: flex; flex-direction: column; gap: 0.5rem; } .folder-history-empty { padding: 2rem 0.5rem; text-align: center; color: var(--text-muted); font-size: 0.85rem; } .welcome-hint { color: var(--text-muted); font-size: 0.8rem; } .welcome-hint kbd { display: inline-block; padding: 0.15rem 0.45rem; background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 5px; font-family: inherit; font-size: 0.75rem; color: var(--text-dim); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); } .welcome-ralph-link { background: none; border: none; color: var(--text-muted); font-size: 0.75rem; cursor: pointer; padding: 0.25rem 0; margin-top: 0.25rem; transition: color 0.15s ease; } .welcome-ralph-link:hover { color: var(--accent); } /* Bottom Toolbar */ .toolbar { display: flex; align-items: center; justify-content: space-between; position: relative; height: var(--toolbar-height); padding: 0 0.75rem; background: var(--glass-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-top: 1px solid var(--glass-border); box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.2), 0 -4px 12px rgba(0, 0, 0, 0.1); flex-shrink: 0; /* contain: style only — layout/paint containment clips the case-settings popover that extends above the toolbar (popover uses position:absolute + bottom:100%) */ contain: style; /* backdrop-filter above makes this a stacking context, which TRAPS the z-index:1000 on .run-mode-menu inside it. Without an explicit z-index here the toolbar resolves to auto (0) and .welcome-overlay (z-index:10, inside
) paints over the popped-up Run menu: with no session open, every item in that menu is unclickable. Must stay below .modal (1000). */ z-index: 20; } /* backdrop-filter creates a stacking context, trapping the popover's z-index inside the toolbar. When the popover is open, raise the toolbar above the CJK input (z-index 52) so the popover is interactable. */ .toolbar:has(.case-settings-popover:not(.hidden)), .toolbar:has(.case-combobox-list:not(.hidden)) { z-index: 100; } .toolbar-left, .toolbar-right { display: flex; align-items: center; gap: 0.5rem; } .toolbar-center { position: absolute; left: 50%; transform: translateX(-50%); } /* Below ~1500px the absolutely-centered group can land on top of the case picker (the left group widens with the case name), so fall back to normal flex flow where overlap is impossible */ @media (max-width: 1500px) { .toolbar-center { position: static; transform: none; margin-left: 0.4rem; } } .version-display { font-family: 'SF Mono', Monaco, monospace; font-size: 0.6rem; color: var(--text-muted); padding: 0.2rem 0.5rem; background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.04); border-radius: var(--btn-radius); cursor: default; user-select: none; opacity: 0.8; letter-spacing: 0.02em; } .toolbar-group { display: flex; align-items: center; gap: 0; } .btn-toolbar { display: flex; align-items: center; gap: 0.35rem; padding: 0.4rem 0.8rem; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--btn-radius); color: var(--text-dim); font-size: 0.75rem; cursor: pointer; transition: all var(--transition-smooth); white-space: nowrap; } .btn-toolbar:hover { background: rgba(255, 255, 255, 0.09); color: var(--text); border-color: rgba(255, 255, 255, 0.12); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); } .btn-toolbar:active { background: rgba(255, 255, 255, 0.06); transform: translateY(0.5px); } .btn-toolbar.btn-sm { padding: 0.3rem 0.55rem; font-size: 0.7rem; } .btn-toolbar.btn-primary { background: var(--accent); border-color: var(--accent); color: white; } .btn-toolbar.btn-primary:hover { background: var(--accent-hover); } /* Run Button Group — split button with dropdown */ .run-btn-group { display: flex; position: relative; } .btn-toolbar.btn-run { border-radius: var(--btn-radius) 0 0 var(--btn-radius); border-right: 1px solid rgba(255,255,255,0.12); font-weight: 600; padding: 0.45rem 0.9rem; gap: 0.45rem; letter-spacing: 0.01em; } .btn-toolbar.btn-run svg { flex-shrink: 0; width: 12px; height: 12px; } .btn-toolbar.btn-run-gear { border-radius: 0 var(--btn-radius) var(--btn-radius) 0; padding: 0.45rem 0.45rem; min-width: unset; } /* Claude mode colors (default) */ .btn-toolbar.btn-run.mode-claude, .btn-toolbar.btn-run-gear.mode-claude { background: linear-gradient(135deg, #1a3358 0%, #1e4fb8 50%, #2563eb 100%); border-color: rgba(59, 130, 246, 0.5); color: #e0e7ff; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); } .btn-toolbar.btn-run.mode-claude:hover, .btn-toolbar.btn-run-gear.mode-claude:hover { background: linear-gradient(135deg, #2454a8 0%, #2d6cf0 50%, #4b8af7 100%); box-shadow: 0 0 16px rgba(59, 130, 246, 0.4), 0 2px 8px rgba(59, 130, 246, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1); border-color: rgba(96, 165, 250, 0.6); color: #fff; } /* OpenCode mode colors */ .btn-toolbar.btn-run.mode-opencode, .btn-toolbar.btn-run-gear.mode-opencode { background: linear-gradient(135deg, #0a2e2a 0%, #0b3d35 50%, #0d4a40 100%); border-color: rgba(16, 185, 129, 0.5); color: #6ee7b7; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .btn-toolbar.btn-run.mode-opencode:hover, .btn-toolbar.btn-run-gear.mode-opencode:hover { background: linear-gradient(135deg, #0d4a40 0%, #116a58 50%, #15856e 100%); box-shadow: 0 0 12px rgba(16, 185, 129, 0.35), 0 2px 8px rgba(16, 185, 129, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(52, 211, 153, 0.6); color: #a7f3d0; } /* Codex mode colors */ .btn-toolbar.btn-run.mode-codex, .btn-toolbar.btn-run-gear.mode-codex { background: linear-gradient(135deg, #2a0a3e 0%, #350b4d 50%, #400d5e 100%); border-color: rgba(168, 85, 247, 0.5); color: #d8b4fe; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .btn-toolbar.btn-run.mode-codex:hover, .btn-toolbar.btn-run-gear.mode-codex:hover { background: linear-gradient(135deg, #400d5e 0%, #581c87 50%, #6b21a8 100%); box-shadow: 0 0 12px rgba(168, 85, 247, 0.35), 0 2px 8px rgba(168, 85, 247, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(192, 132, 252, 0.6); color: #e9d5ff; } /* Gemini mode colors */ .btn-toolbar.btn-run.mode-gemini, .btn-toolbar.btn-run-gear.mode-gemini { background: linear-gradient(135deg, #10243f 0%, #174ea6 55%, #4f46e5 100%); border-color: rgba(96, 165, 250, 0.5); color: #dbeafe; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .btn-toolbar.btn-run.mode-gemini:hover, .btn-toolbar.btn-run-gear.mode-gemini:hover { background: linear-gradient(135deg, #17345f 0%, #2563eb 55%, #6366f1 100%); box-shadow: 0 0 12px rgba(96, 165, 250, 0.35), 0 2px 8px rgba(99, 102, 241, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(147, 197, 253, 0.6); color: #eff6ff; } /* Antigravity mode colors */ .btn-toolbar.btn-run.mode-antigravity, .btn-toolbar.btn-run-gear.mode-antigravity { background: linear-gradient(135deg, #0b2b33 0%, #0e7490 55%, #0891b2 100%); border-color: rgba(34, 211, 238, 0.5); color: #cffafe; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .btn-toolbar.btn-run.mode-antigravity:hover, .btn-toolbar.btn-run-gear.mode-antigravity:hover { background: linear-gradient(135deg, #124450 0%, #0891b2 55%, #06b6d4 100%); box-shadow: 0 0 12px rgba(34, 211, 238, 0.35), 0 2px 8px rgba(8, 145, 178, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); border-color: rgba(103, 232, 249, 0.6); color: #ecfeff; } /* Dropdown menu */ .run-mode-menu { display: none; position: absolute; bottom: 100%; left: 0; margin-bottom: 6px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 10px; padding: 4px; z-index: 1000; min-width: 190px; /* Every long row inside (recent-session paths, saved URL names) ellipsizes, so the cap is a deliberate choice rather than a fit-the-content result: the menu overlays the terminal and does not need to reach across it. 250 rather than a rounder 240 because it is the width at which the common `~//` + timestamp recent-session row still fits whole, which is what that list is for. */ max-width: 250px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3); } .run-mode-menu.active { display: flex; flex-direction: column; gap: 2px; } .run-mode-option { display: flex; align-items: center; gap: 8px; padding: 7px 12px; background: none; border: none; border-radius: var(--btn-radius); color: var(--text); cursor: pointer; font-size: 0.8rem; white-space: nowrap; transition: background var(--transition-smooth); } .run-mode-option:hover { background: rgba(255, 255, 255, 0.07); } .run-mode-option.selected { background: rgba(255, 255, 255, 0.08); font-weight: 600; } .run-mode-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .run-mode-dot.claude { background: #3b82f6; } .run-mode-dot.opencode { background: #10b981; } .run-mode-dot.codex { background: #a855f7; } .run-mode-dot.gemini { background: #8ab4f8; } .run-mode-dot.antigravity { background: #22d3ee; } .run-mode-dot.shell { background: #94a3b8; } /* Phone-only Enter button (see index.html). Hidden by default at every width; mobile.css turns it on inside @media (max-width: 430px), where it takes over the slot the Shell button occupies on wider screens. */ .btn-toolbar.btn-enter { display: none; } .run-mode-sep { height: 1px; background: var(--border); margin: 4px 0; } .run-mode-header { padding: 4px 10px 2px; font-size: 0.72em; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 600; } .run-mode-history { max-height: 200px; overflow-y: auto; } /* `overflow-y: auto` computes overflow-x to auto as well, which makes this a scroll container and lets a row size itself to its own content. A long path therefore scrolled sideways instead of ellipsizing, and before the menu was narrowed it simply pinned the menu at its max-width. */ .run-mode-history .run-mode-option { max-width: 100%; } .run-mode-option .hist-dir { flex: 1; /* A flex item's default min-width is auto, so without this the path refuses to shrink below its own text and pushes the date out of the menu instead of ellipsizing. Only visible once the menu is narrow enough to force the choice. */ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .run-mode-option .hist-meta { font-size: 0.85em; color: var(--text-muted); white-space: nowrap; } .run-mode-hist-empty { padding: 6px 10px; color: var(--text-muted); font-style: italic; } /* Shell Button - Special styling */ .btn-toolbar.btn-shell { background: linear-gradient(135deg, #1a2e1a 0%, #1e3a1e 50%, #234023 100%); border-color: rgba(45, 90, 45, 0.6); color: #8fbc8f; font-weight: 600; letter-spacing: 0.01em; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05); } .btn-toolbar.btn-shell:hover { background: linear-gradient(135deg, #234023 0%, #2d5a2d 50%, #357035 100%); border-color: rgba(61, 122, 61, 0.7); box-shadow: 0 0 12px rgba(34, 139, 34, 0.3), 0 2px 8px rgba(34, 139, 34, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.08); color: #a8d8a8; } /* btn-opencode standalone removed — now part of run-btn-group mode system */ /* Stop button - hidden on desktop, shown on mobile */ .btn-toolbar.btn-stop { display: none; background: linear-gradient(135deg, #4a1515 0%, #5a1a1a 50%, #7f1d1d 100%); border-color: rgba(220, 38, 38, 0.5); color: #fca5a5; font-weight: 600; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05); } .btn-toolbar.btn-stop:hover { background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 50%, #b91c1c 100%); border-color: rgba(239, 68, 68, 0.6); box-shadow: 0 0 12px rgba(220, 38, 38, 0.35), 0 2px 8px rgba(220, 38, 38, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08); color: #fff; } .btn-toolbar.btn-stop svg { flex-shrink: 0; width: 12px; height: 12px; } .btn-toolbar.btn-stop.confirming { background: linear-gradient(135deg, #6b4f00 0%, #856200 100%); border-color: #b8860b; color: #ffd54f; font-size: 0.65rem; white-space: nowrap; } /* Touch devices (iPad, tablets): show stop button — no physical Ctrl+C */ .touch-device .btn-toolbar.btn-stop { display: flex; } /* Mobile app settings gear - hidden on desktop, shown on mobile */ .btn-settings-mobile { display: none; } /* Mobile case button - hidden on desktop, shown on mobile */ .btn-toolbar.btn-case-mobile { display: none; background: transparent; border: 1px solid rgba(255, 255, 255, 0.2); color: #9ca3af; gap: 4px; } .btn-toolbar.btn-case-mobile:hover { background: rgba(255, 255, 255, 0.1); color: #fff; } .btn-toolbar.btn-case-mobile svg { flex-shrink: 0; } .btn-toolbar.btn-case-mobile #mobileCaseName { max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Mobile voice input button - hidden on desktop */ .btn-voice-mobile { display: none; } /* Mobile case settings gear - hidden on desktop */ .btn-case-settings-mobile { display: none; } .case-settings-popover-mobile { display: none; } .case-settings-popover-mobile.hidden { display: none; } /* Button icon styling */ .btn-toolbar .btn-icon { display: inline-flex; align-items: center; justify-content: center; } .btn-toolbar.btn-success { background: linear-gradient(135deg, #16a34a 0%, #22c55e 100%); border-color: rgba(34, 197, 94, 0.5); color: white; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1); } .btn-toolbar.btn-success:hover { background: linear-gradient(135deg, #15803d 0%, #16a34a 100%); box-shadow: 0 0 10px rgba(34, 197, 94, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); } .btn-toolbar.btn-danger { color: var(--red); border-color: rgba(239, 68, 68, 0.2); } .btn-toolbar.btn-danger:hover { background: linear-gradient(135deg, #b91c1c 0%, #ef4444 100%); color: white; border-color: rgba(239, 68, 68, 0.5); box-shadow: 0 0 10px rgba(239, 68, 68, 0.25); } /* Voice Input Button — desktop only (mobile uses .btn-voice-mobile) */ .btn-toolbar.btn-voice { padding: 0.3rem 0.5rem; } @media (max-width: 1023px) { .toolbar-center .btn-toolbar.btn-voice { display: none !important; } } .btn-toolbar.btn-voice:hover { color: var(--text); border-color: rgba(59, 130, 246, 0.4); } .btn-toolbar.btn-voice.recording { background: rgba(239, 68, 68, 0.2); border-color: rgba(239, 68, 68, 0.6); color: #ef4444; animation: voice-pulse 1.2s ease-in-out infinite; } .btn-toolbar.btn-voice.recording:hover { background: rgba(239, 68, 68, 0.3); border-color: rgba(239, 68, 68, 0.8); color: #f87171; } @keyframes voice-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.5); background: rgba(239, 68, 68, 0.2); } 50% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); background: rgba(239, 68, 68, 0.35); } } @media (prefers-reduced-motion: reduce) { .btn-toolbar.btn-voice.recording, .btn-voice-mobile.recording { animation: none; } } /* Voice preview overlay — shows interim transcription */ .voice-preview { position: fixed; bottom: 48px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.88); color: rgba(255, 255, 255, 0.7); font-style: italic; font-family: var(--font-mono, monospace); padding: 8px 20px; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.1); font-size: 0.85rem; max-width: 80%; max-height: 3.6em; overflow: hidden; z-index: 10001; pointer-events: none; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); } .voice-preview-badge { display: inline-block; font-size: 0.6rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; background: rgba(59, 130, 246, 0.3); color: #60a5fa; padding: 1px 5px; border-radius: 3px; font-style: normal; vertical-align: middle; } .voice-provider-status { font-size: 0.75rem; color: var(--text-dim); padding: 2px 8px; border-radius: 4px; background: rgba(255, 255, 255, 0.05); } .voice-provider-status.active { color: #4ade80; background: rgba(74, 222, 128, 0.1); } /* Voice recording indicator (red dot + level bars + timer) */ .voice-recording-indicator { display: inline-flex; align-items: center; gap: 6px; margin-right: 8px; flex-shrink: 0; } .voice-rec-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #ef4444; animation: voice-rec-blink 1s ease-in-out infinite; } @keyframes voice-rec-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } .voice-level-bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; } .voice-level-bar { display: inline-block; width: 3px; background: rgba(239, 68, 68, 0.25); border-radius: 1px; transition: background 0.1s ease, height 0.1s ease; } .voice-level-bar:nth-child(1) { height: 4px; } .voice-level-bar:nth-child(2) { height: 7px; } .voice-level-bar:nth-child(3) { height: 10px; } .voice-level-bar:nth-child(4) { height: 13px; } .voice-level-bar:nth-child(5) { height: 14px; } .voice-level-bar.active { background: #ef4444; } .voice-timer { font-size: 0.7rem; font-weight: 600; color: #ef4444; font-variant-numeric: tabular-nums; min-width: 2.5em; } /* Enhanced recording state on voice preview */ .voice-preview:has(.voice-recording-indicator) { border-color: rgba(239, 68, 68, 0.3); background: rgba(20, 0, 0, 0.92); } @media (prefers-reduced-motion: reduce) { .voice-rec-dot { animation: none; opacity: 1; } } /* Voice send button — gear icon transforms into green Enter after voice input */ .voice-send-active { background: rgba(34, 197, 94, 0.2) !important; border-color: rgba(34, 197, 94, 0.7) !important; color: #22c55e !important; animation: voice-send-glow 1.4s ease-in-out infinite; } .voice-send-active:active { transform: scale(0.9); background: rgba(34, 197, 94, 0.4) !important; } @keyframes voice-send-glow { 0%, 100% { box-shadow: 0 0 4px rgba(34, 197, 94, 0.3); border-color: rgba(34, 197, 94, 0.5) !important; } 50% { box-shadow: 0 0 12px rgba(34, 197, 94, 0.6); border-color: rgba(34, 197, 94, 0.9) !important; } } .voice-send-active.voice-send-blink { animation: voice-send-flash 0.4s ease-out !important; } @keyframes voice-send-flash { 0% { background: rgba(34, 197, 94, 0.6) !important; box-shadow: 0 0 16px rgba(34, 197, 94, 0.8); } 100% { background: transparent !important; box-shadow: none; opacity: 0; } } @media (prefers-reduced-motion: reduce) { .voice-send-active { animation: none; box-shadow: 0 0 6px rgba(34, 197, 94, 0.4); } .voice-send-active.voice-send-blink { animation: none; } } .form-row input[type="password"] { width: 100%; padding: 0.5rem 0.75rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.8rem; font-family: inherit; } .form-row input[type="password"]:focus { outline: none; border-color: var(--accent); } .btn-icon-only { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; background: transparent; border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--btn-radius); color: var(--text-dim); font-size: 0.7rem; cursor: pointer; transition: all var(--transition-smooth); } .btn-icon-only:hover { background: rgba(255, 255, 255, 0.07); color: var(--text); } /* Case select group with + button */ .case-select-group { display: flex; align-items: stretch; position: relative; } .case-combobox { position: relative; width: clamp(170px, 18vw, 280px); } .case-combobox-input { width: 100%; height: 100%; min-height: 28px; padding: 0.4rem 1.6rem 0.4rem 0.65rem; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--btn-radius) 0 0 var(--btn-radius); color: var(--text-dim); font-size: 0.75rem; font-family: inherit; outline: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b8b97' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.5rem center; transition: border-color var(--transition-smooth), background var(--transition-smooth), box-shadow var(--transition-smooth); } .case-combobox-input:hover, .case-combobox-input:focus { background-color: rgba(255, 255, 255, 0.07); border-color: var(--accent); color: var(--text); box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2); } .case-combobox-list { position: absolute; left: 0; bottom: calc(100% + 8px); width: min(340px, calc(100vw - 24px)); max-height: min(320px, 55vh); overflow-y: auto; padding: 0.35rem; background: rgba(22, 27, 35, 0.98); border: 1px solid rgba(120, 141, 170, 0.28); border-radius: 8px; box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04) inset; z-index: 1000; } .case-combobox-list.hidden { display: none; } .case-combobox-option { display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; width: 100%; min-height: 34px; padding: 0.35rem 0.45rem; background: transparent; border: 1px solid transparent; border-radius: 6px; color: var(--text-dim); font: inherit; font-size: 0.78rem; text-align: left; cursor: pointer; } .case-combobox-option:hover, .case-combobox-option.active { background: rgba(59, 130, 246, 0.16); border-color: rgba(96, 165, 250, 0.28); color: var(--text); } .case-combobox-option.selected { color: var(--text); } .case-combobox-check { color: var(--green); font-weight: 700; } .case-combobox-option-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .case-combobox-empty { padding: 0.85rem 0.75rem; color: var(--text-muted); font-size: 0.78rem; text-align: center; } .toolbar-select { padding: 0.4rem 1.5rem 0.4rem 0.6rem; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--btn-radius) 0 0 var(--btn-radius); color: var(--text-dim); font-size: 0.75rem; cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%238b8b97' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.4rem center; width: fit-content; min-width: unset; max-width: unset; transition: all var(--transition-smooth); } .toolbar-select.case-native-select { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; opacity: 0; pointer-events: none; } .toolbar-select:hover { border-color: rgba(255, 255, 255, 0.12); background: rgba(255, 255, 255, 0.07); } .toolbar-select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2); } .btn-case-add { display: flex; align-items: center; justify-content: center; width: 28px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.07); border-left: none; border-radius: 0; color: var(--green); font-size: 1.1rem; font-weight: 500; cursor: pointer; transition: all var(--transition-smooth); } .btn-case-add:hover { background: var(--green); color: white; border-color: var(--green); box-shadow: 0 0 8px rgba(34, 197, 94, 0.3); } .btn-case-settings { display: flex; align-items: center; justify-content: center; width: 28px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.07); border-left: none; border-radius: 0 var(--btn-radius) var(--btn-radius) 0; color: var(--text-dim); font-size: 1rem; cursor: pointer; transition: all var(--transition-smooth); } .btn-case-settings:hover { background: var(--accent); color: white; border-color: var(--accent); } .case-settings-popover { position: absolute; bottom: 100%; right: 0; margin-bottom: 6px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 10px; padding: 0.6rem 0.7rem; width: 220px; z-index: 1000; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2); } .case-settings-popover.hidden { display: none; } .case-settings-popover .form-hint { margin-top: 0.2rem; font-size: 0.6rem; } /* Case Management List (Manage tab) */ .case-manage-list { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow-y: auto; } .case-manage-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 6px; transition: background var(--transition-smooth); } /* COD-105 — discovered remote tmux sessions list (remote-case flow). */ .remote-discover-results { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; } .remote-discover-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 6px; } .remote-discover-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .remote-discover-name { font-weight: 600; font-size: 0.85rem; } .case-manage-item:hover { background: rgba(255, 255, 255, 0.06); } .case-manage-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; } .case-manage-name { font-size: 0.8rem; font-weight: 500; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .case-manage-path { font-size: 0.65rem; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .case-manage-actions { display: flex; gap: 4px; margin-left: 10px; flex-shrink: 0; } .case-manage-btn { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 4px; color: var(--text-dim); font-size: 0.65rem; cursor: pointer; transition: all var(--transition-smooth); } .case-manage-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); color: var(--text); } .case-manage-btn:disabled { opacity: 0.25; cursor: not-allowed; } .case-manage-btn-delete:hover:not(:disabled) { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.3); color: #ef4444; } .toolbar-input { padding: 0.4rem 0.5rem; background: var(--bg-input); border: 1px solid var(--accent); border-radius: 4px; color: var(--text); font-size: 0.75rem; width: 350px; max-width: 50vw; } /* Tab Count Input Group - nicer stepper design */ .tab-count-group { display: flex; align-items: center; background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--btn-radius); overflow: hidden; margin: 0 0.25rem; } .tab-count-btn { display: flex; align-items: center; justify-content: center; width: 22px; height: 26px; background: transparent; border: none; color: var(--text-dim); font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: all var(--transition-smooth); } .tab-count-btn:hover { background: rgba(255, 255, 255, 0.08); color: var(--accent-hover); } .tab-count-btn:active { background: var(--accent); color: white; } .tab-count-input { width: 24px; height: 26px; background: transparent; border: none; border-left: 1px solid var(--border); border-right: 1px solid var(--border); color: var(--text); font-size: 0.75rem; font-weight: 600; text-align: center; font-family: 'SF Mono', Monaco, monospace; -moz-appearance: textfield; } .tab-count-input::-webkit-inner-spin-button, .tab-count-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } .tab-count-input:focus { outline: none; } .toolbar-input-sm { padding: 0.3rem 0.4rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.75rem; width: 40px; text-align: center; } .toolbar-input-sm:focus { outline: none; border-color: var(--accent); } .toolbar-input-sm::-webkit-inner-spin-button, .toolbar-input-sm::-webkit-outer-spin-button { opacity: 1; height: 16px; } #dirDisplay { max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left; } .toolbar-input:focus { outline: none; } .toolbar-input.hidden { display: none; } .font-size-display { font-size: 0.65rem; color: var(--text-muted); min-width: 20px; text-align: center; font-family: 'SF Mono', Monaco, monospace; } /* Close button for modals */ .btn-close { background: transparent; border: none; color: var(--text-dim); font-size: 1.2rem; cursor: pointer; padding: 0 0.25rem; line-height: 1; } .btn-close:hover { color: var(--text); } .btn-icon-sm { background: transparent; border: none; color: var(--text-dim); font-size: 1rem; cursor: pointer; padding: 0.25rem; line-height: 1; border-radius: 4px; } .btn-icon-sm:hover { color: var(--text); background: var(--bg-hover); } .settings-section { margin-bottom: 1.25rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border); } .settings-section:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .form-row { margin-bottom: 0.75rem; } .form-row label { display: block; font-size: 0.7rem; color: var(--text-dim); margin-bottom: 0.35rem; text-transform: uppercase; letter-spacing: 0.03em; } .form-row input[type="text"], .form-row input[type="number"], .form-row textarea, .form-select { width: 100%; padding: 0.5rem 0.75rem; background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: var(--btn-radius); color: var(--text); font-size: 0.8rem; font-family: inherit; transition: border-color var(--transition-smooth), box-shadow var(--transition-smooth); } /* Selects: strip the native control so the field follows the active skin. Opaque --bg-input fill + --border, a custom chevron, and the skin's color-scheme keep option popups coherent in both modes. */ .form-select { padding-right: 2rem; background-color: var(--bg-input); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2398a2b1' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.7rem center; background-size: 0.75rem; border-color: var(--border); appearance: none; -webkit-appearance: none; -moz-appearance: none; cursor: pointer; } .form-row input:focus, .form-row textarea:focus, .form-select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15); } .form-col { flex: 1; } .form-col label { display: block; font-size: 0.7rem; color: var(--text-dim); margin-bottom: 0.35rem; text-transform: uppercase; letter-spacing: 0.03em; } .input-suffix { display: flex; align-items: center; } .input-suffix input { flex: 1; border-radius: 4px 0 0 4px; border-right: none; } .input-suffix span { padding: 0.5rem 0.5rem; background: var(--bg-hover); border: 1px solid var(--border); border-radius: 0 4px 4px 0; color: var(--text-muted); font-size: 0.75rem; } .form-hint { display: block; font-size: 0.65rem; color: var(--text-muted); margin-top: 0.35rem; } /* Preset selector */ .preset-selector { display: flex; gap: 8px; align-items: center; } .preset-selector select { flex: 1; min-width: 0; padding: 0.4rem 0.5rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.75rem; } .preset-selector select:focus { outline: none; border-color: var(--accent); } .preset-selector .btn-sm { white-space: nowrap; padding: 4px 8px; font-size: 0.7rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); cursor: pointer; transition: all 0.15s; } .preset-selector .btn-sm:hover { background: var(--bg-hover); border-color: var(--border-light); } /* Switch toggle for form rows */ .form-section-header { font-size: 0.7rem; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; margin: 1rem 0 0.5rem 0; padding-bottom: 0.25rem; border-bottom: 1px solid var(--border); } .form-section-header:first-child { margin-top: 0; } .form-row-switch { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; } .form-row-switch > label:first-child { margin-bottom: 0; min-width: 120px; } .form-row-switch .form-hint { flex-basis: 100%; margin-top: 0.25rem; } .switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; } .switch input { opacity: 0; width: 0; height: 0; } .switch .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08); transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1); border-radius: 20px; } .switch .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 2px; bottom: 2px; background-color: var(--text-muted); transition: 0.2s; border-radius: 50%; } .switch input:checked + .slider { background-color: var(--accent); border-color: var(--accent); } .switch input:checked + .slider:before { transform: translateX(16px); background-color: white; } .switch input:focus + .slider { box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3); } /* Smaller switch variant for compact settings grid */ .switch-sm { width: 28px; height: 16px; } .switch-sm .slider:before { height: 10px; width: 10px; left: 2px; bottom: 2px; } .switch-sm input:checked + .slider:before { transform: translateX(12px); } /* Settings Grid Layout - 2 column compact view */ .settings-grid { display: grid; /* minmax(0, 1fr) lets tracks shrink below their min-content so long labels ellipsis-truncate instead of blowing out the modal width and forcing a horizontal scrollbar (1fr === minmax(auto, 1fr) would not). */ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.5rem 1rem; } .settings-section-header { grid-column: 1 / -1; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); padding: 0.5rem 0 0.25rem 0; border-bottom: 1px solid var(--border); margin-top: 0.75rem; } .settings-section-header:first-child { margin-top: 0; } .settings-item { display: flex; align-items: center; justify-content: space-between; padding: 0.45rem 0.7rem; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: var(--btn-radius); font-size: 0.75rem; transition: background var(--transition-smooth); } .settings-item-label { color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .settings-inline-input, .settings-inline-select { width: min(190px, 52%); min-width: 0; padding: 0.3rem 0.45rem; border: 1px solid var(--border); border-radius: 4px; background: var(--bg-input); color: var(--text); font: inherit; } .settings-inline-input:focus, .settings-inline-select:focus { outline: none; border-color: var(--accent); } /* Skin picker: full-width row (not squeezed into a half-width grid cell) with an auto-width select, so the "Skin" label keeps its space instead of truncating. */ .settings-item-skin { grid-column: 1 / -1; gap: 0.75rem; } .settings-item-skin .settings-item-label { flex: 0 0 auto; } .settings-item-skin .form-select { width: auto; min-width: 220px; max-width: 320px; flex: 0 1 auto; /* Match the field to its settings row: the base .form-select (0.8rem / 0.5rem padding) renders bigger and taller than the row, and the daylight skins' Manrope font exaggerates it further. Slim it to the row's 0.75rem text. */ font-size: 0.75rem; padding-top: 0.3rem; padding-bottom: 0.3rem; } .settings-item-multiline { align-items: center; } .settings-item-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; } .settings-item-desc { font-size: 0.6rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .settings-item-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; } /* Three column variant for notification levels */ .settings-grid-3col { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); } /* Inline input in settings item */ .settings-item-input { width: 60px; padding: 0.2rem 0.4rem; font-size: 0.7rem; background: var(--bg-dark); border: 1px solid var(--border); border-radius: 3px; color: var(--text); text-align: right; } .settings-item-input:focus { outline: none; border-color: var(--accent); } /* Status badge in settings */ .settings-status { font-size: 0.6rem; padding: 2px 6px; border-radius: 3px; background: var(--bg-hover); color: var(--text-dim); } .settings-status.granted { background: rgba(34, 197, 94, 0.2); color: var(--green); } .settings-status.denied { background: rgba(239, 68, 68, 0.2); color: var(--red); } /* Event Type Notification Grid */ .event-type-grid { display: grid; grid-template-columns: 1fr 50px 50px 50px 50px; gap: 6px 8px; align-items: center; margin-top: 8px; padding: 8px; background: var(--bg-dark); border-radius: 4px; } .event-header { font-size: 0.65rem; text-transform: uppercase; color: var(--text-dim); text-align: center; font-weight: 500; } .event-header:first-child { text-align: left; } .event-label { font-size: 0.75rem; color: var(--text); } .event-type-grid input[type="checkbox"] { justify-self: center; width: 14px; height: 14px; cursor: pointer; } /* Session Color Picker */ .color-picker { display: flex; gap: 6px; flex-wrap: wrap; } .color-swatch { width: 28px; height: 28px; border-radius: 4px; border: 2px solid transparent; background: transparent; padding: 2px; cursor: pointer; transition: border-color 0.15s, transform 0.1s; } .color-swatch:hover { transform: scale(1.1); } .color-swatch.selected { border-color: var(--accent); } .swatch-inner { display: block; width: 100%; height: 100%; border-radius: 2px; } .form-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem; padding: 0.75rem; border-top: 1px solid var(--border); } /* Modal */ .modal { display: none; position: fixed; inset: 0; z-index: 1000; align-items: center; justify-content: center; contain: layout paint; } .modal.active { display: flex; } .modal-backdrop { position: absolute; inset: 0; background: var(--modal-backdrop); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); } .modal-content { position: relative; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 12px; width: 90%; max-width: 400px; box-shadow: var(--elevated-shadow); /* Performance: isolate modal paint operations */ contain: layout style paint; } .modal-content.modal-sm { max-width: 340px; } .modal-content.modal-lg { max-width: 540px; max-height: 85vh; display: flex; flex-direction: column; } .modal-content.modal-lg > .modal-body { overflow-y: auto; flex: 1; min-height: 0; } /* App Settings packs a 2-column toggle grid; give it room so right-column switches aren't cramped against the edge (other modal-lg modals stay 540). */ #appSettingsModal .modal-content.modal-lg { max-width: 600px; } /* Mobile Case Picker - Base Styles */ .mobile-case-picker-sheet { position: fixed; bottom: 0; left: 0; right: 0; background: var(--floating-bg); border-radius: 16px 16px 0 0; max-height: 70vh; display: flex; flex-direction: column; z-index: 1001; box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.4); } .mobile-case-picker-header { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .mobile-case-picker-header h3 { margin: 0; font-size: 1.1rem; font-weight: 600; color: #fff; } .mobile-case-picker-body { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 8px 0; max-height: 50vh; } .mobile-case-list { display: flex; flex-direction: column; } .mobile-case-item { display: flex; align-items: center; gap: 12px; padding: 14px 20px; background: transparent; border: none; color: #e5e5e5; font-size: 0.95rem; text-align: left; cursor: pointer; transition: background 0.1s; width: 100%; } .mobile-case-item:hover { background: rgba(255, 255, 255, 0.05); } .mobile-case-item:active { background: rgba(255, 255, 255, 0.1); } .mobile-case-item.selected { background: rgba(34, 197, 94, 0.15); color: #22c55e; } .mobile-case-item-icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; color: #666; flex-shrink: 0; } .mobile-case-item.selected .mobile-case-item-icon { color: #22c55e; } .mobile-case-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .mobile-case-item-check { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; color: #22c55e; opacity: 0; flex-shrink: 0; } .mobile-case-item.selected .mobile-case-item-check { opacity: 1; } .mobile-case-item-delete { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--text-dim); opacity: 0.4; flex-shrink: 0; border-radius: 4px; transition: all var(--transition-smooth); } .mobile-case-item-delete:active { opacity: 1; color: #ef4444; background: rgba(239, 68, 68, 0.15); } .mobile-case-picker-footer { padding: 12px 20px 16px; border-top: 1px solid rgba(255, 255, 255, 0.1); } .btn-case-create-mobile { width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px 16px; background: var(--bg-input); border: 1px solid var(--border-light); border-radius: 8px; color: var(--text); font-size: 0.9rem; font-weight: 500; cursor: pointer; transition: background 0.15s; } .btn-case-create-mobile:hover { background: var(--bg-hover); } .btn-case-create-mobile:active { background: var(--bg-hover); } .btn-case-create-mobile svg { width: 16px; height: 16px; } /* Fix Plan Modal */ .fix-plan-modal { max-width: 600px; width: 95%; } .fix-plan-textarea { width: 100%; height: 400px; font-family: 'SF Mono', Monaco, 'Menlo', monospace; font-size: 0.75rem; line-height: 1.4; background: var(--bg-dark); color: var(--text); border: 1px solid var(--border); border-radius: 4px; padding: 0.75rem; resize: vertical; } .fix-plan-stats { color: var(--text-muted); font-size: 0.75rem; margin-right: auto; } /* Run Summary Modal */ /* Summary tab scrollable container */ #summary-tab { display: flex; flex-direction: column; max-height: calc(70vh - 120px); overflow: hidden; } /* Fix CSS specificity: ID selector overrides class selector, so we need this explicit rule */ #summary-tab.hidden, #respawn-tab.hidden, #context-tab.hidden, #ralph-tab.hidden { display: none !important; } /* Also hide child elements when parent tab is hidden (belt and suspenders) */ #summary-tab.hidden .run-summary-filters, #summary-tab.hidden .run-summary-timeline, #summary-tab.hidden .run-summary-footer { display: none !important; } #summary-tab .run-summary-filters { flex-shrink: 0; } #summary-tab .run-summary-timeline { flex: 1; min-height: 0; max-height: none; } #summary-tab .run-summary-footer { flex-shrink: 0; } .run-summary-filters { display: flex; gap: 0.375rem; margin-bottom: 0.75rem; flex-wrap: wrap; } .filter-btn { padding: 0.25rem 0.625rem; background: transparent; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 100px; color: var(--text-dim); cursor: pointer; font-size: 0.7rem; transition: all 0.15s; } .filter-btn:hover { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.15); color: var(--text); } .filter-btn.active { background: var(--accent); border-color: var(--accent); color: var(--bg); } .run-summary-timeline { max-height: 400px; overflow-y: auto; padding-right: 0.25rem; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.1) transparent; } .run-summary-timeline::-webkit-scrollbar { width: 4px; } .run-summary-timeline::-webkit-scrollbar-track { background: transparent; } .run-summary-timeline::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 2px; } .run-summary-timeline::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.2); } .timeline-event { display: flex; gap: 0.5rem; padding: 0.5rem 0.625rem; margin-bottom: 0.375rem; background: rgba(255, 255, 255, 0.02); border-radius: 6px; border-left: 2px solid var(--border); transition: background 0.15s; content-visibility: auto; contain-intrinsic-size: auto 40px; } .timeline-event:hover { background: rgba(255, 255, 255, 0.04); } .timeline-event.event-success { border-left-color: var(--green); } .timeline-event.event-warning { border-left-color: var(--yellow); } .timeline-event.event-error { border-left-color: var(--red); } .timeline-event.event-info { border-left-color: var(--accent); } .event-icon { font-size: 0.9rem; flex-shrink: 0; opacity: 0.8; } .event-content { flex: 1; min-width: 0; } .event-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.5rem; } .event-title { font-weight: 500; font-size: 0.8rem; color: var(--text); } .event-time { font-size: 0.65rem; color: var(--text-muted); flex-shrink: 0; font-family: 'SF Mono', Monaco, monospace; } .event-details { font-size: 0.7rem; color: var(--text-dim); margin-top: 0.125rem; } .run-summary-session-info { font-size: 0.7rem; color: var(--text-muted); font-family: 'SF Mono', Monaco, monospace; padding: 0.25rem 0; } .run-summary-footer { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.75rem; padding-top: 0.625rem; border-top: 1px solid rgba(255, 255, 255, 0.06); } .run-summary-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } .run-summary-actions .btn-toolbar { font-size: 0.7rem; padding: 0.25rem 0.5rem; } .auto-refresh-label { display: flex; align-items: center; gap: 0.25rem; font-size: 0.7rem; color: var(--text-dim); cursor: pointer; } .auto-refresh-label input[type="checkbox"] { cursor: pointer; width: 12px; height: 12px; } /* Empty message for timeline */ .run-summary-timeline .empty-message { color: var(--text-muted); font-size: 0.75rem; text-align: center; padding: 2rem 1rem; margin: 0; } /* Legacy run summary modal footer */ #runSummaryModal .modal-footer { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.75rem 1rem; border-top: 1px solid rgba(255, 255, 255, 0.06); } #runSummaryModal .modal-footer .run-summary-session-info { font-size: 0.7rem; color: var(--text-muted); font-family: 'SF Mono', Monaco, monospace; } .modal-warning-text { color: var(--text-dim); font-size: 0.85rem; margin-bottom: 0.5rem; } /* Close Session Options */ .close-options { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; } .close-option { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 0.75rem 1rem; background: var(--bg-hover); border: 1px solid var(--border); border-radius: 6px; cursor: pointer; transition: all 0.15s; text-align: left; } .close-option:hover { background: var(--bg-card); border-color: var(--accent); } .close-option-danger { border-color: var(--red); background: rgba(239, 68, 68, 0.1); } .close-option-danger:hover { background: rgba(239, 68, 68, 0.2); border-color: var(--red); } .close-option-title { font-weight: 500; font-size: 0.9rem; color: var(--text); } .close-option-danger .close-option-title { color: var(--red); } .close-option-desc { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.15rem; } .modal-footer-cancel { display: flex; justify-content: center; padding-top: 0.5rem; border-top: 1px solid var(--border); } .modal-session-name { font-family: 'SF Mono', Monaco, monospace; font-size: 0.8rem; color: var(--accent-hover); background: var(--bg-input); padding: 0.5rem 0.75rem; border-radius: 4px; border: 1px solid var(--border); } /* Session respawn section in options modal */ .session-respawn-section { padding-top: 0; margin-top: 0; } .session-respawn-status { display: flex; align-items: center; gap: 0.4rem; font-size: 0.75rem; padding: 0.25rem 0.5rem; background: var(--bg-input); border-radius: 4px; } .session-respawn-status .respawn-status-indicator { width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); } .session-respawn-status .respawn-status-text { color: var(--text-dim); } .session-respawn-status.active .respawn-status-indicator { background: var(--green); animation: pulse 1.5s infinite; } .session-respawn-status.active .respawn-status-text { color: var(--green); } /* Inline checkbox group */ .checkbox-inline { display: flex; align-items: center; gap: 0.35rem; cursor: pointer; font-size: 0.8rem; color: var(--text-dim); } .checkbox-inline input[type="checkbox"] { accent-color: var(--accent); } .checkbox-inline:hover { color: var(--text); } .input-suffix-sm { display: flex; align-items: center; } .input-suffix-sm input { width: 80px; padding: 0.35rem 0.5rem; font-size: 0.75rem; } .input-suffix-sm span { padding: 0.35rem 0.4rem; font-size: 0.7rem; } /* Duration preset buttons */ .duration-presets { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; } .duration-preset-btn { padding: 0.4rem 0.7rem; font-size: 0.75rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); cursor: pointer; transition: all 0.15s; } .duration-preset-btn:hover { border-color: var(--border-light); color: var(--text); } .duration-preset-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } .duration-custom { display: flex; align-items: center; gap: 0.35rem; } .duration-custom-input { display: none; } .duration-custom-input.visible { display: flex; } .duration-custom-input input { width: 60px; } /* Respawn status + Enable/Stop row — sits at the bottom of the Respawn tab, below the settings it acts on */ .respawn-header { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid rgba(34, 197, 94, 0.2); } .respawn-header .respawn-actions { margin: 0; padding: 0; border: none; } /* Respawn options row - inline checkboxes */ .respawn-options-row { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 0.25rem; } /* Auto-resume on usage limit (token pause control) */ .auto-resume-box { display: flex; flex-direction: column; gap: 0.3rem; margin: 0.75rem 0; padding: 0.6rem 0.75rem; background: rgba(59, 130, 246, 0.07); border: 1px solid rgba(59, 130, 246, 0.35); border-radius: 6px; } .auto-resume-box .checkbox-inline { font-size: 0.85rem; font-weight: 500; color: var(--text); } .auto-resume-box .form-hint { margin-top: 0; } /* Respawn loop box — groups every setting that belongs to the autonomous respawn cycle (duration, presets, cycle prompts, enable). Green like its Enable button; a visual sibling of the standalone auto-resume option above */ .respawn-loop-box { margin: 0.75rem 0; padding: 0.6rem 0.75rem; background: rgba(34, 197, 94, 0.05); border: 1px solid rgba(34, 197, 94, 0.3); border-radius: 6px; } .respawn-loop-title { font-size: 0.85rem; font-weight: 500; color: var(--text); margin-bottom: 0.3rem; } .respawn-loop-hint { display: block; margin-top: 0; margin-bottom: 0.5rem; } .respawn-loop-box .form-section-header { border-bottom-color: rgba(34, 197, 94, 0.2); } /* Match the cycle-step checkboxes (2./3.) to the step labels (1./4.) */ .respawn-loop-box .checkbox-inline { font-size: 0.7rem; } .auto-resume-status { display: none; font-size: 0.7rem; font-weight: 600; color: var(--accent-hover); } .auto-resume-status.active { display: block; } /* Respawn actions in modal */ .respawn-actions { display: flex; gap: 0.5rem; } /* Modal Tabs */ .modal-tabs { display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0 1rem 0.75rem 1rem; border-bottom: 1px solid var(--border); } .modal-tab-btn { padding: 0.5rem 1rem; font-size: 0.8rem; background: transparent; border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); cursor: pointer; transition: all 0.15s; } .modal-tab-btn:hover { background: var(--bg-input); color: var(--text); } .modal-tab-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } .modal-tab-content.hidden { display: none !important; } /* Context Tab Settings Grid */ .context-settings-grid { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 0.75rem; } .context-setting { padding: 0.875rem; background: rgba(255, 255, 255, 0.02); border: 1px solid var(--border); border-radius: 6px; } .context-setting-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.625rem; } .context-setting-header .checkbox-inline span { font-weight: 500; } .context-setting-header .input-suffix-sm { flex-shrink: 0; } .context-setting-header .input-suffix-sm input { width: 70px; } .context-setting input[type="text"] { width: 100%; padding: 0.375rem 0.5rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.75rem; } .context-setting input[type="text"]:focus { outline: none; border-color: var(--accent); } .context-setting .form-hint { margin-top: 0.5rem; } /* Ralph Limits Grid */ .ralph-limits-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-bottom: 0.5rem; } @media (max-width: 500px) { .ralph-limits-grid { grid-template-columns: 1fr 1fr; } } .ralph-limits-grid .form-col input[type="number"] { width: 100%; padding: 0.375rem 0.5rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.8rem; } .ralph-limits-grid .form-col .form-hint { font-size: 0.6rem; } /* Ralph Config Actions */ .ralph-config-actions { display: flex; gap: 0.5rem; margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border); } .modal-header { display: flex; justify-content: space-between; align-items: center; padding: 1rem 1.25rem; border-bottom: 1px solid rgba(255, 255, 255, 0.06); } .modal-header h3 { font-size: 0.95rem; font-weight: 600; } .modal-header-actions { display: flex; align-items: center; gap: 0.25rem; } .modal-close { background: transparent; border: none; color: var(--text-dim); font-size: 1.5rem; cursor: pointer; line-height: 1; } .modal-close:hover { color: var(--text); } .modal-body { padding: 1rem; } .shortcuts-grid { display: grid; grid-template-columns: auto 1fr; gap: 0.5rem 1rem; font-size: 0.8rem; } .shortcuts-grid > div:nth-child(odd) { text-align: right; } .shortcuts-grid > div:nth-child(even) { color: var(--text-dim); } kbd { display: inline-block; padding: 0.15rem 0.45rem; background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 5px; font-family: 'SF Mono', Monaco, monospace; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); font-size: 0.7rem; color: var(--text); } /* Away Digest Modal */ .away-digest-modal { max-width: 860px; width: min(92vw, 860px); max-height: 86vh; display: flex; flex-direction: column; } .away-digest-modal .modal-body { overflow-y: auto; padding: 1rem; } /* Command palette (COD-153) */ .command-palette-modal { align-items: flex-start; padding-top: min(16vh, 120px); } .command-palette-shell { position: relative; width: min(92vw, 620px); max-height: min(70vh, 620px); display: flex; flex-direction: column; overflow: hidden; background: var(--floating-bg); border: 1px solid var(--control-border); border-radius: 10px; box-shadow: 0 20px 70px rgba(0, 0, 0, 0.55), 0 4px 18px rgba(0, 0, 0, 0.35); } .command-palette-input-row { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center; gap: 0.55rem; padding: 0.65rem 0.75rem; border-bottom: 1px solid rgba(255, 255, 255, 0.08); } .command-palette-search-icon { color: var(--text-muted); font-size: 1rem; text-align: center; } .command-palette-search { min-width: 0; width: 100%; background: transparent; border: 0; color: var(--text); font: inherit; font-size: 0.95rem; outline: 0; } .command-palette-search:focus-visible { box-shadow: none; } .command-palette-search::placeholder { color: var(--text-muted); } .command-palette-input-row kbd { padding: 0.15rem 0.35rem; color: var(--text-muted); background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 4px; font-size: 0.68rem; } .command-palette-label { padding: 0.55rem 0.8rem 0.25rem; color: var(--text-muted); font-size: 0.68rem; font-weight: 600; letter-spacing: 0; text-transform: uppercase; } .command-palette-list { display: flex; flex-direction: column; gap: 0.2rem; min-height: 0; overflow-y: auto; padding: 0.25rem 0.45rem 0.55rem; } .command-palette-item { display: grid; grid-template-columns: 26px minmax(0, 1fr); align-items: center; gap: 0.55rem; width: 100%; min-height: 52px; padding: 0.45rem 0.55rem; color: var(--text); background: transparent; border: 1px solid transparent; border-radius: 7px; text-align: left; cursor: pointer; } .command-palette-item:hover, .command-palette-item.active { background: rgba(59, 130, 246, 0.14); border-color: rgba(59, 130, 246, 0.28); } .command-palette-icon { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; color: var(--accent-hover); background: rgba(255, 255, 255, 0.06); border-radius: 6px; font-size: 0.9rem; } .command-palette-text { min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; } .command-palette-title, .command-palette-subtitle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .command-palette-title { font-size: 0.85rem; font-weight: 600; } .command-palette-subtitle { color: var(--text-muted); font-size: 0.72rem; } /* COD-192: "Browse all sessions…" escape hatch — visually secondary */ .command-palette-item--browse { margin-top: 4px; } .command-palette-item--browse .command-palette-icon { color: var(--text-muted); background: rgba(255, 255, 255, 0.03); } .command-palette-item--browse .command-palette-title { color: var(--text-muted); font-weight: 500; } /* Session Manager modal (COD-121) */ .session-manager-modal { max-width: 720px; width: min(92vw, 720px); max-height: 70vh; display: flex; flex-direction: column; } .session-manager-modal .modal-body { display: flex; flex-direction: column; gap: 0.6rem; overflow: hidden; padding: 1rem; } #sessionManagerSearch { flex: 0 0 auto; } .session-manager-list { display: flex; flex-direction: column; gap: 0.35rem; overflow-y: auto; } /* COD-130: per-row ⋯ kebab context menu (appended to , fixed-positioned). z-index must clear the Session Manager modal (.modal is z-index: 1000). */ .session-row-menu { position: fixed; z-index: 10010; min-width: 180px; display: flex; flex-direction: column; gap: 2px; padding: 4px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3); } .session-row-menu-item { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; padding: 7px 12px; background: none; border: none; border-radius: var(--btn-radius); color: var(--text); cursor: pointer; font-size: 0.8rem; text-align: left; white-space: nowrap; transition: background var(--transition-smooth); } .session-row-menu-item:hover { background: var(--bg-hover); } .session-row-menu-sublabel { color: var(--text-muted); font-size: 0.72rem; } /* Shortcut settings rows (App Settings → Shortcuts, COD-157) */ .shortcut-setting-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 190px) auto auto auto; align-items: center; gap: 0.5rem; padding: 0.4rem 0; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .shortcut-setting-row:last-child { border-bottom: none; } .shortcut-setting-label { color: var(--text); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .shortcut-binding-input { min-width: 0; padding: 0.3rem 0.5rem; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: var(--btn-radius); color: var(--text-dim); font-family: monospace; font-size: 0.72rem; cursor: default; } .shortcut-binding-input:focus { border-color: var(--accent); color: var(--text); outline: none; } .shortcut-capture-btn, .shortcut-reset-btn { padding: 0.3rem 0.6rem; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: var(--btn-radius); color: var(--text-dim); font-size: 0.72rem; cursor: pointer; transition: all var(--transition-smooth); } .shortcut-capture-btn:hover, .shortcut-reset-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.09); color: var(--text); } .shortcut-reset-btn:disabled { opacity: 0.4; cursor: default; } .shortcut-enabled-checkbox { accent-color: var(--accent); cursor: pointer; } /* Shortcut overlay modal (registry-driven; opened with Ctrl+? / Alt+?) */ .shortcut-overlay-modal .modal-content { max-width: 560px; } .shortcut-overlay-group { margin-bottom: 1rem; } .shortcut-overlay-group:last-child { margin-bottom: 0; } .shortcut-overlay-group-label { margin-bottom: 0.35rem; color: var(--text-muted); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; } .shortcut-overlay-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.3rem 0; } .shortcut-overlay-label { color: var(--text); font-size: 0.8rem; } .shortcut-overlay-keys { flex-shrink: 0; color: var(--text-dim); } .shortcut-overlay-footer { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border); text-align: right; } .away-digest-ranges { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.75rem; } .away-digest-custom-range { display: none; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; margin-bottom: 0.75rem; padding: 0.75rem; background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border); border-radius: 8px; } .away-digest-custom-range.active { display: grid; } .away-digest-custom-range label { display: flex; flex-direction: column; gap: 0.35rem; color: var(--text-muted); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.4px; } .away-digest-custom-range input { min-height: 34px; padding: 0.35rem 0.5rem; background: var(--bg-input); border: 1px solid var(--border-light); border-radius: 6px; color: var(--text); } .away-digest-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.75rem; margin-bottom: 0.75rem; } .away-digest-card, .away-digest-loading, .away-digest-load-error { min-height: 74px; padding: 0.75rem; background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border); border-radius: 8px; } .away-digest-loading, .away-digest-load-error { grid-column: 1 / -1; display: flex; align-items: center; color: var(--text-dim); font-size: 0.8rem; } .away-digest-load-error { color: var(--red); } .away-digest-card-label { display: block; margin-bottom: 0.25rem; color: var(--text-muted); font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.5px; } .away-digest-card-value { display: block; color: var(--text); font-family: 'SF Mono', Monaco, monospace; font-size: 1.2rem; font-weight: 600; } .away-digest-card-cost { display: block; margin-top: 0.15rem; color: var(--accent-hover); font-size: 0.7rem; } .away-digest-freshness { min-height: 18px; margin-bottom: 0.75rem; color: var(--text-muted); font-size: 0.72rem; line-height: 1.4; } .away-digest-sections { display: flex; flex-direction: column; gap: 0.75rem; } .away-digest-section { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } .away-digest-section-title { display: flex; align-items: center; justify-content: space-between; padding: 0.55rem 0.75rem; background: rgba(255, 255, 255, 0.03); border-bottom: 1px solid var(--border); } .away-digest-section-title h4 { margin: 0; color: var(--text-dim); font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } .away-digest-section-title span { color: var(--text-muted); font-family: 'SF Mono', Monaco, monospace; font-size: 0.7rem; } .away-digest-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.75rem; align-items: center; padding: 0.75rem; border-left: 3px solid var(--border-light); border-bottom: 1px solid var(--border); } .away-digest-item:last-child { border-bottom: none; } .away-digest-success { border-left-color: var(--green); } .away-digest-warning { border-left-color: var(--yellow); } .away-digest-error { border-left-color: var(--red); } .away-digest-info { border-left-color: var(--accent); } .away-digest-item-main { min-width: 0; } .away-digest-item-meta { display: flex; flex-wrap: wrap; gap: 0.35rem 0.55rem; margin-bottom: 0.3rem; color: var(--text-muted); font-size: 0.68rem; } .away-digest-item-title { color: var(--text); font-size: 0.85rem; font-weight: 600; line-height: 1.35; } .away-digest-item-detail { margin-top: 0.25rem; color: var(--text-dim); font-size: 0.76rem; line-height: 1.35; } .away-digest-action { min-height: 32px; padding: 0.35rem 0.7rem; background: transparent; border: 1px solid var(--border-light); border-radius: 6px; color: var(--accent-hover); cursor: pointer; font-size: 0.75rem; } .away-digest-action:hover { background: rgba(59, 130, 246, 0.1); border-color: rgba(96, 165, 250, 0.45); } .away-digest-empty { padding: 0.75rem; color: var(--text-muted); font-size: 0.78rem; } /* Token Stats Modal */ .token-stats-modal { max-width: 560px; max-height: 85vh; overflow: hidden; display: flex; flex-direction: column; } .token-stats-modal .modal-body { overflow-y: auto; padding: 1rem; } .stats-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-bottom: 1.25rem; } .stat-card { background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border); padding: 0.75rem; border-radius: 8px; text-align: center; } .stat-card-label { display: block; font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.25rem; } .stat-card-value { display: block; font-size: 1.1rem; font-weight: 600; color: var(--text); font-family: 'SF Mono', Monaco, monospace; } .stat-card-cost { display: block; font-size: 0.7rem; color: var(--accent-hover); margin-top: 0.15rem; } .stats-chart-container { margin-bottom: 1.25rem; } .stats-chart-label, .stats-table-label { font-size: 0.7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.5rem; } .stats-chart { display: flex; align-items: flex-end; gap: 4px; height: 80px; padding: 0 4px; } .stats-chart .bar { flex: 1; background: linear-gradient(to top, var(--accent), var(--green)); border-radius: 3px 3px 0 0; min-height: 3px; transition: opacity 0.15s; position: relative; } .stats-chart .bar:hover { opacity: 0.8; } .stats-chart .bar::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); padding: 0.25rem 0.5rem; background: var(--bg-card); border: 1px solid var(--border); border-radius: 4px; font-size: 0.65rem; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.15s; z-index: 10; } .stats-chart .bar:hover::after { opacity: 1; } .stats-chart-days { display: flex; gap: 4px; padding: 0 4px; margin-top: 0.35rem; } .stats-chart-days span { flex: 1; text-align: center; font-size: 0.6rem; color: var(--text-muted); } .stats-table-container { max-height: 200px; overflow-y: auto; } .stats-table { width: 100%; font-size: 0.75rem; } .stats-table-header, .stats-table-row { display: grid; grid-template-columns: 1fr 1fr 1fr 0.8fr; gap: 0.5rem; padding: 0.5rem 0.25rem; border-bottom: 1px solid var(--border); } .stats-table-header { color: var(--text-muted); font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.5px; position: sticky; top: 0; background: var(--bg-card); } .stats-table-row:last-child { border-bottom: none; } .stats-table-row .cell { font-family: 'SF Mono', Monaco, monospace; } .stats-table-row .cell-date { color: var(--text-dim); } .stats-table-row .cell-cost { color: var(--accent-hover); } .stats-no-data { text-align: center; color: var(--text-muted); padding: 2rem 1rem; font-size: 0.8rem; } /* Make header tokens clickable */ .header-tokens.clickable { cursor: pointer; transition: color 0.15s; } .header-tokens.clickable:hover { color: var(--text); } /* Toast Notifications */ .toast-container { position: fixed; top: calc(var(--header-height) + 0.5rem); right: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem; z-index: 10000; pointer-events: none; } .toast { background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; padding: 0.6rem 1rem; font-size: 0.8rem; color: var(--text); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); transform: translateX(100%); opacity: 0; transition: all 0.2s ease; pointer-events: auto; } .toast.show { transform: translateX(0); opacity: 1; } .toast-success { border-color: rgba(34, 197, 94, 0.4); } .toast-error { border-color: rgba(239, 68, 68, 0.4); } .toast-warning { border-color: rgba(234, 179, 8, 0.4); } .toast-info { border-color: rgba(59, 130, 246, 0.4); } /* Notification Bell Button */ .btn-icon-header.btn-notifications { position: relative; width: 32px; height: 32px; font-size: 1.1rem; margin-left: 0; margin-right: 2px; } .btn-icon-header.btn-notifications:hover { transform: none; } .notification-badge { position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px; background: var(--red); color: #fff; font-size: 0.6rem; font-weight: 700; border-radius: 8px; display: flex; align-items: center; justify-content: center; pointer-events: none; animation: notif-badge-pulse 2s ease-in-out infinite; } @keyframes notif-badge-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } } /* Notification Drawer */ .notification-drawer { position: fixed; top: var(--header-height); right: 0; width: 340px; height: calc(100vh - var(--header-height)); height: calc(100dvh - var(--header-height)); background: var(--bg-card); border-left: 1px solid var(--border); z-index: 10001; display: flex; flex-direction: column; transform: translateX(100%); transition: transform 0.2s ease; box-shadow: -4px 0 16px rgba(0, 0, 0, 0.3); } .notification-drawer.open { transform: translateX(0); } .notif-drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .notif-drawer-title { font-size: 0.85rem; font-weight: 600; color: var(--text); } .notif-drawer-actions { display: flex; gap: 4px; } .btn-notif-action { background: none; border: 1px solid var(--border); color: var(--text-dim); width: 26px; height: 26px; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; transition: all 0.15s; } .btn-notif-action:hover { background: var(--bg-hover); color: var(--text); border-color: var(--border-light); } .notif-drawer-list { flex: 1; overflow-y: auto; padding: 6px; } .notif-drawer-empty { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-muted); font-size: 0.8rem; } /* Notification Items */ .notif-item { padding: 10px 12px; margin-bottom: 4px; border-radius: 6px; border-left: 3px solid var(--border-light); background: var(--bg-dark); cursor: pointer; transition: background 0.15s; animation: notif-slide-in 0.2s ease; content-visibility: auto; contain-intrinsic-size: auto 60px; } .notif-item:hover { background: var(--bg-hover); } .notif-item.unread { background: rgba(59, 130, 246, 0.05); } .notif-item-critical { border-left-color: var(--red); } .notif-item-warning { border-left-color: var(--yellow); } .notif-item-info { border-left-color: var(--accent); } .notif-item-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; } .notif-item-title { font-size: 0.78rem; font-weight: 600; color: var(--text); } .notif-item-count { font-size: 0.65rem; color: var(--text-muted); margin-left: 6px; } .notif-item-time { font-size: 0.65rem; color: var(--text-muted); white-space: nowrap; } .notif-item-message { font-size: 0.72rem; color: var(--text-dim); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .notif-item-session { display: inline-block; margin-top: 4px; padding: 1px 6px; background: var(--bg-hover); border: 1px solid var(--border); border-radius: 3px; font-size: 0.65rem; color: var(--text-dim); } @keyframes notif-slide-in { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } /* Task Badge on Session Tab */ .session-tab .tab-badge { display: flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 4px; background: var(--yellow); border-radius: 8px; font-size: 0.65rem; font-weight: 600; color: #000; animation: pulse 1.5s infinite; } .session-tab .tab-badge.completed { background: var(--green); animation: none; } /* Subagent Badge on Tabs - Compact hover-triggered */ .session-tab .tab-subagent-badge { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 2px; height: 16px; padding: 0 5px; border-radius: 8px; font-size: 0.6rem; cursor: pointer; background: var(--accent); color: white; margin-left: 4px; transition: transform 0.1s, background 0.15s; } @media (hover: hover) { .session-tab .tab-subagent-badge:hover { background: var(--accent-hover); transform: scale(1.05); } } .session-tab .tab-subagent-badge .subagent-label { font-size: 0.55rem; font-weight: 600; letter-spacing: 0.03em; } /* Ultracode run minimized-to-tab badge — same chip shape as the subagent badge but a distinct purple (matches the ultracode window accent), and a SEPARATE class so the incremental tab-update path (which keys on .tab-subagent-badge) never touches it. Reuses the shared .subagent-dropdown for its restore/dismiss list. */ .session-tab .tab-ultracode-badge { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 2px; height: 16px; padding: 0 5px; border-radius: 8px; font-size: 0.6rem; cursor: pointer; background: #a855f7; color: white; margin-left: 4px; transition: transform 0.1s, background 0.15s; } @media (hover: hover) { .session-tab .tab-ultracode-badge:hover { background: #9333ea; transform: scale(1.05); } } .session-tab .tab-ultracode-badge .subagent-label { font-size: 0.55rem; font-weight: 600; letter-spacing: 0.03em; } /* Per-item type glyph in the ULTRA dropdown (🧬 run vs 📄 transcript). */ .subagent-dropdown-item .ultracode-dd-icon { font-size: 0.7rem; line-height: 1; flex-shrink: 0; margin-right: 1px; } /* Subagent Dropdown - compact, hover-triggered */ .subagent-dropdown { display: none; position: fixed; min-width: 180px; max-width: 280px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); z-index: 10000; overflow: hidden; padding: 4px 0; } .subagent-dropdown.open { display: block; animation: dropdownFadeIn 0.1s ease-out; } @keyframes dropdownFadeIn { from { opacity: 0; transform: translateX(-50%) translateY(-4px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } .subagent-dropdown.pinned { border-color: var(--accent); } /* Header removed - no longer needed */ .subagent-dropdown-header { display: none; } .subagent-dropdown-item { display: flex; align-items: center; gap: 6px; padding: 6px 10px; cursor: pointer; transition: background 0.1s; } /* Hover styles only for devices with real hover (mouse/trackpad). On iOS Safari, :hover triggers a "double-tap" requirement — first tap activates hover state, second tap fires click. Guarding with @media(hover:hover) avoids this. */ @media (hover: hover) { .subagent-dropdown-item:hover { background: var(--bg-hover); } .subagent-dropdown-item:hover .subagent-dropdown-name { color: var(--accent-hover); } .subagent-dropdown-item:hover .subagent-dropdown-close { opacity: 0.6; } .subagent-dropdown-close:hover { opacity: 1; color: var(--red); } } /* Touch devices: show active state on tap instead of hover */ @media (hover: none) { .subagent-dropdown-item:active { background: var(--bg-hover); } .subagent-dropdown-close { opacity: 0.6; /* Always visible on touch (no hover to reveal) */ } } /* Status dot instead of text label */ .subagent-dropdown-status { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--text-muted); } .subagent-dropdown-status.active { background: var(--green); box-shadow: 0 0 4px var(--green); } .subagent-dropdown-status.idle { background: var(--yellow); } .subagent-dropdown-status.completed { background: var(--accent); } .subagent-dropdown-name { flex: 1; font-size: 0.72rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .subagent-dropdown-close { font-size: 0.9rem; color: var(--text-muted); cursor: pointer; padding: 0 2px; opacity: 0; transition: opacity 0.1s, color 0.1s; } .task-empty { padding: 1rem; text-align: center; color: var(--text-muted); font-size: 0.8rem; } /* Task Tree */ .task-tree { font-size: 0.75rem; } .task-node { border-left: 2px solid var(--border); padding-left: 0.75rem; margin-left: 0.5rem; margin-bottom: 0.25rem; } .task-node:first-child { border-left: none; margin-left: 0; padding-left: 0; } .task-item { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.4rem 0.5rem; background: var(--bg-input); border-radius: 4px; margin-bottom: 0.25rem; } .task-status-icon { flex-shrink: 0; width: 14px; height: 14px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.6rem; } .task-status-icon.running { background: var(--yellow); animation: pulse 1.5s infinite; } .task-status-icon.completed { background: var(--green); color: white; } .task-status-icon.failed { background: var(--red); color: white; } .task-info { flex: 1; min-width: 0; } .task-description { color: var(--text); word-break: break-word; } .task-meta { display: flex; gap: 0.5rem; font-size: 0.65rem; color: var(--text-muted); margin-top: 0.2rem; } .task-type { color: var(--accent); } .task-children { margin-top: 0.25rem; } /* Task toggle button in toolbar */ .task-toggle-btn { position: relative; } .task-toggle-btn .badge { position: absolute; top: -4px; right: -4px; min-width: 14px; height: 14px; padding: 0 3px; background: var(--yellow); border-radius: 7px; font-size: 0.6rem; font-weight: 600; color: #000; display: flex; align-items: center; justify-content: center; } /* Scrollbar */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--border-light); } .process-empty { padding: 1rem; text-align: center; color: var(--text-muted); font-size: 0.8rem; } .process-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.6rem 0.75rem; background: var(--bg-input); border-radius: 4px; margin-bottom: 0.5rem; } .process-item:hover { background: var(--bg-hover); } .process-item-clickable { cursor: pointer; transition: border-color 0.15s, background 0.15s; border: 1px solid transparent; } .process-item-clickable:hover { border-color: var(--accent); } .process-info { flex: 1; min-width: 0; } .process-name { font-size: 0.8rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .process-meta { display: flex; gap: 0.75rem; font-size: 0.7rem; color: var(--text-muted); margin-top: 0.2rem; } .process-stat { display: flex; align-items: center; gap: 0.25rem; } .process-stat.memory { color: var(--accent-hover); } .process-stat.cpu { color: var(--green); } .process-stat.children { color: var(--yellow); } .process-actions { display: flex; gap: 0.25rem; } .process-mode { font-size: 0.6rem; padding: 2px 6px; border-radius: 3px; background: var(--bg-hover); color: var(--text-muted); text-transform: uppercase; } .process-mode.shell { background: rgba(234, 179, 8, 0.2); color: var(--yellow); } /* Monitor status badges */ .monitor-status-badge { font-size: 0.55rem; font-weight: 700; padding: 2px 6px; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; min-width: 52px; text-align: center; } .monitor-status-badge.status-idle { background: rgba(234, 179, 8, 0.2); color: var(--yellow); } .monitor-status-badge.status-working { background: rgba(74, 222, 128, 0.2); color: var(--green); animation: pulse-working 2s ease-in-out infinite; } .monitor-status-badge.status-stopped { background: rgba(239, 68, 68, 0.2); color: var(--red, #ef4444); } @keyframes pulse-working { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* Monitor model badges */ .monitor-model-badge { font-size: 0.55rem; padding: 1px 4px; border-radius: 2px; font-weight: 600; text-transform: uppercase; } .monitor-model-badge.opus { background: rgba(168, 85, 247, 0.2); color: #c084fc; } .monitor-model-badge.sonnet { background: rgba(59, 130, 246, 0.2); color: #60a5fa; } .monitor-model-badge.haiku { background: rgba(74, 222, 128, 0.2); color: #4ade80; } /* Monitor stat colors */ .process-stat.tokens { color: var(--accent-hover); } .process-stat.cost { color: #f59e0b; } .process-stat.todo-progress { color: #c084fc; } /* Combined Monitor Panel (Tmux Sessions + Background Tasks) */ .monitor-panel { position: fixed; bottom: var(--toolbar-height); right: 0.5rem; width: 380px; max-width: calc(100vw - 1rem); max-height: 80vh; background: rgba(19, 19, 22, 0.95); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid rgba(255, 255, 255, 0.07); border-bottom: none; border-radius: 10px 10px 0 0; box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.4), 0 -2px 8px rgba(0, 0, 0, 0.2); z-index: 100; transform: translateY(100%); transition: transform 0.2s ease, width 0.2s ease; display: flex; flex-direction: column; } .monitor-panel.open { transform: translateY(0); } /* Detached floating state */ .monitor-panel.detached { bottom: auto; right: auto; top: 100px; left: calc(50% - 300px); width: 600px; height: 500px; max-height: none; border-radius: 8px; border-bottom: 1px solid var(--border); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05); transform: none; resize: both; overflow: hidden; min-width: 350px; min-height: 250px; } .monitor-panel.detached .monitor-panel-header { cursor: move; background: linear-gradient(180deg, var(--bg-hover) 0%, var(--bg-card) 100%); user-select: none; } .monitor-panel.detached .monitor-resize-handle { display: block; } .monitor-panel.detached .monitor-section-body { max-height: none; } .monitor-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 1rem; border-bottom: 1px solid var(--border); font-size: 0.85rem; font-weight: 500; flex-shrink: 0; } .monitor-panel-title { font-weight: 600; font-size: 0.8rem; color: var(--text); } .monitor-panel-actions { display: flex; align-items: center; gap: 0.5rem; } .monitor-panel-body { flex: 1; overflow-y: auto; padding: 0; } /* Resize handle for detached panel */ .monitor-resize-handle { display: none; position: absolute; bottom: 0; right: 0; width: 16px; height: 16px; cursor: nwse-resize; background: linear-gradient(135deg, transparent 50%, var(--border-light) 50%); border-radius: 0 0 8px 0; } .monitor-resize-handle::before { content: ''; position: absolute; bottom: 3px; right: 3px; width: 8px; height: 8px; border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); } .monitor-section { border-bottom: 1px solid var(--border); } .monitor-section:last-child { border-bottom: none; } .monitor-section-header { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 1rem; background: var(--bg-input); font-size: 0.75rem; font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; } .monitor-section-body { padding: 0.5rem; max-height: 25vh; overflow-y: auto; } .monitor-empty { padding: 1rem; text-align: center; color: var(--text-muted); font-size: 0.8rem; } .task-stats { font-size: 0.65rem; color: var(--text-dim); padding: 0.15rem 0.4rem; background: var(--bg-card); border-radius: 8px; } /* Responsive */ @media (max-width: 600px) { .header-brand { padding-right: 0.4rem; margin-right: 0.3rem; } .header-brand .logo { font-size: 0.75rem; } .connection-text { display: none; } .toolbar-left .toolbar-group:not(:first-child) { display: none; } .monitor-panel { width: 100%; max-width: 100%; border-radius: 8px 8px 0 0; } } /* ========== Subagent Panel (Claude Code Background Agents) ========== */ /* ========== Separate Subagents Panel ========== */ .subagents-panel { position: fixed; bottom: var(--toolbar-height); right: 0.5rem; width: 500px; max-width: calc(100vw - 1rem); max-height: 50vh; background: rgba(19, 19, 22, 0.95); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid rgba(255, 255, 255, 0.07); border-bottom: none; border-radius: 10px 10px 0 0; z-index: 91; /* Above monitor panel */ transform: translateY(calc(100% - 36px)); /* Collapsed by default, show header */ transition: transform 0.2s ease, width 0.2s ease; display: flex; flex-direction: column; } .subagents-panel.open { transform: translateY(0); max-height: 65vh; } .subagents-panel.hidden { display: none; } /* Detached floating state for subagents panel */ .subagents-panel.detached { bottom: auto; right: auto; top: 80px; left: calc(50% - 350px); width: 700px; height: 500px; max-height: none; border-radius: 8px; border-bottom: 1px solid var(--border); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05); transform: none; resize: both; overflow: hidden; min-width: 400px; min-height: 300px; } .subagents-panel.detached .subagents-panel-header { cursor: move; background: linear-gradient(180deg, var(--bg-hover) 0%, var(--bg-card) 100%); user-select: none; } .subagents-panel.detached .subagents-resize-handle { display: block; } .subagents-panel-header { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 1rem; border-bottom: 1px solid var(--border); flex-shrink: 0; } .subagents-panel-title { font-weight: 600; font-size: 0.8rem; color: var(--text); display: flex; align-items: center; gap: 0.5rem; } .subagents-panel-actions { display: flex; align-items: center; gap: 0.5rem; } .subagents-panel-body { flex: 1; overflow-y: auto; padding: 0.5rem; } .subagents-resize-handle { display: none; position: absolute; bottom: 0; right: 0; width: 16px; height: 16px; cursor: se-resize; } .subagents-resize-handle::after { content: ''; position: absolute; bottom: 3px; right: 3px; width: 8px; height: 8px; border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); } /* Responsive: full width on small screens */ @media (max-width: 600px) { .subagents-panel { width: 100%; max-width: 100%; left: 0; right: 0; border-radius: 8px 8px 0 0; } } /* Subagent container (list + detail) */ .subagent-container { display: flex; gap: 0.5rem; height: 100%; min-height: 280px; } .subagent-list { flex: 0 0 200px; overflow-y: auto; border-right: 1px solid var(--border); padding-right: 0.5rem; } .subagent-detail { flex: 1; overflow-y: auto; padding-left: 0.5rem; } .subagent-empty { color: var(--text-dim); font-size: 0.75rem; text-align: center; padding: 1rem; } .subagent-badge { background: var(--accent); color: white; font-size: 0.65rem; padding: 0.1rem 0.4rem; border-radius: 8px; margin-left: 0.5rem; } .subagent-item { padding: 0.5rem; border-radius: 6px; background: var(--bg-input); margin-bottom: 0.4rem; cursor: pointer; transition: background 0.15s; content-visibility: auto; contain-intrinsic-size: auto 48px; } .subagent-item:hover { background: var(--bg-card); } .subagent-item.selected { background: var(--bg-card); border: 1px solid var(--accent); } .subagent-header { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.3rem; } .subagent-icon { font-size: 0.9rem; } .subagent-id { font-family: var(--font-mono); font-size: 0.75rem; color: var(--text); } .subagent-status { font-size: 0.6rem; padding: 0.1rem 0.3rem; border-radius: 4px; margin-left: auto; } .subagent-status.active { background: var(--success); color: white; } .subagent-status.idle { background: var(--warning); color: black; } .subagent-status.completed { background: var(--text-muted); color: white; } .subagent-window-btn { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.1rem 0.3rem; font-size: 0.75rem; margin-left: auto; } .subagent-window-btn:hover { color: var(--accent); } .subagent-kill-btn { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.1rem 0.3rem; font-size: 0.7rem; opacity: 0.6; transition: opacity 0.15s, color 0.15s; } .subagent-kill-btn:hover { color: var(--red); opacity: 1; } .subagent-meta { display: flex; gap: 0.5rem; font-size: 0.65rem; color: var(--text-muted); } .subagent-last-tool { color: var(--accent); } /* Subagent Detail */ .subagent-detail-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--border); } .subagent-detail-header .subagent-id { font-size: 0.85rem; font-weight: 600; } .subagent-transcript-btn { margin-left: auto; font-size: 0.65rem; padding: 0.2rem 0.5rem; background: var(--bg-card); border: 1px solid var(--border); border-radius: 4px; color: var(--text); cursor: pointer; } .subagent-transcript-btn:hover { background: var(--bg-hover); } .subagent-detail-stats { display: flex; gap: 1rem; font-size: 0.7rem; color: var(--text-muted); margin-bottom: 0.5rem; } .subagent-activity-log { font-family: var(--font-mono); font-size: 0.7rem; max-height: 150px; overflow-y: auto; } .subagent-activity { display: flex; gap: 0.4rem; padding: 0.2rem 0; border-bottom: 1px solid var(--border-subtle); } .subagent-activity .time { color: var(--text-muted); flex: 0 0 60px; } .subagent-activity .icon { flex: 0 0 20px; } .subagent-activity .name { color: var(--accent); flex: 0 0 80px; } .subagent-activity .detail { color: var(--text-dim); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .subagent-activity.tool .icon { color: var(--accent); } .subagent-activity.progress .icon { color: var(--warning); } .subagent-activity.message .icon { color: var(--text); } /* Model badges */ .subagent-model-badge { font-size: 0.55rem; padding: 0.1rem 0.35rem; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; } .subagent-model-badge.haiku { background: #4ade80; color: #052e16; } .subagent-model-badge.sonnet { background: #60a5fa; color: #1e3a5f; } .subagent-model-badge.opus { background: #c084fc; color: #3b0764; } /* Hook events */ .subagent-activity.progress.hook .icon { color: #f59e0b; } .activity-line.hook-line .tool-icon { color: #f59e0b; } /* Tool result activity */ .subagent-activity.tool-result .icon { color: var(--success); } .subagent-activity.tool-result.error .icon { color: var(--red); } .activity-line.result-line .tool-icon { color: var(--success); } .activity-line.result-line.error .tool-icon { color: var(--red); } .activity-line.result-line .tool-detail { color: var(--text-dim); font-style: italic; } /* Tool params expansion */ .tool-expand-btn { background: transparent; border: 1px solid var(--border); border-radius: 3px; color: var(--text-muted); cursor: pointer; font-size: 0.6rem; padding: 0.1rem 0.3rem; margin-left: 0.3rem; transition: all 0.15s; } .tool-expand-btn:hover { background: var(--bg-hover); color: var(--text); } .tool-params-expanded { background: var(--bg-dark); border-left: 2px solid var(--accent); margin: 0.3rem 0 0.3rem 2rem; padding: 0.4rem 0.6rem; border-radius: 0 4px 4px 0; font-size: 0.65rem; max-height: 150px; overflow-y: auto; } .tool-params-expanded pre { margin: 0; white-space: pre-wrap; word-break: break-all; color: var(--text-dim); } /* ========== Subagent Windows (Floating) ========== */ .subagent-window { position: fixed; width: 420px; height: 350px; min-width: 280px; min-height: 180px; max-width: 90vw; max-height: 80vh; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); z-index: 1000; display: flex; flex-direction: column; overflow: hidden; resize: both; contain: layout paint; } /* Resize handle indicator in bottom-right corner */ .subagent-window::after { content: ''; position: absolute; bottom: 4px; right: 4px; width: 12px; height: 12px; background: linear-gradient(135deg, transparent 50%, var(--border-light) 50%, var(--border-light) 60%, transparent 60%, transparent 70%, var(--border-light) 70%, var(--border-light) 80%, transparent 80%); pointer-events: none; opacity: 0.6; } .subagent-window-header { display: flex; align-items: center; padding: 0.5rem 0.75rem; background: var(--bg-input); border-bottom: 1px solid var(--border); cursor: move; } .subagent-window-title { display: flex; align-items: center; gap: 0.4rem; flex: 1; } .subagent-window-title .icon { font-size: 1rem; } .subagent-window-title .id { font-family: var(--font-mono); font-size: 0.8rem; color: var(--text); } .subagent-window-title .status { font-size: 0.6rem; padding: 0.1rem 0.3rem; border-radius: 4px; } .subagent-window-title .status.active { background: var(--green); color: white; } .subagent-window-title .status.idle { background: var(--yellow); color: #000; } .subagent-window-title .status.completed { background: var(--accent); color: white; } .subagent-window-actions { display: flex; gap: 0.3rem; } .subagent-window-actions button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.2rem 0.4rem; font-size: 0.9rem; } .subagent-window-actions button:hover { color: var(--text); } .subagent-window-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 0.5rem; font-family: var(--font-mono); font-size: 0.75rem; background: var(--bg-dark); color: var(--text); min-height: 0; /* Allow flex child to shrink below content size */ scroll-behavior: smooth; } /* Custom scrollbar for subagent window body */ .subagent-window-body::-webkit-scrollbar { width: 6px; } .subagent-window-body::-webkit-scrollbar-track { background: transparent; } .subagent-window-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } .subagent-window-body::-webkit-scrollbar-thumb:hover { background: var(--border-light); } .subagent-window-body .activity-line { display: flex; gap: 0.3rem; padding: 0.15rem 0; align-items: baseline; } .subagent-window-body .activity-line .time { color: #888; flex: 0 0 auto; white-space: nowrap; } .subagent-window-body .activity-line .tool-icon { flex: 0 0 auto; opacity: 0.9; } .subagent-window-body .activity-line .tool-name { color: #b0b0b0; flex: 0 0 auto; white-space: nowrap; } .subagent-window-body .activity-line .tool-detail { color: #d0d0d0; flex: 1; overflow: hidden; text-overflow: ellipsis; } .subagent-window-body .message-line { padding: 0.3rem 0; color: #c8c8c8; } .subagent-window-body .progress-line { color: #a0a0a0; font-style: italic; } /* Subagent Window Parent Tab Header */ .subagent-window-parent { background: var(--bg-darker); padding: 4px 12px; font-size: 11px; color: var(--text-muted); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 6px; } .subagent-window-parent .parent-label { opacity: 0.7; } .subagent-window-parent .parent-name { color: var(--accent); cursor: pointer; font-weight: 500; } .subagent-window-parent .parent-name:hover { text-decoration: underline; } /* Subagent Window Spawn Animation */ .subagent-window.spawning { pointer-events: none; } /* ========== Connection Lines SVG Overlay ========== */ .connection-lines-svg { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; height: 100dvh; pointer-events: none; z-index: 999; /* Below windows (1000+), above panels (91) */ } .connection-line { stroke: #3b82f6; stroke-width: 3; stroke-dasharray: 5 3; fill: none; opacity: 0.9; /* Dark outline for contrast, vibrant blue glow */ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 4px rgba(59, 130, 246, 0.8)) drop-shadow(0 0 8px rgba(59, 130, 246, 0.5)); transition: opacity 0.2s, stroke-width 0.2s, filter 0.2s; } .connection-line:hover { opacity: 1; stroke-width: 3.5; filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.9)) drop-shadow(0 0 6px rgba(59, 130, 246, 1)) drop-shadow(0 0 12px rgba(59, 130, 246, 0.7)); } .connection-line.spawning-line { stroke-dasharray: 1000; stroke-dashoffset: 1000; } /* Wizard connection lines - different color to show plan generation link */ .connection-line.wizard-connection { stroke: #60a5fa; stroke-width: 3; /* Dark outline for contrast against blurred backgrounds */ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 5px #60a5fa) drop-shadow(0 0 10px #60a5fa); stroke-dasharray: 8 4; animation: wizard-pulse 1.5s ease-in-out infinite; } @keyframes wizard-pulse { 0%, 100% { opacity: 0.75; } 50% { opacity: 1; } } /* Plan subagent to regular subagent connection lines (Opus → Haiku) */ .connection-line.plan-to-subagent-line { stroke: #3b82f6; stroke-width: 3; /* Dark outline for contrast, vibrant blue glow */ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 4px rgba(59, 130, 246, 0.8)) drop-shadow(0 0 8px rgba(59, 130, 246, 0.5)); stroke-dasharray: 5 3; animation: plan-subagent-pulse 1.2s ease-in-out infinite; } .connection-line.plan-to-subagent-line:hover { stroke-width: 3.5; filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.9)) drop-shadow(0 0 6px rgba(59, 130, 246, 1)) drop-shadow(0 0 12px rgba(59, 130, 246, 0.7)); } @keyframes plan-subagent-pulse { 0%, 100% { opacity: 0.8; } 50% { opacity: 1; } } /* ========== Project Insights Panel (Bash File Viewers) ========== */ .project-insights-panel { position: fixed; right: 20px; top: calc(var(--header-height) + 10px); width: 450px; height: 350px; min-width: 300px; min-height: 200px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 12px; box-shadow: 0 16px 64px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.2); z-index: 1000; display: none; flex-direction: column; overflow: hidden; resize: both; } .project-insights-panel.visible { display: flex; } .project-insights-header { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0.75rem; background: var(--bg-input); border-bottom: 1px solid var(--border); border-radius: 8px 8px 0 0; flex-shrink: 0; } .project-insights-title { font-size: 0.85rem; font-weight: 600; color: var(--text); } .project-insights-body { flex: 1; overflow-y: auto; padding: 0.5rem; } .project-insights-resize-handle { position: absolute; bottom: 0; right: 0; width: 16px; height: 16px; cursor: se-resize; opacity: 0.5; } .project-insights-resize-handle::after { content: ''; position: absolute; right: 3px; bottom: 3px; width: 8px; height: 8px; border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); } .project-insight-item { display: flex; flex-direction: column; padding: 0.5rem 0.6rem; border-radius: 4px; background: var(--bg-input); margin-bottom: 0.4rem; } .project-insight-item:last-child { margin-bottom: 0; } .project-insight-command { display: flex; align-items: center; gap: 0.4rem; font-family: var(--font-mono); font-size: 0.8rem; color: var(--text); } .project-insight-command .icon { font-size: 1rem; } .project-insight-command .cmd { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .project-insight-paths { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.4rem; padding-left: 1.4rem; } .project-insight-filepath { cursor: pointer; color: var(--accent); font-family: var(--font-mono); font-size: 0.75rem; text-decoration: underline; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .project-insight-filepath:hover { color: var(--accent-hover); } .project-insight-timeout { font-size: 0.7rem; color: var(--text-muted); margin-left: auto; } .project-insight-status { font-size: 0.7rem; padding: 0.15rem 0.35rem; border-radius: 3px; margin-left: 0.3rem; } .project-insight-status.running { background: var(--success); color: white; } .project-insight-status.completed { background: var(--text-muted); color: white; } /* ========== File Browser Panel ========== */ .file-browser-panel { position: fixed; top: calc(var(--header-height) + 10px); right: 20px; width: 280px; height: calc(100vh - var(--header-height) - var(--toolbar-height) - 40px); height: calc(100dvh - var(--header-height) - var(--toolbar-height) - 40px); max-height: 600px; min-width: 200px; min-height: 300px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2); z-index: 100; display: none; flex-direction: column; overflow: hidden; resize: both; } .file-browser-panel.visible { display: flex; } .file-browser-header { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0.6rem; background: var(--bg-input); border-bottom: 1px solid var(--border); flex-shrink: 0; cursor: move; user-select: none; } .file-browser-title { font-size: 0.8rem; font-weight: 600; color: var(--text); } .file-browser-actions { display: flex; gap: 0.25rem; } .file-browser-search { padding: 0.4rem; border-bottom: 1px solid var(--border); flex-shrink: 0; } .file-browser-search input { width: 100%; padding: 0.3rem 0.5rem; font-size: 0.75rem; background: var(--bg-dark); border: 1px solid var(--border); border-radius: 4px; color: var(--text); } .file-browser-search input:focus { outline: none; border-color: var(--accent); } .file-browser-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 0.25rem 0; } .file-browser-body::-webkit-scrollbar { width: 6px; } .file-browser-body::-webkit-scrollbar-track { background: transparent; } .file-browser-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } .file-browser-body::-webkit-scrollbar-thumb:hover { background: var(--border-light); } .file-browser-status { padding: 0.25rem 0.5rem; font-size: 0.65rem; color: var(--text-muted); border-top: 1px solid var(--border); flex-shrink: 0; } .file-browser-empty { padding: 1rem; text-align: center; color: var(--text-muted); font-size: 0.75rem; } .file-browser-loading { padding: 1rem; text-align: center; color: var(--text-dim); font-size: 0.75rem; } /* File Tree Item */ .file-tree-item { display: flex; align-items: center; gap: 0.35rem; padding: 0.2rem 0.5rem; cursor: pointer; font-size: 0.75rem; white-space: nowrap; user-select: none; transition: background 0.1s; } .file-tree-item:hover { background: var(--bg-hover); } .file-tree-item.selected { background: rgba(59, 130, 246, 0.15); } .file-tree-item.hidden-by-filter { display: none; } .file-tree-icon { width: 1rem; text-align: center; flex-shrink: 0; font-size: 0.9rem; } .file-tree-expand { width: 0.75rem; color: var(--text-muted); font-size: 0.6rem; flex-shrink: 0; transition: transform 0.15s; } .file-tree-expand.expanded { transform: rotate(90deg); } .file-tree-name { flex: 1; overflow: hidden; text-overflow: ellipsis; color: var(--text); } .file-tree-name.directory { color: var(--accent-hover); font-weight: 500; } .file-tree-size { font-size: 0.65rem; color: var(--text-muted); margin-left: auto; padding-left: 0.5rem; } .file-tree-download { display: none; margin-left: auto; padding: 0 4px; color: #888; text-decoration: none; font-size: 12px; flex-shrink: 0; } .file-tree-item:hover .file-tree-download { display: inline; } .file-tree-download:hover { color: #4fc3f7; } /* File tree indent levels */ .file-tree-item[data-depth="0"] { padding-left: 0.5rem; } .file-tree-item[data-depth="1"] { padding-left: 1.25rem; } .file-tree-item[data-depth="2"] { padding-left: 2rem; } .file-tree-item[data-depth="3"] { padding-left: 2.75rem; } .file-tree-item[data-depth="4"] { padding-left: 3.5rem; } .file-tree-item[data-depth="5"] { padding-left: 4.25rem; } .file-tree-item[data-depth="6"] { padding-left: 5rem; } .file-tree-item[data-depth="7"] { padding-left: 5.75rem; } .file-tree-item[data-depth="8"] { padding-left: 6.5rem; } .file-tree-item[data-depth="9"] { padding-left: 7.25rem; } /* ========== File Preview Overlay ========== */ .file-preview-overlay { position: fixed; inset: 0; background: var(--modal-backdrop); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); z-index: 2000; display: none; align-items: center; justify-content: center; } .file-preview-overlay.visible { display: flex; } .file-preview-window { width: 80vw; max-width: 900px; height: 80vh; max-height: 700px; background: var(--floating-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--control-border); border-radius: 12px; box-shadow: var(--elevated-shadow); display: flex; flex-direction: column; overflow: hidden; } .file-preview-header { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0.75rem; background: var(--bg-input); border-bottom: 1px solid var(--border); flex-shrink: 0; } .file-preview-title { font-family: var(--font-mono); font-size: 0.85rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .file-preview-actions { display: flex; gap: 0.25rem; } .file-preview-body { flex: 1; overflow: auto; padding: 0; background: var(--bg-dark); } .file-preview-body pre { margin: 0; padding: 0.75rem; font-family: var(--font-mono); font-size: 0.8rem; line-height: 1.5; color: var(--text); white-space: pre-wrap; word-break: break-all; } .file-preview-body pre code { font-family: inherit; } .file-preview-body img { max-width: 100%; max-height: 100%; object-fit: contain; } .file-preview-body video { max-width: 100%; max-height: 100%; } .file-preview-body audio { display: block; width: 90%; margin: 2rem auto; } .file-preview-body .binary-message { padding: 2rem; text-align: center; color: var(--text-muted); } .file-preview-body .binary-message a { color: var(--accent, #4ea1ff); } .file-preview-footer { padding: 0.35rem 0.75rem; font-size: 0.7rem; color: var(--text-muted); border-top: 1px solid var(--border); flex-shrink: 0; } /* ---- File Viewer edit mode (issue #212) ---- */ .file-preview-body textarea.file-preview-editor { display: block; width: 100%; height: 100%; margin: 0; padding: 0.75rem; border: none; outline: none; resize: none; background: var(--bg-dark); color: var(--text); font-family: var(--font-mono); font-size: 0.8rem; line-height: 1.5; white-space: pre; overflow-wrap: normal; overflow: auto; tab-size: 4; } .file-preview-editbar { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.75rem; border-top: 1px solid var(--border); background: var(--bg-input); flex-shrink: 0; } .file-preview-editbar[hidden] { display: none; } .file-preview-editbar-spacer { flex: 1; } .file-preview-dirty { font-size: 0.7rem; color: var(--warning, #e5c07b); } .file-preview-dirty::before { content: '\25CF '; } .file-preview-editbar-btn { padding: 0.3rem 0.9rem; font-size: 0.75rem; border-radius: 6px; border: 1px solid var(--control-border); background: var(--bg-input); color: var(--text); cursor: pointer; } .file-preview-editbar-btn:hover { background: var(--bg-hover, rgba(255, 255, 255, 0.08)); } .file-preview-editbar-btn--save { background: var(--accent); border-color: var(--accent); color: #fff; } .file-preview-editbar-btn--save:hover { background: var(--accent-hover); } .file-preview-editbar-btn--save:disabled { opacity: 0.45; cursor: default; } /* ========== Log Viewer Windows (Floating) ========== */ .log-viewer-window { position: fixed; width: 550px; height: 400px; min-width: 350px; min-height: 200px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-lg); z-index: 2000; display: flex; flex-direction: column; overflow: hidden; resize: both; contain: layout paint; } .log-viewer-window-header { display: flex; align-items: center; padding: 0.5rem 0.75rem; background: var(--bg-input); border-bottom: 1px solid var(--border); cursor: move; } .log-viewer-window-title { display: flex; align-items: center; gap: 0.4rem; flex: 1; } .log-viewer-window-title .icon { font-size: 1rem; } .log-viewer-window-title .filename { font-family: var(--font-mono); font-size: 0.8rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .log-viewer-window-title .status { font-size: 0.6rem; padding: 0.1rem 0.3rem; border-radius: 4px; margin-left: 0.5rem; } .log-viewer-window-title .status.streaming { background: var(--success); color: white; animation: pulse 2s infinite; } .log-viewer-window-title .status.disconnected { background: var(--text-muted); color: white; } .log-viewer-window-title .status.error { background: var(--error); color: white; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } .log-viewer-window-actions { display: flex; gap: 0.3rem; } .log-viewer-window-actions button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.2rem 0.4rem; font-size: 0.9rem; } .log-viewer-window-actions button:hover { color: var(--text); } .log-viewer-window-body { flex: 1; overflow-y: auto; padding: 0.5rem; font-family: var(--font-mono); font-size: 0.75rem; background: var(--bg-dark); white-space: pre-wrap; word-break: break-all; color: var(--text); line-height: 1.4; } .log-viewer-window-body .log-line { padding: 0.1rem 0; content-visibility: auto; contain-intrinsic-size: auto 20px; } .log-viewer-window-body .log-error { color: var(--error); } .log-viewer-window-body .log-info { color: var(--text-muted); font-style: italic; } /* ========== Image Popup Windows (Auto-popup for Screenshots) ========== */ .image-popup-window { position: fixed; width: 600px; height: 500px; min-width: 300px; min-height: 250px; max-width: 90vw; max-height: 90vh; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-lg); display: flex; flex-direction: column; overflow: hidden; resize: both; z-index: 3000; contain: layout paint; } .image-popup-header { display: flex; align-items: center; padding: 0.5rem 0.75rem; background: var(--bg-input); border-bottom: 1px solid var(--border); cursor: move; } .image-popup-title { display: flex; align-items: center; gap: 0.4rem; flex: 1; min-width: 0; } .image-popup-title .icon { font-size: 1rem; flex-shrink: 0; } .image-popup-title .filename { font-family: var(--font-mono); font-size: 0.8rem; color: white; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .image-popup-title .session-badge { font-size: 0.6rem; padding: 0.1rem 0.4rem; border-radius: 4px; background: var(--accent); color: white; flex-shrink: 0; } .image-popup-title .size-badge { font-size: 0.6rem; padding: 0.1rem 0.3rem; border-radius: 4px; background: var(--text-muted); color: white; flex-shrink: 0; } .image-popup-actions { display: flex; gap: 0.3rem; flex-shrink: 0; } .image-popup-actions button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.2rem 0.4rem; font-size: 0.9rem; } .image-popup-actions button:hover { color: var(--text); } .image-popup-body { flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #1a1a1a; padding: 0.5rem; } .image-popup-body img { max-width: 100%; max-height: 100%; object-fit: contain; cursor: pointer; transition: transform 0.1s ease; } .image-popup-body img:hover { transform: scale(1.02); } .image-popup-body .image-error { color: var(--error); font-size: 0.85rem; padding: 1rem; text-align: center; } /* ========== xterm.js Clickable Links ========== */ /* Style for detected file path links in terminal */ .xterm-link-layer .xterm-link { text-decoration: underline; text-decoration-style: dotted; cursor: pointer; } /* Hover state for links */ .xterm .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-link-decoration { cursor: pointer; } /* ========== Ralph Loop Wizard ========== */ /* Wizard Progress Indicator */ .wizard-progress { display: flex; justify-content: center; gap: 1.5rem; padding: 0.5rem 0.75rem; background: var(--bg-dark); border-bottom: 1px solid var(--border); } .wizard-step { display: flex; align-items: center; gap: 0.5rem; color: var(--text-muted); font-size: 0.8rem; transition: color 0.2s; } .wizard-step.active { color: var(--accent); } .wizard-step.completed { color: var(--green); } .wizard-step-number { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; background: var(--bg-input); border: 1px solid var(--border); border-radius: 50%; font-size: 0.7rem; font-weight: 600; } .wizard-step.active .wizard-step-number { background: var(--accent); border-color: var(--accent); color: #fff; } .wizard-step.completed .wizard-step-number { background: var(--green); border-color: var(--green); color: #fff; } .wizard-step-label { font-weight: 500; } /* Wizard Pages */ .wizard-page { min-height: 180px; } .wizard-page.hidden { display: none; } /* Wizard Footer */ .wizard-footer { display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 1rem; border-top: 1px solid var(--border); background: var(--bg-card); } .wizard-footer-right { display: flex; gap: 0.5rem; } /* Wizard Modal - compact layout */ .modal-wizard { width: 480px; max-width: 95vw; max-height: 70vh; display: flex; flex-direction: column; } /* Draggable wizard state */ .modal-wizard.draggable { position: absolute; transform: none; cursor: default; } .modal-wizard .modal-body { overflow-y: auto; flex: 1; min-height: 0; } .modal-wizard .wizard-footer { flex-shrink: 0; } .wizard-page-compact { min-height: auto; padding: 0.5rem 0; } .wizard-step-intro { text-align: center; margin-bottom: 0.75rem; color: var(--text-dim); font-size: 0.9rem; } .wizard-step-intro p { margin: 0; } /* Wizard inline row for compact layout */ .wizard-inline-row { display: flex; gap: 1rem; margin-top: 0.75rem; } .wizard-inline-field { flex: 1; } .wizard-inline-field-small { flex: 0 0 auto; } .wizard-inline-field label { display: block; font-size: 0.8rem; color: var(--text-dim); margin-bottom: 0.25rem; } .iteration-presets-compact { display: flex; gap: 0.25rem; } .iteration-presets-compact .iteration-preset-btn { padding: 0.35rem 0.6rem; font-size: 0.75rem; min-width: 36px; } /* Plan Generation Step */ .plan-section { padding: 1rem; text-align: center; } .plan-actions { display: flex; gap: 0.5rem; justify-content: center; } /* Existing Plan Badge (in case selector) */ .existing-plan-badge { font-size: 0.7rem; background: var(--accent); color: white; padding: 0.1rem 0.4rem; border-radius: 3px; margin-left: 0.5rem; font-weight: normal; } /* Existing Plan Card (Step 2) */ .existing-plan-card { background: var(--bg-input); border: 1px solid var(--accent); border-radius: 6px; padding: 1rem; text-align: left; } .existing-plan-header { display: flex; align-items: center; gap: 0.5rem; font-weight: 500; margin-bottom: 0.75rem; } .existing-plan-icon { font-size: 1.2rem; } .existing-plan-stats { display: flex; gap: 1rem; margin-bottom: 1rem; font-size: 0.85rem; } .existing-plan-stats .stat { display: flex; align-items: center; gap: 0.25rem; } .existing-plan-stats .stat.pending { color: var(--yellow); } .existing-plan-stats .stat.completed { color: var(--green); } .existing-plan-stats .stat.total { color: var(--text-muted); } .existing-plan-actions { display: flex; gap: 0.5rem; } /* Plan Loading State */ .plan-loading-state { padding: 1.5rem 1rem; text-align: center; } .plan-loading-content { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 0.75rem; } .plan-spinner { width: 28px; height: 28px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 1s linear infinite; flex-shrink: 0; } @keyframes spin { to { transform: rotate(360deg); } } .plan-loading-text { display: flex; flex-direction: column; align-items: flex-start; text-align: left; } .plan-loading-title { font-weight: 500; color: var(--text); } .plan-loading-time { font-size: 0.8rem; color: var(--text-muted); font-family: 'SF Mono', Monaco, monospace; } .plan-loading-hint { color: var(--text-dim); font-size: 0.85rem; margin: 0 0 1rem 0; } .plan-error-msg { color: var(--red); margin-bottom: 1rem; } .plan-option-group { display: flex; align-items: center; gap: 0.5rem; } .plan-option-group label { font-size: 0.8rem; color: var(--text-dim); } .plan-option-group select { padding: 0.3rem 0.5rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.8rem; } .plan-detail-btns { display: flex; gap: 0.25rem; } .plan-detail-btn { padding: 0.3rem 0.6rem; font-size: 0.75rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); cursor: pointer; transition: all 0.15s; } .plan-detail-btn:hover { border-color: var(--border-light); } .plan-detail-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } /* Plan Editor */ .plan-editor-header { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.75rem; font-weight: 500; font-size: 0.9rem; } .plan-stats { font-weight: normal; font-size: 0.8rem; color: var(--text-muted); margin-left: 0.5rem; } .plan-editor-actions { display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: center; } .plan-items-list { display: flex; flex-direction: column; gap: 0.35rem; max-height: 280px; overflow-y: auto; margin-bottom: 0.5rem; } .plan-loading-actions { display: flex; gap: 0.5rem; justify-content: center; } .plan-autostart-toggle { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border); } .plan-autostart-label { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; justify-content: center; } .plan-autostart-label input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; } .plan-autostart-text { font-size: 0.85rem; color: var(--text); } .plan-autostart-label:hover .plan-autostart-text { color: var(--accent); } /* Existing wizard files section */ .existing-wizard-files-section { padding: 1rem; } .existing-wizard-card { background: var(--bg-dark); border: 1px solid var(--accent); border-radius: 8px; padding: 1rem; } .existing-wizard-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; } .existing-wizard-icon { font-size: 1.2rem; } .existing-wizard-title { font-weight: 600; color: var(--text); } .existing-wizard-desc { font-size: 0.85rem; color: var(--text-dim); margin: 0 0 0.75rem 0; } .existing-wizard-agents { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 1rem; } .existing-wizard-agent { background: rgba(96, 165, 250, 0.2); color: var(--accent); padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 500; } .existing-wizard-actions { display: flex; gap: 0.5rem; justify-content: center; } .plan-cancel-btn { color: var(--red); } /* Plan Stopped State */ .plan-stopped-indicator { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin-bottom: 1rem; padding: 0.75rem; background: var(--surface); border-radius: 6px; border: 1px solid var(--border); } .plan-stopped-icon { color: var(--red); font-size: 1rem; } .plan-stopped-text { font-weight: 500; color: var(--text); } .plan-skip-hint { font-size: 0.75rem; color: var(--text-muted); text-align: center; margin-top: 0.75rem; } .plan-skip-hint strong { color: var(--text-dim); } /* ========== Plan Subagent Windows (Visible Opus Agents) ========== */ .plan-subagent-window { position: fixed; width: 280px; background: var(--bg-card); border: 1px solid var(--accent); border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 20px rgba(96, 165, 250, 0.2); overflow: hidden; animation: planSubagentSpawn 0.3s ease-out; } @keyframes planSubagentSpawn { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } } .plan-subagent-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; background: linear-gradient(135deg, rgba(96, 165, 250, 0.2), rgba(96, 165, 250, 0.1)); border-bottom: 1px solid var(--border); cursor: grab; user-select: none; } .plan-subagent-header:active { cursor: grabbing; } .plan-subagent-icon { font-size: 1rem; } .plan-subagent-title { flex: 1; font-weight: 500; font-size: 0.8rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .plan-subagent-model { font-size: 0.65rem; padding: 0.15rem 0.4rem; background: #7c3aed; color: white; border-radius: 3px; text-transform: uppercase; font-weight: 600; } .plan-subagent-body { padding: 0.75rem; } .plan-subagent-status { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.35rem; } .plan-subagent-status.running .plan-subagent-spinner { width: 14px; height: 14px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 1s linear infinite; } .plan-subagent-status.completed .plan-subagent-status-text { color: var(--green); } .plan-subagent-status.failed .plan-subagent-status-text { color: var(--red); } .plan-subagent-status-text { font-size: 0.8rem; font-weight: 500; } .plan-subagent-detail { font-size: 0.7rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Clickable prompt link in plan subagent header */ .plan-subagent-prompt-link { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; padding: 0.15rem 0.3rem; margin: -0.15rem -0.3rem; border-radius: 4px; transition: background 0.15s ease; } .plan-subagent-prompt-link:hover { background: rgba(255, 255, 255, 0.1); } /* Clickable status text */ .plan-subagent-status-text.clickable { cursor: pointer; text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px; } .plan-subagent-status-text.clickable:hover { text-decoration-style: solid; color: var(--accent); } /* Ralph panel version info */ .ralph-version-info { display: flex; align-items: center; gap: 0.35rem; font-size: 0.7rem; color: var(--text-muted); margin-left: auto; } .ralph-version-info .version-badge { background: var(--bg-card); padding: 0.1rem 0.25rem; border-radius: 2px; font-family: 'SF Mono', Monaco, monospace; } .ralph-version-info .rollback-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 0.65rem; padding: 0.1rem 0.25rem; } .ralph-version-info .rollback-btn:hover { text-decoration: underline; } /* Textarea with AI Assist button */ .textarea-with-assist { position: relative; } .textarea-with-assist textarea { width: 100%; padding: 0.6rem; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 0.85rem; font-family: 'SF Mono', Monaco, 'Courier New', monospace; resize: vertical; min-height: 80px; } .textarea-with-assist textarea:focus { outline: none; border-color: var(--accent); } /* Iteration Presets */ .iteration-presets { display: flex; gap: 0.35rem; flex-wrap: wrap; } .iteration-preset-btn { padding: 0.5rem 1rem; font-size: 0.8rem; font-weight: 500; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); cursor: pointer; transition: all 0.15s; min-width: 50px; } .iteration-preset-btn:hover { border-color: var(--border-light); color: var(--text); } .iteration-preset-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } /* Case Select Inline */ .case-select-inline { display: flex; gap: 0.5rem; } .case-select-inline select { flex: 1; } /* Ralph Prompt Preview */ .ralph-preview-section { margin-bottom: 1rem; } .ralph-preview-section > label { display: block; font-size: 0.7rem; color: var(--text-dim); margin-bottom: 0.35rem; text-transform: uppercase; letter-spacing: 0.03em; } .ralph-prompt-preview { background: var(--bg-dark); border: 1px solid var(--border); border-radius: 4px; padding: 0.5rem 0.75rem; font-family: 'SF Mono', Monaco, 'Courier New', monospace; font-size: 0.75rem; color: var(--text-dim); max-height: 120px; overflow-y: auto; white-space: pre-wrap; word-break: break-word; } .ralph-prompt-preview .preview-highlight { color: var(--accent); font-weight: 500; } /* Config Summary */ .ralph-config-summary { background: var(--bg-input); border-radius: 4px; padding: 0.75rem; margin-bottom: 1rem; } .config-summary-row { display: flex; justify-content: space-between; padding: 0.35rem 0; font-size: 0.8rem; } .config-summary-row:not(:last-child) { border-bottom: 1px solid var(--border); } .config-label { color: var(--text-dim); } .config-summary-row code { background: var(--bg-dark); padding: 0.15rem 0.4rem; border-radius: 3px; font-size: 0.75rem; color: var(--text); } /* Advanced Options */ .advanced-options { margin-top: 1rem; } .advanced-options summary { cursor: pointer; font-size: 0.8rem; color: var(--text-dim); padding: 0.5rem 0; border-top: 1px solid var(--border); } .advanced-options summary:hover { color: var(--text); } .advanced-options[open] summary { margin-bottom: 0.75rem; } .advanced-options-content { padding-left: 0.5rem; } /* "Run in Docker" quick option — the primary one-click entry point, so its label + hint read larger and brighter than the standard form label/hint. */ .docker-quick-row .checkbox-row { font-size: 0.9rem; color: var(--text); } .docker-quick-row .form-hint { font-size: 0.8rem; line-height: 1.45; } /* The container-settings panel is always shown + expanded (no longer gated on the checkbox), so its summary header reads a touch larger too. */ .docker-quick-settings > summary { font-size: 0.85rem; } /* ═══════════════════════════════════════════════════════════════ Response Viewer — native-scroll overlay for reading Claude responses ═══════════════════════════════════════════════════════════════ */ .btn-response-viewer-header { display: inline-flex !important; } /* "Response Viewer" header toggle (App Settings → Display) — must out-specify the inline-flex !important above */ .btn-response-viewer-header.btn-response-viewer-header--hidden { display: none !important; } /* "Attachments" header button — opt-in (App Settings → Display), hidden by default. Same pattern as the response viewer: a base inline-flex !important so an inline style can't override it, and a more-specific marker rule to hide. */ .btn-attachments-history { display: inline-flex !important; } .btn-attachments-history.btn-attachments-history--hidden { display: none !important; } /* "Session Manager" + "Away Digest" header buttons — opt-in (App Settings → Display), hidden by default. Same marker pattern as the response viewer: a base inline-flex !important so an inline style can't override it, and a more-specific marker rule to hide. Phones keep them hidden regardless via the higher-specificity mobile.css rule (.btn-icon-header.btn-...). */ .btn-session-manager { display: inline-flex !important; } .btn-session-manager.btn-session-manager--hidden { display: none !important; } .btn-away-digest { display: inline-flex !important; } .btn-away-digest.btn-away-digest--hidden { display: none !important; } /* "File Viewer" header button — opt-in (App Settings → Header Displays), hidden by default. Clicking it toggles the file browser panel. Same marker pattern as the response viewer: a base inline-flex !important so an inline style can't override it, and a more-specific marker rule to hide. */ .btn-file-viewer { display: inline-flex !important; } .btn-file-viewer.btn-file-viewer--hidden { display: none !important; } /* "Cron" footer-toolbar button — opt-in, hidden by default (enable under App Settings → Display → Header Displays). Toolbar button, not a header icon, so only the hide marker is needed; out-specify any base .btn-toolbar display. */ .btn-toolbar.btn-cron--hidden { display: none !important; } /* "Ultracode Agents" header launcher — opt-in (App Settings → Display), hidden by default everywhere (so the mobile-header-buttons-policy guard auto-excludes it). Base inline-flex !important + a more-specific marker rule to hide. */ .btn-ultracode-agents { display: inline-flex !important; } .btn-ultracode-agents.btn-ultracode-agents--hidden { display: none !important; } /* ===== Ultracode / Workflow agents master-detail panel ===== */ /* Reuses .subagents-panel dock behavior but anchors LEFT so it never overlaps the bottom-right subagents panel when both are open. */ .ultracode-agents-panel { right: auto; left: 0.5rem; width: 640px; } @media (max-width: 700px) { .ultracode-agents-panel { left: 0; right: 0; width: 100%; max-width: 100%; } } /* LEFT pane: run rows */ .ultracode-run-item { padding: 0.45rem 0.5rem; border-radius: 6px; background: var(--bg-input); margin-bottom: 0.4rem; cursor: pointer; transition: background 0.15s; } .ultracode-run-item:hover { background: var(--bg-card); } .ultracode-run-item.selected { background: var(--bg-card); border: 1px solid var(--accent); } .ultracode-run-head { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.2rem; } .ultracode-run-name { font-size: 0.75rem; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ultracode-run-stats { font-size: 0.65rem; color: var(--text-dim); } .ultracode-status { font-size: 0.58rem; padding: 0.05rem 0.3rem; border-radius: 4px; margin-left: auto; text-transform: lowercase; background: var(--text-muted); color: white; flex-shrink: 0; } .ultracode-status.completed { background: var(--green); } .ultracode-status.active { background: var(--yellow); color: black; } .ultracode-status.failed { background: var(--red, #b3261e); color: white; } /* LEFT pane: phase chips for the selected run */ .ultracode-phase-list { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.4rem; } .ultracode-phase-chip { font-size: 0.62rem; padding: 0.1rem 0.4rem; border-radius: 10px; background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted); cursor: pointer; } .ultracode-phase-chip:hover { color: var(--text); } .ultracode-phase-chip.selected { background: var(--accent); border-color: var(--accent); color: white; } /* RIGHT pane: per-phase header + agent cards */ .ultracode-phase-header { display: flex; align-items: baseline; justify-content: space-between; font-size: 0.7rem; font-weight: 600; color: var(--text); margin: 0.5rem 0 0.3rem; padding-bottom: 0.2rem; border-bottom: 1px solid var(--border); } .ultracode-phase-sub { font-size: 0.62rem; font-weight: 400; color: var(--text-dim); } .ultracode-agent-card { background: var(--bg-input); border-radius: 6px; padding: 0.4rem 0.5rem; margin-bottom: 0.35rem; border-left: 3px solid transparent; } /* At-a-glance agent state: yellow while working, green when done. */ .ultracode-agent-card.uw-state-working { border-left-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 9%, var(--bg-input)); } .ultracode-agent-card.uw-state-done { border-left-color: var(--green); background: color-mix(in srgb, var(--green) 9%, var(--bg-input)); } .ultracode-agent-card--clickable { cursor: pointer; transition: background 0.15s; } .ultracode-agent-card--clickable:hover { background: var(--bg-card); } /* Keep the state tint on hover (equal specificity to the hover rule, so it must come after it) — a tad stronger so the hover still reads as interactive. */ .ultracode-agent-card--clickable.uw-state-working:hover { background: color-mix(in srgb, var(--yellow) 16%, var(--bg-card)); } .ultracode-agent-card--clickable.uw-state-done:hover { background: color-mix(in srgb, var(--green) 16%, var(--bg-card)); } .ultracode-agent-top { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.25rem; } .ultracode-agent-label { font-size: 0.72rem; font-weight: 600; color: var(--text); font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ultracode-agent-state { font-size: 0.56rem; padding: 0.05rem 0.3rem; border-radius: 4px; margin-left: auto; flex-shrink: 0; background: var(--text-muted); color: white; } .ultracode-agent-state.completed { background: var(--green); } .ultracode-agent-state.active { background: var(--yellow); color: black; } .ultracode-agent-state.idle { background: var(--bg-card); color: var(--text-muted); } .ultracode-agent-meta { display: flex; flex-wrap: wrap; gap: 0.3rem; } .ultracode-chip { font-size: 0.62rem; padding: 0.05rem 0.35rem; border-radius: 4px; background: var(--bg-card); color: var(--text-muted); font-family: var(--font-mono); } .ultracode-chip-tok { color: var(--accent); } .ultracode-chip-tool { color: var(--text); } .ultracode-agent-sub { font-size: 0.62rem; color: var(--text-dim); margin-top: 0.25rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ========== Ultracode floating run windows (additional to the dock panel) ========== */ /* A draggable window that auto-pops while a Workflow/ultracode run is active and is tied by a glowing connector line to the originating session tab (ultracode-windows.js). */ .ultracode-window { position: fixed; width: 380px; height: 320px; min-width: 260px; min-height: 140px; max-width: 92vw; max-height: 80vh; background: var(--bg-card); border: 1px solid #a855f7; border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(168, 85, 247, 0.15); z-index: 1000; display: flex; flex-direction: column; overflow: hidden; resize: both; contain: layout paint; transition: transform 0.18s ease, opacity 0.18s ease; } .ultracode-window.spawning { transform: scale(0.92); opacity: 0; } .ultracode-window-header { display: flex; align-items: center; gap: 0.4rem; padding: 0.45rem 0.6rem; background: var(--bg-input); border-bottom: 1px solid var(--border); cursor: move; } .ultracode-window-title { display: flex; align-items: center; gap: 0.4rem; flex: 1; min-width: 0; } .ultracode-window-title .icon { font-size: 0.95rem; flex-shrink: 0; } .ultracode-window-title .uw-name { font-size: 0.78rem; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ultracode-window-title .uw-status { flex-shrink: 0; margin-left: 0; } .ultracode-window-actions { display: flex; gap: 0.25rem; flex-shrink: 0; } .ultracode-window-actions button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.15rem 0.4rem; font-size: 0.9rem; line-height: 1; } .ultracode-window-actions button:hover { color: var(--text); } .ultracode-window-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 0.5rem; background: var(--bg); min-height: 0; } .ultracode-window-body::-webkit-scrollbar { width: 6px; } .ultracode-window-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } .ultracode-window-body .uw-summary { font-size: 0.65rem; color: var(--text-dim); font-family: var(--font-mono); margin-bottom: 0.4rem; } /* Ultracode connector line — the session-tab accent blue (dashed to stay distinct from the solid subagent lines, per the same-blue-as-the-tab request). */ .connection-line.ultracode-connection { stroke: var(--accent); stroke-width: 3; stroke-dasharray: 6 3; filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 5px rgba(var(--accent-rgb), 0.85)) drop-shadow(0 0 10px rgba(var(--accent-rgb), 0.5)); animation: ultracode-conn-pulse 1.4s ease-in-out infinite; } .connection-line.ultracode-connection:hover { stroke-width: 3.5; } @keyframes ultracode-conn-pulse { 0%, 100% { opacity: 0.8; } 50% { opacity: 1; } } /* Agent-transcript window: spawned from an agent card (in a run window or the dock panel), tied to its parent run window by its own connector line. Reuses the .ultracode-window chrome; wider with a monospace transcript body. */ .ultracode-agent-window { width: 470px; height: 420px; border-color: #38bdf8; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(56, 189, 248, 0.18); } .ultracode-agent-window .ultracode-window-body .uw-transcript { margin: 0; white-space: pre-wrap; word-break: break-word; font-family: var(--font-mono); font-size: 0.68rem; line-height: 1.45; color: var(--text); } /* Distinguish the parent→agent line from the tab→run line: solid cyan, no dashes. Must follow .ultracode-connection (equal specificity → source order wins). */ .connection-line.ultracode-agent-connection { stroke: #38bdf8; stroke-dasharray: none; filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 5px rgba(56, 189, 248, 0.85)); } /* Plan-usage chip (App Settings → Display → "Plan Usage Limits"). Shows the live 5-hour + weekly plan limits parsed from the Claude statusline. Ships hidden via the marker class below because display is PER-DEVICE and the server cannot read localStorage; settings-ui.js reveals it on load (desktop default ON, handhelds OFF) and on a live toggle. */ .header-plan-usage { display: inline-flex !important; align-items: center; height: 22px; padding: 0 0.5rem; border-radius: 11px; font-size: 0.7rem; font-weight: 500; font-family: 'SF Mono', Monaco, monospace; color: var(--text-dim); background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); white-space: nowrap; cursor: default; } /* Readable two-window layout: dim uppercase label + bold, color-coded value. */ .header-plan-usage .pu-win { display: inline-flex; align-items: baseline; gap: 4px; } .header-plan-usage .pu-label { font-size: 0.66rem; font-weight: 700; color: var(--text); opacity: 0.9; text-transform: uppercase; letter-spacing: 0.02em; } .header-plan-usage .pu-val { font-weight: 700; } .header-plan-usage .pu-sep { margin: 0 7px; color: var(--text-dim); opacity: 0.45; } /* Green/yellow/red by how much of the window is used up. */ .header-plan-usage .pu-green { color: #3fb950; } .header-plan-usage .pu-yellow { color: #d6a01a; } .header-plan-usage .pu-red { color: #f85149; } /* Marker class must out-specify the display:inline-flex !important above. */ .header-plan-usage.header-plan-usage--hidden { display: none !important; } .response-viewer { display: none; position: fixed; bottom: 0; left: 0; right: 0; max-height: 88vh; background: var(--floating-bg); border-top: 1px solid var(--border); border-radius: 14px 14px 0 0; box-shadow: var(--elevated-shadow); z-index: 5000; flex-direction: column; transform: translateY(100%); transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1); } .response-viewer.visible { display: flex; transform: translateY(0); } .response-viewer-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px; border-bottom: 1px solid var(--border); flex-shrink: 0; font-size: 14px; font-weight: 600; color: var(--text); letter-spacing: 0.2px; } .response-viewer-actions { display: flex; align-items: center; gap: 8px; } .response-viewer-more { background: var(--control-bg); border: 1px solid var(--control-border); color: var(--text-dim); font-size: 12px; padding: 3px 10px; border-radius: 4px; cursor: pointer; } .response-viewer-more:active { background: var(--control-bg-hover); } .response-viewer-close { background: none; border: none; color: var(--text-muted); font-size: 22px; cursor: pointer; padding: 0 4px; line-height: 1; } /* Conversation thread messages — card-style layout for clear separation */ .rv-message { margin: 0 0 18px; padding: 14px 16px 16px; border-radius: 10px; border: 1px solid var(--border); border-left-width: 3px; background: var(--bg-card); position: relative; } .rv-message:last-child { margin-bottom: 6px; } /* Distinct accent per role so threads are scannable at a glance */ .rv-message:has(.rv-role-user), .rv-message.rv-msg-user { border-left-color: var(--accent); background: rgba(var(--accent-rgb), 0.055); } .rv-message:has(.rv-role-assistant), .rv-message.rv-msg-assistant { border-left-color: var(--green); background: color-mix(in srgb, var(--green) 6%, var(--bg-card)); } .rv-role { display: inline-block; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px; padding: 2px 8px; border-radius: 10px; background: var(--control-bg); } .rv-role-user { color: var(--accent); background: rgba(var(--accent-rgb), 0.12); } .rv-role-assistant { color: var(--green); background: color-mix(in srgb, var(--green) 12%, transparent); } /* Markdown rendered content inside response viewer. Prose uses a proportional font for readability; code keeps monospace. */ .rv-text, .response-viewer-body > :not(.rv-message) { word-break: normal; overflow-wrap: anywhere; line-height: 1.7; } .rv-text p, .response-viewer-body > p { margin: 0 0 0.85em; } .rv-text p:last-child, .response-viewer-body > p:last-child { margin-bottom: 0; } .rv-text h1, .rv-text h2, .rv-text h3, .rv-text h4, .response-viewer-body > h1, .response-viewer-body > h2, .response-viewer-body > h3, .response-viewer-body > h4 { color: var(--text); margin: 1.4em 0 0.5em; line-height: 1.3; font-weight: 700; letter-spacing: -0.01em; } .rv-text h1:first-child, .rv-text h2:first-child, .response-viewer-body > h1:first-child, .response-viewer-body > h2:first-child { margin-top: 0; } .rv-text h1, .response-viewer-body > h1 { font-size: 1.55em; padding-bottom: 0.3em; border-bottom: 1px solid var(--border); } .rv-text h2, .response-viewer-body > h2 { font-size: 1.3em; color: var(--yellow); } .rv-text h3, .response-viewer-body > h3 { font-size: 1.13em; color: var(--accent); } .rv-text h4, .response-viewer-body > h4 { font-size: 1em; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; } .rv-text code, .response-viewer-body > :not(pre) code { background: var(--bg-input); color: var(--red); padding: 1px 6px; border-radius: 4px; font-family: 'Fira Code', 'JetBrains Mono', 'SF Mono', Menlo, Monaco, monospace; font-size: 0.9em; } /* Descendant (not child) combinator: code blocks are wrapped in .rv-code-wrap, so the latest-response view (markdown rendered straight into the body) nests
 one level deeper than a direct child. The historical .rv-text path
   already matched via descendant; keep both in lockstep. */
.rv-text pre,
.response-viewer-body pre {
  background: var(--bg-dark);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  overflow-x: auto;
  margin: 1em 0;
  -webkit-overflow-scrolling: touch;
  box-shadow: inset 0 0 0 1px var(--control-border);
  position: relative;
}

/* Default: wrap long lines so mobile code reads naturally without horizontal scroll.
   Preserve indentation (pre-wrap) but allow breaks inside long tokens
   (URLs, paths, identifiers) so they don't overflow. */
.rv-text pre code,
.response-viewer-body pre code {
  background: none;
  color: var(--text);
  padding: 0;
  font-family: 'Fira Code', 'JetBrains Mono', 'SF Mono', Menlo, Monaco, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: normal;
  overflow-wrap: anywhere;
  tab-size: 4;
}

/* ASCII diagrams (box-drawing, arrows): default is wrap for mobile readability.
   A toggle button lets users switch to horizontal-scroll mode when preserving
   the original grid structure matters more than fitting the viewport. The
   button lives in a wrapper div outside the 
 so it stays pinned to the
   visual right edge when the user scrolls horizontally. */
.rv-text .rv-diagram-wrap,
.response-viewer-body .rv-diagram-wrap {
  position: relative;
  margin: 1em 0;
  max-width: var(--rv-content-max, 720px);
  margin-left: auto;
  margin-right: auto;
}

.rv-text .rv-diagram-wrap > pre.rv-diagram,
.response-viewer-body .rv-diagram-wrap > pre.rv-diagram {
  /* Pre lives inside wrap — move outer spacing to wrap */
  margin: 0;
  padding-right: 44px;    /* reserve space for the pinned button */
}

/* Default state: wrap long lines — same behavior as regular code blocks */
.rv-text pre.rv-diagram code,
.response-viewer-body pre.rv-diagram code {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: normal;
}

/* Scroll-mode (toggled): preserve structure, horizontal scroll with gradient hint */
.rv-text pre.rv-diagram.rv-nowrap code,
.response-viewer-body pre.rv-diagram.rv-nowrap code {
  white-space: pre;
  overflow-wrap: normal;
  word-break: normal;
}

.rv-text pre.rv-diagram.rv-nowrap,
.response-viewer-body pre.rv-diagram.rv-nowrap {
  background: var(--bg-dark);
}

/* Toggle button — pinned to the wrapper's top-right, NOT affected by 
's
   horizontal scroll since it lives outside that scrolling container. */
.rv-wrap-toggle {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 28px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--control-border);
  border-radius: 5px;
  background: var(--floating-bg);
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s, border-color 0.15s;
  z-index: 2;
}

.rv-wrap-toggle:hover,
.rv-wrap-toggle:active {
  color: var(--text);
  border-color: var(--control-border-hover);
}

/* Default icon = "return" (wrap is active). Clicking switches to expand/scroll. */
.rv-wrap-toggle::before {
  content: '↵';
  font-size: 13px;
}

.rv-diagram-wrap:has(> pre.rv-nowrap) .rv-wrap-toggle::before,
.rv-diagram-wrap.rv-wrap-nowrap .rv-wrap-toggle::before {
  content: '⤢';
}

/* ── Code block one-click copy ──────────────────────────────────────────────
   Every fenced code block is wrapped in .rv-code-wrap with an action toolbar
   pinned to its top-right. Regular blocks get the relative positioning here;
   ASCII diagrams already get it from .rv-diagram-wrap (don't clobber its
   centering margins). */
.rv-text .rv-code-wrap:not(.rv-diagram-wrap),
.response-viewer-body .rv-code-wrap:not(.rv-diagram-wrap) {
  position: relative;
  margin: 1em 0;
}

.rv-text .rv-code-wrap:not(.rv-diagram-wrap) > pre,
.response-viewer-body .rv-code-wrap:not(.rv-diagram-wrap) > pre {
  margin: 0;
  padding-right: 44px;    /* reserve room for the copy button */
}

/* Diagrams carry two buttons (copy + wrap toggle) — widen the reserve. */
.rv-text .rv-code-wrap.rv-diagram-wrap > pre.rv-diagram,
.response-viewer-body .rv-code-wrap.rv-diagram-wrap > pre.rv-diagram {
  padding-right: 76px;
}

.rv-code-actions {
  position: absolute;
  top: 6px;
  right: 6px;
  display: inline-flex;
  gap: 4px;
  z-index: 2;
}

/* Inside the flex toolbar the wrap toggle flows normally — drop its own pin. */
.rv-code-actions .rv-wrap-toggle {
  position: static;
  top: auto;
  right: auto;
}

.rv-copy-btn {
  width: 28px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--control-border);
  border-radius: 5px;
  background: var(--floating-bg);
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s, border-color 0.15s;
}

.rv-copy-btn:hover,
.rv-copy-btn:active {
  color: var(--text);
  border-color: var(--control-border-hover);
}

.rv-copy-btn::before { content: '\2398'; }            /* ⎘ — matches file-preview copy */
.rv-copy-btn.rv-copied { color: var(--green); border-color: var(--green); }
.rv-copy-btn.rv-copied::before { content: '\2713'; }  /* ✓ */
.rv-copy-btn.rv-copy-failed { color: var(--red); border-color: var(--red); }
.rv-copy-btn.rv-copy-failed::before { content: '\2715'; } /* ✕ */

.rv-text ul, .rv-text ol,
.response-viewer-body > ul, .response-viewer-body > ol {
  margin: 0.6em 0;
  padding-left: 1.5em;
}

.rv-text li,
.response-viewer-body > ul > li, .response-viewer-body > ol > li {
  margin-bottom: 0.3em;
}

.rv-text li > p { margin: 0.2em 0; }

.rv-text blockquote,
.response-viewer-body > blockquote {
  border-left: 3px solid var(--accent);
  background: rgba(var(--accent-rgb), 0.06);
  margin: 0.8em 0;
  padding: 0.5em 14px;
  color: var(--text-dim);
  border-radius: 0 6px 6px 0;
}

.rv-text strong,
.response-viewer-body > p strong,
.response-viewer-body > li strong {
  color: var(--text);
  font-weight: 700;
}

.rv-text em,
.response-viewer-body em {
  color: var(--text);
}

.rv-text a,
.response-viewer-body a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(var(--accent-rgb), 0.35);
}

.rv-text a:hover,
.response-viewer-body a:hover {
  border-bottom-color: var(--accent);
}

/* Tables — scroll wrapper keeps table proper while allowing horizontal overflow */
.rv-table-wrap {
  margin: 1em 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
}

.rv-text table,
.response-viewer-body > table,
.rv-table-wrap > table {
  border-collapse: collapse;
  margin: 0;
  width: 100%;
  font-size: 0.92em;
  line-height: 1.55;
}

.rv-text th, .rv-text td,
.response-viewer-body > table th,
.response-viewer-body > table td,
.rv-table-wrap th, .rv-table-wrap td {
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
  white-space: normal;
}

.rv-text th:last-child, .rv-text td:last-child,
.response-viewer-body > table th:last-child,
.response-viewer-body > table td:last-child,
.rv-table-wrap th:last-child, .rv-table-wrap td:last-child {
  border-right: none;
}

.rv-text tr:last-child td,
.response-viewer-body > table tr:last-child td,
.rv-table-wrap tr:last-child td {
  border-bottom: none;
}

.rv-text th,
.response-viewer-body > table th,
.rv-table-wrap th {
  background: var(--bg-input);
  color: var(--text);
  font-weight: 600;
  border-bottom: 2px solid var(--border-light);
  white-space: nowrap;
}

.rv-text tbody tr:nth-child(even) td,
.response-viewer-body > table tbody tr:nth-child(even) td,
.rv-table-wrap tbody tr:nth-child(even) td {
  background: var(--control-bg);
}

.rv-text tbody tr:hover td,
.response-viewer-body > table tbody tr:hover td,
.rv-table-wrap tbody tr:hover td {
  background: rgba(var(--accent-rgb), 0.06);
}

.rv-text hr,
.response-viewer-body > hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 1.5em 0;
}

.response-viewer-body {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 20px 22px 28px;
  /* Proportional font for prose — monospace only for code/pre */
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC',
    'Hiragino Sans GB', 'Segoe UI', 'Helvetica Neue', Helvetica, Arial,
    'Noto Sans CJK SC', sans-serif;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text);
  /* Comfortable reading width on wider viewports */
  --rv-content-max: 720px;
}

/* Constrain content width for readability; code blocks can still scroll horizontally */
.response-viewer-body > * {
  max-width: var(--rv-content-max);
  margin-left: auto;
  margin-right: auto;
}
.response-viewer-body > pre,
.response-viewer-body > table,
.response-viewer-body > .rv-message {
  max-width: var(--rv-content-max);
}

.response-viewer-body:empty::after {
  content: 'No response yet';
  color: var(--text-muted);
  font-style: italic;
}

.response-viewer-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--modal-backdrop);
  z-index: 4999;
}

.response-viewer-backdrop.visible {
  display: block;
}

/* ═══════════════════════════════════════════════════════════════
   CJK IME Input
   ═══════════════════════════════════════════════════════════════ */

#cjkInput {
  display: none;
  flex-shrink: 0;
  width: 100%;
  font-family: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', 'SF Mono', Monaco, monospace;
  font-size: 14px;
  background: var(--bg-input);
  color: var(--text);
  border: 1px solid var(--border);
  border-top: none;
  padding: 6px 10px;
  outline: none;
  resize: none;
  line-height: 1.4;
  box-sizing: border-box;
}

#cjkInput:focus {
  border-color: var(--accent);
  background: var(--bg-card);
}

#cjkInput::placeholder {
  color: var(--text-muted);
  font-size: 12px;
}

.touch-device #cjkInput.cjk-input-visible {
  position: fixed;
  left: var(--safe-area-left);
  right: var(--safe-area-right);
  bottom: calc(var(--safe-area-bottom) + 40px);
  z-index: 52;
  display: block;
  min-height: 34px;
  max-height: 68px;
  padding: 6px 10px;
  border: 1px solid var(--control-border-hover);
  border-left: none;
  border-right: none;
  background: var(--floating-bg);
  color: var(--text);
  box-shadow: var(--subtle-shadow);
  transition: transform 0.15s ease-out;
  will-change: transform;
}

.touch-device.keyboard-visible #cjkInput.cjk-input-visible {
  bottom: calc(var(--safe-area-bottom) + 84px);
}

body.touch-device.cjk-input-visible .main {
  padding-bottom: calc(84px + var(--safe-area-bottom));
}

/* ═══════════════════════════════════════════════════════════════
   Keyboard Accessory Bar
   Base styles in styles.css (always loaded) so iPad landscape (≥1024px,
   where mobile.css doesn't load) still gets dark styling. Phone overrides
   remain in mobile.css @media (max-width: 430px).
   ═══════════════════════════════════════════════════════════════ */

.keyboard-accessory-bar {
  display: none;
  height: 44px;
  background: var(--floating-bg);
  border-top: 1px solid var(--control-border);
  padding: 6px 8px;
  gap: 8px;
  align-items: center;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  z-index: 51;
}

.keyboard-accessory-bar.visible {
  display: flex;
}

.keyboard-accessory-bar::-webkit-scrollbar {
  display: none;
}

/* Touch devices: fixed positioning to float above keyboard.
   Phone CSS (mobile.css) adds bottom + safe-area padding;
   iPad JS sets bottom dynamically via updateLayoutForKeyboard(). */
.touch-device .keyboard-accessory-bar {
  position: fixed;
  left: 0;
  right: 0;
  transition: transform 0.15s ease-out;
  will-change: transform;
}

.accessory-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  gap: 4px;
  padding: 6px 12px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  border-radius: 6px;
  color: var(--text-dim);
  font-size: 0.65rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

.accessory-btn.confirming {
  background: color-mix(in srgb, var(--yellow) 18%, var(--bg-input));
  border-color: var(--yellow);
  color: var(--yellow);
}

.accessory-btn:active {
  background: var(--control-bg-hover);
}

.accessory-btn svg {
  width: 14px;
  height: 14px;
}

.accessory-btn-arrow {
  padding: 6px 10px;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.accessory-btn-arrow:active {
  background: var(--accent-hover);
}

.accessory-btn-dismiss {
  margin-left: auto;
  flex: 1 1 0;
  max-width: 100px;
  padding: 10px 8px;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

.accessory-btn-dismiss svg {
  width: 22px;
  height: 22px;
}

.accessory-btn-dismiss:active {
  background: var(--accent-hover);
}

/* ═══════════════════════════════════════════════════════════════
   Paste Overlay
   Base styles in styles.css so iPad landscape works.
   ═══════════════════════════════════════════════════════════════ */

.paste-overlay {
  position: fixed;
  inset: 0;
  background: var(--modal-backdrop);
  z-index: 10000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 15vh;
}

.paste-dialog {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  width: calc(100% - 24px);
  max-width: 400px;
}

.paste-textarea {
  width: 100%;
  min-height: 80px;
  max-height: 200px;
  background: var(--bg-input);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px;
  font-family: inherit;
  font-size: 16px;
  resize: none;
  box-sizing: border-box;
}

.paste-textarea:focus {
  outline: none;
  border-color: var(--accent);
}

.paste-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}

.paste-cancel, .paste-new, .paste-send, .paste-image {
  padding: 8px 18px;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
}

.paste-image {
  margin-right: auto;
  background: var(--bg-input);
  color: var(--accent);
  border: 1px solid var(--accent);
}

.paste-cancel {
  background: var(--bg-input);
  color: var(--text-dim);
}

.paste-new {
  background: var(--bg-input);
  color: var(--accent);
  border: 1px solid var(--accent);
}

.paste-send {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}

/* Shared lazy filesystem path picker (case linking + mobile input). */
.path-input-group {
  display: flex;
  gap: 8px;
  width: 100%;
}

.path-input-group input {
  flex: 1 1 auto;
  min-width: 0;
}

.path-input-browse {
  flex: 0 0 auto;
  min-height: 38px;
}

.path-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 10020;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.path-picker-dialog {
  display: flex;
  flex-direction: column;
  width: min(680px, 100%);
  height: min(720px, calc(100dvh - 32px));
  overflow: hidden;
  color: var(--text);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}

.path-picker-header,
.path-picker-nav,
.path-picker-roots-row,
.path-picker-selection,
.path-picker-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.path-picker-header {
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}

.path-picker-title {
  font-size: 0.95rem;
}

.path-picker-close {
  width: 36px;
  height: 36px;
  color: var(--text-muted);
  font-size: 1.5rem;
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

.path-picker-roots-row {
  padding: 10px 12px 0;
  color: var(--text-muted);
  font-size: 0.75rem;
}

.path-picker-roots {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.path-picker-nav {
  padding: 10px 12px;
}

.path-picker-up,
.path-picker-refresh {
  flex: 0 0 38px;
  height: 38px;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}

.path-picker-up:disabled {
  opacity: 0.35;
  cursor: default;
}

.path-picker-current {
  flex: 1;
  min-width: 0;
  padding: 9px 11px;
  overflow-x: auto;
  color: var(--accent);
  font-family: var(--font-mono, monospace);
  font-size: 0.75rem;
  white-space: nowrap;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.path-picker-status {
  padding: 0 14px 8px;
  color: var(--text-dim);
  font-size: 0.7rem;
}

.path-picker-status.error {
  color: var(--danger, #ef4444);
}

.path-picker-list {
  flex: 1;
  min-height: 140px;
  overflow-y: auto;
  padding: 0 10px 10px;
}

.path-picker-item {
  display: flex;
  align-items: stretch;
  margin: 2px 0;
  border: 1px solid transparent;
  border-radius: 9px;
}

.path-picker-item:hover,
.path-picker-item.selected {
  background: var(--bg-hover);
  border-color: var(--border);
}

.path-picker-item.selected {
  border-color: var(--accent);
}

.path-picker-item.not-selectable {
  opacity: 0.62;
}

.path-picker-item-main {
  display: flex;
  flex: 1;
  align-items: center;
  min-width: 0;
  padding: 10px 8px;
  color: var(--text);
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
}

.path-picker-item-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: 0.8rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.path-picker-item-icon {
  margin-right: 8px;
}

.path-picker-item-link,
.path-picker-item-chevron,
.path-picker-item-preview {
  margin-left: 8px;
  color: var(--text-dim);
}

.path-picker-item-preview {
  font-size: 0.9rem;
}

.path-picker-item-select {
  align-self: center;
  margin-right: 6px;
  padding: 6px 9px;
  color: var(--accent);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 7px;
  cursor: pointer;
}

.path-picker-selection {
  padding: 9px 14px;
  color: var(--text-muted);
  font-size: 0.72rem;
  border-top: 1px solid var(--border);
}

.path-picker-selection-value {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-family: var(--font-mono, monospace);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.path-picker-actions {
  padding: 10px 12px 12px;
}

.path-picker-actions button {
  min-height: 40px;
  padding: 8px 13px;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}

.path-picker-action-spacer {
  flex: 1;
}

.path-picker-actions .path-picker-confirm {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}

.path-picker-actions .path-picker-confirm:disabled {
  opacity: 0.4;
  cursor: default;
}

.path-preview-overlay {
  position: fixed;
  inset: 0;
  z-index: 10030;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  background: rgba(0, 0, 0, 0.82);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.path-preview-dialog {
  display: flex;
  flex-direction: column;
  width: min(1000px, 100%);
  height: min(860px, calc(100dvh - 36px));
  overflow: hidden;
  color: var(--text);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 24px 72px rgba(0, 0, 0, 0.62);
}

.path-preview-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border-bottom: 1px solid var(--border);
}

.path-preview-heading {
  flex: 1;
  min-width: 0;
}

.path-preview-title,
.path-preview-path {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.path-preview-title {
  font-size: 0.9rem;
}

.path-preview-path {
  margin-top: 2px;
  color: var(--text-dim);
  font-family: var(--font-mono, monospace);
  font-size: 0.65rem;
}

.path-preview-open,
.path-preview-close {
  flex: 0 0 auto;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.path-preview-open {
  padding: 8px 11px;
  color: var(--accent);
  font-size: 0.75rem;
  text-decoration: none;
}

.path-preview-close {
  width: 38px;
  height: 38px;
  font-size: 1.5rem;
  cursor: pointer;
}

.path-preview-body {
  position: relative;
  display: flex;
  flex: 1;
  min-height: 0;
  align-items: center;
  justify-content: center;
  overflow: auto;
  background: #111;
}

.path-preview-loading,
.path-preview-error {
  padding: 24px;
  color: var(--text-muted);
  font-size: 0.8rem;
  text-align: center;
}

.path-preview-error {
  color: var(--danger, #ef4444);
}

.path-preview-image {
  display: block;
  max-width: 100%;
  max-height: 100%;
  margin: auto;
  object-fit: contain;
}

.path-preview-frame {
  width: 100%;
  height: 100%;
  background: #fff;
  border: 0;
}

.path-preview-text {
  width: 100%;
  min-height: 100%;
  margin: 0;
  padding: 18px;
  overflow: visible;
  color: #e5e7eb;
  font-family: var(--font-mono, monospace);
  font-size: 0.78rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 600px) {
  .path-picker-overlay {
    align-items: flex-end;
    padding: 0;
  }

  .path-picker-dialog {
    width: 100%;
    height: min(82dvh, 720px);
    border-right: 0;
    border-bottom: 0;
    border-left: 0;
    border-radius: 16px 16px 0 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .path-picker-actions {
    flex-wrap: wrap;
  }

  .path-picker-current-select {
    flex: 1 1 100%;
  }

  .path-preview-overlay {
    align-items: stretch;
    padding: 0;
  }

  .path-preview-dialog {
    width: 100%;
    height: 100dvh;
    border: 0;
    border-radius: 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .path-preview-open {
    padding: 8px;
  }
}

/* ═══════════════════════════════════════════════════════════════
   Orchestrator Panel
   ═══════════════════════════════════════════════════════════════ */

.orchestrator-panel {
  background: var(--glass-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--glass-border);
  font-size: 0.75rem;
  flex-shrink: 0;
  overflow: hidden;
  position: relative;
  contain: layout style paint;
}

.orchestrator-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}

.orchestrator-title {
  font-weight: 600;
  color: var(--text-primary);
  font-size: 0.8rem;
}

.orchestrator-state-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 10px;
  color: #fff;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.orchestrator-actions {
  display: flex;
  gap: 4px;
  margin-left: auto;
}

.orchestrator-close-btn {
  background: none;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 1rem;
  padding: 0 4px;
  line-height: 1;
}
.orchestrator-close-btn:hover { color: var(--text-primary); }

.orch-btn {
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-input);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.7rem;
}
.orch-btn:hover { background: var(--bg-hover); }
.orch-btn-primary { background: #3b82f6; color: #fff; border-color: #3b82f6; }
.orch-btn-primary:hover { background: #2563eb; }
.orch-btn-warn { background: #f59e0b; color: #000; border-color: #f59e0b; }
.orch-btn-warn:hover { background: #d97706; }
.orch-btn-danger { background: #ef4444; color: #fff; border-color: #ef4444; }
.orch-btn-danger:hover { background: #dc2626; }

.orchestrator-body {
  max-height: 300px;
  overflow-y: auto;
  padding: 8px 10px;
}

.orch-empty {
  color: var(--text-secondary);
  text-align: center;
  padding: 12px;
}

.orch-planning {
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: #f59e0b;
  padding: 12px;
}
.orch-planning > .orch-spinner {
  display: inline-block;
}
.orch-progress-log {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 0.8em;
  color: var(--text-secondary);
  max-height: 200px;
  overflow-y: auto;
}
.orch-progress-item {
  padding: 2px 0;
  line-height: 1.3;
}
.orch-progress-phase {
  color: #f59e0b;
  font-weight: 600;
  margin-right: 4px;
}

.orch-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid #f59e0b33;
  border-top-color: #f59e0b;
  border-radius: 50%;
  animation: orch-spin 0.8s linear infinite;
}
@keyframes orch-spin { to { transform: rotate(360deg); } }

.orch-goal {
  margin-bottom: 6px;
  color: var(--text-secondary);
  line-height: 1.3;
}

.orch-progress-bar {
  position: relative;
  height: 18px;
  background: var(--bg-input);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}
.orch-progress-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: linear-gradient(90deg, #3b82f6, #22c55e);
  transition: width 0.3s ease;
  border-radius: 4px;
}
.orch-progress-bar span {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--text-primary);
  font-size: 0.65rem;
  font-weight: 600;
  z-index: 1;
}

.orch-phases {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.orch-phase {
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
}
.orch-phase-active { border-color: #3b82f6; }
.orch-phase-passed { opacity: 0.7; }
.orch-phase-skipped { opacity: 0.5; }
.orch-phase-failed { border-color: #ef4444; }

.orch-phase-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  background: var(--bg-secondary);
}

.orch-phase-icon { width: 14px; text-align: center; }
.orch-phase-name { flex: 1; color: var(--text-primary); font-weight: 500; }
.orch-phase-tasks { color: var(--text-secondary); font-size: 0.65rem; }
.orch-phase-duration { color: var(--text-secondary); font-size: 0.65rem; }
.orch-phase-actions { display: flex; gap: 2px; }

.orch-phase-btn {
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-input);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.6rem;
}
.orch-phase-btn:hover { background: var(--bg-hover); color: var(--text-primary); }

.orch-phase-tasks-list {
  padding: 4px 8px 4px 26px;
  border-top: 1px solid var(--border);
}

.orch-task {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  padding: 2px 0;
  line-height: 1.3;
}
.orch-task-icon { width: 12px; text-align: center; flex-shrink: 0; margin-top: 1px; }
.orch-task-prompt { color: var(--text-primary); word-break: break-word; }
.orch-task-error { color: #ef4444; font-size: 0.6rem; margin-left: auto; }
.orch-task-completed .orch-task-prompt { color: var(--text-secondary); }
.orch-task-failed .orch-task-icon { color: #ef4444; }

.orch-verify-pass { color: #22c55e; padding: 2px 8px; font-size: 0.65rem; }
.orch-verify-fail { color: #ef4444; padding: 2px 8px; font-size: 0.65rem; }

.orch-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: 6px 0;
  margin-top: 6px;
  border-top: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 0.65rem;
}

.orch-error {
  color: #ef4444;
  padding: 4px 0;
  margin-top: 4px;
  font-size: 0.7rem;
}

/* Image drag-and-drop overlay */
#terminalContainer.drag-active {
  outline: 2px dashed #4a9eff;
  outline-offset: -2px;
  position: relative;
}
#terminalContainer.drag-active::after {
  content: 'Drop image here';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(74, 158, 255, 0.08);
  color: #4a9eff;
  font-size: 1.2rem;
  pointer-events: none;
  z-index: 100;
}

.attachment-card-stack {
  position: fixed;
  right: 18px;
  bottom: calc(var(--toolbar-height) + 18px);
  z-index: 1900;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: min(540px, calc(100vw - 32px));
  pointer-events: none;
}

.attachment-clear-all {
  align-self: flex-end;
  padding: 3px 10px;
  border: 1px solid var(--border-light);
  border-radius: 5px;
  background: var(--floating-bg);
  color: var(--text-dim);
  font-size: 0.68rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  pointer-events: auto;
}

.attachment-clear-all:hover {
  border-color: var(--accent);
  color: var(--accent-hover);
}

.attachment-clear-all[hidden] {
  display: none;
}

.attachment-card {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) 24px;
  gap: 10px;
  align-items: center;
  padding: 10px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  background: var(--floating-bg);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  pointer-events: auto;
}

.attachment-thumbnail {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: auto;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 6px;
  background: #f8f8fb;
  border: 1px solid var(--border-light);
}

.attachment-thumbnail-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}

.attachment-thumbnail-fallback {
  display: none;
  align-items: center;
  justify-content: center;
  position: absolute;
  inset: 0;
  color: var(--text);
  font-size: 0.7rem;
  font-weight: 700;
  background: var(--bg-input);
}

.attachment-thumbnail-fallback.visible {
  display: flex;
}

.attachment-type-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 6px;
  background: var(--bg-input);
  color: var(--text);
  border: 1px solid var(--border-light);
  font-size: 0.7rem;
  font-weight: 700;
}

.attachment-card-main {
  min-width: 0;
}

.attachment-file-name {
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attachment-file-meta {
  display: flex;
  gap: 8px;
  margin-top: 2px;
  color: var(--text-dim);
  font-size: 0.68rem;
}

.attachment-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
}

.attachment-actions button,
.attachment-actions a {
  padding: 3px 8px;
  border: 1px solid var(--border-light);
  border-radius: 5px;
  background: var(--bg-input);
  color: var(--text);
  text-decoration: none;
  font-size: 0.68rem;
  cursor: pointer;
}

.attachment-actions button:hover,
.attachment-actions a:hover {
  border-color: var(--accent);
  color: var(--accent-hover);
}

.attachment-close-btn {
  align-self: start;
  width: 22px;
  height: 22px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 1rem;
  cursor: pointer;
}

.attachment-close-btn:hover {
  color: var(--text);
}

/* PDF/Office previews render in an iframe inside the preview body. */
.file-preview-body iframe {
  width: 100%;
  height: 100%;
  border: 0;
  background: #fff;
}

/* Positioning context so the absolutely-positioned badge anchors to the icon,
   not the header bar (mirrors .btn-notifications). */
.btn-attachments-history {
  position: relative;
}

.attachment-history-badge {
  position: absolute;
  top: 2px;
  right: 1px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  background: var(--accent);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

/* Attachment History Drawer */
.attachment-history-drawer {
  position: fixed;
  top: var(--header-height);
  right: 0;
  width: 390px;
  max-width: calc(100vw - 24px);
  height: calc(100vh - var(--header-height) - var(--toolbar-height));
  height: calc(100dvh - var(--header-height) - var(--toolbar-height));
  background: var(--floating-bg);
  border-left: 1px solid var(--border);
  z-index: 10000;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.18s ease;
  box-shadow: -10px 0 28px rgba(0, 0, 0, 0.36);
}

.attachment-history-drawer.open {
  transform: translateX(0);
}

.attachment-history-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.attachment-history-title {
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 650;
}

.attachment-history-subtitle {
  margin-top: 2px;
  color: var(--text-dim);
  font-size: 0.68rem;
}

.attachment-history-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.attachment-history-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
}

.attachment-history-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 160px;
  padding: 24px 16px;
  color: var(--text-muted);
  font-size: 0.78rem;
  text-align: center;
}

.attachment-history-empty-title {
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 600;
}

.attachment-history-empty code {
  max-width: 100%;
  overflow-wrap: anywhere;
  border: 1px solid var(--border-light);
  border-radius: 6px;
  padding: 5px 7px;
  color: var(--text);
  background: var(--bg-input);
  font-size: 0.76rem;
}

.attachment-history-item {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.attachment-history-item:last-child {
  border-bottom: none;
}

.attachment-history-item.missing {
  opacity: 0.58;
}

.attachment-history-thumb {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 112px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--border-light);
  border-radius: 6px;
  background: #f8f8fb;
}

.attachment-history-thumb-img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  object-position: center;
}

.attachment-history-thumb-fallback {
  display: none;
  align-items: center;
  justify-content: center;
  position: absolute;
  inset: 0;
  background: var(--bg-input);
  color: var(--text);
  font-size: 0.72rem;
  font-weight: 700;
}

.attachment-history-thumb-fallback.visible {
  display: flex;
}

.attachment-history-item-main {
  min-width: 0;
}

.attachment-history-file-name {
  overflow: hidden;
  color: var(--text);
  font-size: 0.8rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attachment-history-meta {
  margin-top: 2px;
  color: var(--text-dim);
  font-size: 0.67rem;
}

.attachment-history-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 7px;
}

.attachment-history-actions button {
  padding: 3px 7px;
  border: 1px solid var(--border-light);
  border-radius: 5px;
  background: var(--bg-input);
  color: var(--text);
  font-size: 0.67rem;
  cursor: pointer;
}

.attachment-history-actions button:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent-hover);
}

.attachment-history-actions button:disabled {
  opacity: 0.45;
  cursor: default;
}

/* ============================================================
   === v1.0 Carbon Aurora · Daylight overrides ===
   Single appended block — trivially removable. Retones the hardcoded
   component colors that don't flow through :root: the active session
   tab (#00FF66), the banners' literal gradients, the Ralph Material
   palette, the Run/welcome/stop gradient buttons, the panels' glass,
   and the welcome title. Calms heavy glows; the ONLY real saturation/
   glow is reserved for the Run button + the progress ring.
   ============================================================ */

html:not([data-skin="og"]) {
/* ---- Brand wordmark: emerald, calm (kill the blue glow) ---- */
.logo:hover {
  color: var(--accent-hover);
  text-shadow: none;
  filter: brightness(1.06);
}

/* ---- Active session tab: crisp emerald (replaces neon #00FF66) ---- */
.session-tab.active {
  background: rgba(var(--accent-rgb), 0.13) !important;
  border: 1px solid var(--accent) !important;
  color: var(--text) !important;
  box-shadow: none !important;
}
.session-tab:hover {
  background: rgba(var(--accent-rgb), 0.06);
  border-color: rgba(var(--accent-rgb), 0.2);
  box-shadow: none;
}
.session-tab .tab-number {
  background: var(--control-bg-hover);
  border: 1px solid var(--control-border-hover);
  color: var(--text-dim);
}
.session-tab.active .tab-number {
  background: rgba(var(--accent-rgb), 0.2) !important;
  border-color: rgba(var(--accent-rgb), 0.45) !important;
  color: var(--accent-hover) !important;
}
/* per-color active tints: calm the glow, keep the identity hue as a quiet border */
.session-tab.active[data-color] {
  box-shadow: none;
}
/* tab status dots: quiet, no halo */
.session-tab .tab-status.idle,
.session-tab .tab-status.busy {
  box-shadow: none;
}
.tab-glow { animation: none; box-shadow: none; }

/* ---- Timer banner: emerald-teal, flat ---- */
.timer-banner {
  background: linear-gradient(90deg, var(--banner-bg-a), var(--banner-bg-b));
  border-bottom: 1px solid var(--glass-border);
}
.timer-value { color: var(--accent); }
.timer-progress-fill { background: linear-gradient(90deg, var(--accent-grad-a), var(--accent-grad-b)); }

/* ---- Respawn banner: lifted slate, calm green hairline ---- */
.respawn-banner {
  background: linear-gradient(90deg, var(--banner-bg-a), var(--banner-bg-b));
  border-bottom: 1px solid var(--glass-border);
}
.respawn-countdown-timer .respawn-timer-value,
.action-type { color: var(--accent); }
.respawn-timer-progress { background: var(--accent); }
.respawn-action-log { border-left-color: rgba(var(--accent-rgb), 0.18); }
.respawn-action-log::-webkit-scrollbar-thumb { background: rgba(var(--accent-rgb), 0.28); }

/* ---- Ralph panel: replace the blue->green ring gradient + Material badges ---- */
.ralph-ring-text {
  background: linear-gradient(135deg, var(--accent-grad-a), var(--accent-grad-b));
  -webkit-background-clip: text;
  background-clip: text;
}
.ralph-ring-bg, .ralph-ring-track { stroke: var(--control-border); }
/* Ralph status badges: collapse the off-token Material palette onto the system */
.ralph-status-badge { color: var(--text-dim); }
.ralph-status-dot { box-shadow: none; }
.ralph-info { background: rgba(var(--accent-rgb), 0.05); }

/* ---- Bottom toolbar + neutral buttons ---- */
.toolbar { box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.22), 0 -4px 14px rgba(0, 0, 0, 0.14); }
.btn-toolbar {
  background: var(--control-bg);
  border-color: var(--control-border);
  color: var(--text-dim);
}
.btn-toolbar:hover {
  background: var(--control-bg-hover);
  border-color: var(--control-border-hover);
  color: var(--text);
  box-shadow: none;
}

/* ---- RUN button: THE focal saturated accent (flat emerald->teal fill) ---- */
.btn-toolbar.btn-run,
.btn-toolbar.btn-run.mode-claude {
  background: linear-gradient(135deg, var(--accent-grad-a), var(--accent-grad-b));
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  text-shadow: none;
}
.btn-toolbar.btn-run:hover,
.btn-toolbar.btn-run.mode-claude:hover {
  background: linear-gradient(135deg, var(--run-hover-a), var(--run-hover-b));
  box-shadow: 0 0 14px -2px rgba(var(--accent-rgb), 0.5);
}
.btn-toolbar.btn-run.mode-opencode {
  background: linear-gradient(135deg, var(--accent-d), var(--accent-grad-b));
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn-toolbar.btn-run.mode-opencode:hover { box-shadow: 0 0 14px -2px rgba(var(--accent-rgb), 0.45); }
.btn-toolbar.btn-run.mode-codex {
  background: linear-gradient(135deg, var(--accent-grad-b), #5cc6e8);
  border-color: var(--accent-grad-b);
  color: #061c20;
}
.btn-toolbar.btn-run.mode-codex:hover { box-shadow: 0 0 14px -2px rgba(43, 203, 187, 0.45); }
.btn-toolbar.btn-run-gear {
  background: var(--accent-d);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn-toolbar.btn-run-gear:hover { background: var(--gear-hover); box-shadow: none; }
.run-mode-dot.claude { background: var(--accent); }
.run-mode-dot.opencode { background: var(--accent-soft); }
.run-mode-dot.codex { background: var(--accent-grad-b); }
.run-mode-dot.shell { background: var(--text-dim); }

/* ---- Shell button: quiet neutral with a calm green tint ---- */
.btn-toolbar.btn-shell {
  background: rgba(68, 185, 147, 0.1);
  border: 1px solid rgba(68, 185, 147, 0.28);
  color: var(--green);
  text-shadow: none;
}
.btn-toolbar.btn-shell:hover {
  background: rgba(68, 185, 147, 0.16);
  border-color: rgba(68, 185, 147, 0.4);
  box-shadow: none;
}

/* ---- Stop button: quiet neutral control (no rose glow) ---- */
.btn-toolbar.btn-stop {
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  color: var(--text-dim);
  text-shadow: none;
}
.btn-toolbar.btn-stop:hover {
  background: rgba(224, 99, 99, 0.14);
  border-color: rgba(224, 99, 99, 0.4);
  color: #f0a0a0;
  box-shadow: none;
}
.btn-toolbar.btn-stop.confirming {
  background: linear-gradient(135deg, #5a4a1a, #6b5620);
  border-color: rgba(240, 194, 90, 0.6);
  color: var(--yellow);
}

/* ---- Case selector + add ---- */
.toolbar-select {
  background: var(--control-bg);
  border-color: var(--control-border);
  color: var(--text-dim);
}
.toolbar-select:hover { background: var(--control-bg-hover); border-color: var(--control-border-hover); }
.toolbar-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.25);
}
.btn-case-add { color: var(--accent-soft); }

/* ---- Header system stats: cohesive accent meters ---- */
.stat-bar-mem { background: linear-gradient(90deg, var(--accent), var(--accent-hover)); }
.header-tokens.clickable:hover { background: rgba(var(--accent-rgb), 0.16); }

/* ---- Monitor + Subagents panels: lifted frosted slate ---- */
.monitor-panel,
.subagents-panel {
  background: var(--floating-bg);
  border: 1px solid var(--control-border);
}

/* ---- Subagent progress ring: emerald, calm glow ---- */
.subagent-ring-progress,
.subagent-ring circle.progress { stroke: var(--accent); }

/* ---- PROGRESS RING (Ralph large): the one place a soft glow lives ---- */
.ralph-ring-fill { filter: drop-shadow(0 0 6px rgba(var(--accent-rgb), 0.45)); }

/* ---- Welcome overlay: emerald title + Daylight buttons ---- */
.welcome-title {
  background: linear-gradient(135deg, var(--accent-grad-a) 0%, var(--accent-grad-b) 50%, var(--accent-grad-a) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.welcome-btn-claude {
  background: linear-gradient(135deg, var(--accent-grad-a), var(--accent-grad-b));
  border-color: var(--accent);
  color: var(--accent-ink);
}
.welcome-btn-claude:hover { box-shadow: 0 0 28px -4px rgba(var(--accent-rgb), 0.3); }
.welcome-btn-opencode {
  background: linear-gradient(135deg, var(--accent-d), var(--accent-grad-b));
  border-color: rgba(var(--accent-rgb), 0.4);
  color: var(--accent-ink);
}
.welcome-btn-opencode:hover { box-shadow: 0 0 28px -4px rgba(var(--accent-rgb), 0.25); }
.welcome-btn-tunnel {
  background: linear-gradient(135deg, var(--bg-input), var(--bg-hover));
  border-color: var(--border-light);
  color: var(--text);
}
.welcome-btn-tunnel:hover { box-shadow: none; }
.welcome-btn-tunnel.active {
  background: linear-gradient(135deg, var(--accent-d), var(--accent-grad-a));
  border-color: var(--accent);
  color: var(--accent-ink);
}

/* ---- Focus rings (driven by --accent, now emerald) stay accessible ---- */
:focus-visible { outline-color: var(--accent); }
}

/* ---- Daylight Blue: distinct identity per welcome action button ----
   Run Claude Code keeps the blue accent; Cloudflare Tunnel is purple; Run
   OpenCode is emerald green — so the three are clearly different colors instead
   of all reading blue. Scoped to daylight-blue only; placed after the shared
   daylight block to win on equal specificity. ---- */
html[data-skin="daylight-blue"] .welcome-btn-opencode {
  background: linear-gradient(135deg, #0d9f6e, #2fbf85);
  border-color: rgba(16, 185, 129, 0.5);
  color: #04291b;
}
html[data-skin="daylight-blue"] .welcome-btn-opencode:hover {
  background: linear-gradient(135deg, #10b981, #34d399);
  border-color: rgba(52, 211, 153, 0.6);
  box-shadow: 0 0 28px -4px rgba(16, 185, 129, 0.4);
}
html[data-skin="daylight-blue"] .welcome-btn-tunnel {
  background: linear-gradient(135deg, #7c3aed, #a855f7);
  border-color: rgba(168, 85, 247, 0.5);
  color: #f5f3ff;
}
html[data-skin="daylight-blue"] .welcome-btn-tunnel:hover {
  background: linear-gradient(135deg, #8b5cf6, #c084fc);
  border-color: rgba(192, 132, 252, 0.6);
  box-shadow: 0 0 28px -4px rgba(124, 58, 237, 0.45);
}
html[data-skin="daylight-blue"] .welcome-btn-tunnel.active {
  background: linear-gradient(135deg, #6d28d9, #7c3aed);
  border-color: rgba(124, 58, 237, 0.6);
  color: #f5f3ff;
}
html[data-skin="daylight-blue"] .welcome-btn-tunnel.active:hover {
  background: linear-gradient(135deg, #7c3aed, #8b5cf6);
  box-shadow: 0 0 28px -4px rgba(124, 58, 237, 0.5);
}

/* ── Cron Jobs ───────────────────────────────── */
/* There is no global `.hidden{display:none}` utility in this stylesheet — each
   component scopes its own. The cron modal shipped without one, so its
   `.hidden`-toggled create form + conditional schedule/prompt rows never
   actually collapsed (all fields showed at once). Scope one here. */
#cronModal .hidden { display: none !important; }
.cron-modal-hint { margin-bottom: 1rem; }
.cron-toolbar {
  display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap;
  margin-bottom: 1.1rem; padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--border);
}

/* Job list — cards that echo the App Settings item look */
.cron-job-list { display: flex; flex-direction: column; gap: 0.5rem; }
.cron-job-row {
  display: flex; justify-content: space-between; align-items: center; gap: 0.9rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: var(--btn-radius);
  background: rgba(255, 255, 255, 0.03);
  transition: background var(--transition-smooth), border-color var(--transition-smooth);
}
.cron-job-row:hover { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.1); }
.cron-job-main { min-width: 0; flex: 1; }
.cron-job-name { font-weight: 600; font-size: 0.85rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.cron-job-meta { font-size: 0.68rem; color: var(--text-muted); margin-top: 0.35rem; overflow: hidden; text-overflow: ellipsis; }
.cron-job-actions { display: flex; gap: 0.35rem; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.cron-badge {
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase;
  padding: 0.1rem 0.45rem; border-radius: 999px;
  background: var(--accent-bg, rgba(120, 160, 255, 0.15)); color: var(--text-dim);
}
.cron-badge-off { background: rgba(200, 80, 80, 0.18); color: #e88; }

/* Create / edit form — sectioned + spaced to match the App Settings modal */
.cron-job-form {
  margin-top: 1rem; padding-top: 0.85rem; border-top: 1px solid var(--border);
}
.cron-form-title {
  font-size: 0.95rem; font-weight: 600; color: var(--text); margin-bottom: 0.35rem;
}
#cronModal .form-row { margin-bottom: 0.85rem; }
/* datetime-local / time inputs aren't covered by the base .form-row input rule */
#cronModal .form-row input[type="datetime-local"],
#cronModal .form-row input[type="time"] {
  width: 100%; padding: 0.5rem 0.75rem;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--btn-radius);
  color: var(--text); font-size: 0.8rem; font-family: inherit;
  transition: border-color var(--transition-smooth), box-shadow var(--transition-smooth);
}
#cronModal .form-row input[type="datetime-local"]:focus,
#cronModal .form-row input[type="time"]:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
}

/* Toggle rows rendered as settings cards (label + description left, switch right) */
#cronModal .form-row-switch.cron-switch-row {
  justify-content: space-between; gap: 0.75rem; flex-wrap: nowrap;
  padding: 0.55rem 0.7rem; margin-bottom: 0.5rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: var(--btn-radius);
}
.cron-switch-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.cron-switch-label { font-size: 0.75rem; color: var(--text); text-transform: none; letter-spacing: 0; margin: 0; }
.cron-switch-desc { font-size: 0.62rem; color: var(--text-muted); line-height: 1.35; }

/* Weekday selector — pill toggles instead of raw checkboxes */
.cron-weekdays { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.cron-weekdays label {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.6rem; margin: 0; padding: 0.3rem 0.55rem;
  font-size: 0.7rem; font-weight: 500; text-transform: none; letter-spacing: 0;
  color: var(--text-dim); cursor: pointer;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  transition: background var(--transition-smooth), border-color var(--transition-smooth), color var(--transition-smooth);
}
.cron-weekdays label:hover { border-color: var(--accent); color: var(--text); }
.cron-weekdays label input { position: absolute; opacity: 0; width: 0; height: 0; }
.cron-weekdays label:has(input:checked) { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Footer */
.cron-form-error { color: var(--danger, #e55); margin-top: 0.4rem; }
.cron-form-error:empty { display: none; }
.cron-form-actions {
  display: flex; gap: 0.5rem; justify-content: flex-end;
  margin-top: 1rem; padding-top: 0.85rem; border-top: 1px solid var(--border);
}

/* ═══════════════════════════════════════════════════════════════
   Web tabs (dashboard URLs embedded as tabs)
   ═══════════════════════════════════════════════════════════════ */

/* The iframe layer sits alongside .terminal-wrap inside 
and only one of the two is visible at a time. Frames stay in the DOM while hidden so switching tabs does not reload a dashboard. */ .webview-layer { display: none; flex: 1; min-height: 0; position: relative; background: var(--term-bg, #161b23); } .main.webview-active .webview-layer { display: flex; } .main.webview-active .terminal-wrap { display: none; } .webview-frame { display: none; position: absolute; inset: 0; } .webview-frame.active { display: block; } .webview-iframe { width: 100%; height: 100%; border: 0; display: block; background: #fff; } /* Shown only when the frame never signalled load: a refused embed or an unreachable host would otherwise be an unexplained blank rectangle. */ .webview-failure { display: none; } .webview-frame--failed .webview-failure { display: flex; position: absolute; inset: 0; align-items: center; justify-content: center; background: var(--bg, #0f1319); padding: 1.5rem; text-align: center; } .webview-failure-inner { max-width: 380px; } .webview-failure-inner h3 { margin: 0 0 0.5rem; font-size: 1rem; color: var(--text); } .webview-failure-inner p { margin: 0 0 1rem; font-size: 0.85rem; color: var(--text-dim); line-height: 1.5; } .webview-failure-actions { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; } /* Tab styling: same shape as a session tab, distinguished by the globe icon and a cool accent so a dashboard never reads as a running agent. */ .session-tab--web .tab-web-icon { display: inline-flex; align-items: center; color: var(--text-dim); flex-shrink: 0; } .session-tab--web.active .tab-web-icon { color: var(--accent, #3ec8ee); } .session-tab--web.active { border-bottom-color: var(--accent, #3ec8ee); } .run-mode-dot.web { background: #38bdf8; } .run-mode-webviews { max-height: 180px; overflow-y: auto; } /* A saved URL is a ROW: open on the left, edit + delete on the right, so a URL can be changed or removed without first opening it as a tab. The side buttons stay permanently visible rather than hover-revealed, because this menu is used on touch devices where there is no hover to reveal them with. */ .run-mode-row--web { display: flex; align-items: center; gap: 2px; } .run-mode-row--web .run-mode-option--web { flex: 1 1 auto; min-width: 0; overflow: hidden; } /* The label needs its own element: `text-overflow` on the button does nothing, because the button is a flex container and a bare text node in one becomes an anonymous flex item that ellipsis cannot reach. Without this a long dashboard name widens the whole menu instead of truncating. */ .run-mode-web-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .run-mode-row-btn { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; background: none; border: none; border-radius: var(--btn-radius); color: var(--text-dim); font-size: 0.9rem; line-height: 1; cursor: pointer; } .run-mode-row-btn:hover { background: rgba(255, 255, 255, 0.07); color: var(--text); } .run-mode-webview-delete { font-size: 1.05rem; } .run-mode-webview-delete:hover { color: var(--danger, #ef4444); } .run-mode-empty { padding: 4px 10px 6px; font-size: 0.75em; color: var(--text-dim); font-style: italic; } /* Icon picker: a compact grid above the free-text field, so the common case is a click and the escape hatch (any emoji at all) stays available. */ .webview-icon-picker { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; } .webview-icon-choice { width: 34px; height: 34px; font-size: 1.05rem; line-height: 1; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-soft, rgba(255, 255, 255, 0.03)); cursor: pointer; padding: 0; } .webview-icon-choice:hover { border-color: var(--accent, #3ec8ee); } .webview-icon-choice.selected { border-color: var(--accent, #3ec8ee); box-shadow: 0 0 0 1px var(--accent, #3ec8ee) inset; } /* Saved-URL rows in the Run dropdown show their chosen icon in the dot's slot. */ .run-mode-menu-icon { display: inline-flex; align-items: center; justify-content: center; width: 14px; margin-right: 6px; font-size: 0.95em; flex-shrink: 0; } .webview-probe-result.ok { color: var(--success, #10b981); } .webview-probe-result.bad { color: var(--danger, #ef4444); } /* Delete sits apart from Cancel/Save so it is not fat-fingered on the way to Save. */ .webview-modal-actions { justify-content: space-between; } .webview-modal-actions .btn-danger { margin-right: auto; }